/src/solidity/libsolidity/formal/SymbolicState.h
Line | Count | Source |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <libsolidity/formal/SymbolicTypes.h> |
22 | | #include <libsolidity/formal/SymbolicVariables.h> |
23 | | |
24 | | #include <libsmtutil/Sorts.h> |
25 | | #include <libsmtutil/SolverInterface.h> |
26 | | |
27 | | namespace solidity::frontend::smt |
28 | | { |
29 | | |
30 | | class EncodingContext; |
31 | | class SymbolicAddressVariable; |
32 | | class SymbolicArrayVariable; |
33 | | |
34 | | class BlockchainVariable |
35 | | { |
36 | | public: |
37 | | BlockchainVariable(std::string _name, std::map<std::string, smtutil::SortPointer> _members, EncodingContext& _context); |
38 | | /// @returns the variable data as a tuple. |
39 | 773k | smtutil::Expression value() const { return m_tuple->currentValue(); } |
40 | 2.19M | smtutil::Expression value(unsigned _idx) const { return m_tuple->valueAtIndex(_idx); } |
41 | 1.34M | smtutil::SortPointer const& sort() const { return m_tuple->sort(); } |
42 | 332 | unsigned index() const { return m_tuple->index(); } |
43 | 252k | void newVar() { m_tuple->increaseIndex(); } |
44 | 1.23M | void reset() { m_tuple->resetIndex(); } |
45 | | |
46 | | /// @returns the symbolic _member. |
47 | | smtutil::Expression member(std::string const& _member) const; |
48 | | /// Generates a new tuple where _member is assigned _value. |
49 | | smtutil::Expression assignMember(std::string const& _member, smtutil::Expression const& _value); |
50 | | |
51 | | private: |
52 | | std::string const m_name; |
53 | | std::map<std::string, smtutil::SortPointer> const m_members; |
54 | | EncodingContext& m_context; |
55 | | std::map<std::string, unsigned> m_componentIndices; |
56 | | std::unique_ptr<SymbolicTupleVariable> m_tuple; |
57 | | }; |
58 | | |
59 | | /** |
60 | | * Symbolic representation of the blockchain context: |
61 | | * - error flag |
62 | | * - this (the address of the currently executing contract) |
63 | | * - state, represented as a tuple of: |
64 | | * - balances |
65 | | * - array of address => bool representing whether an address is used by a contract |
66 | | * - storage of contracts |
67 | | * - block and transaction properties, represented as a tuple of: |
68 | | * - blobhash |
69 | | * - blockhash |
70 | | * - block basefee |
71 | | * - block blobbasefee |
72 | | * - block chainid |
73 | | * - block coinbase |
74 | | * - block gaslimit |
75 | | * - block number |
76 | | * - block prevrandao |
77 | | * - block slotnum |
78 | | * - block timestamp |
79 | | * - TODO gasleft |
80 | | * - msg data |
81 | | * - msg sender |
82 | | * - msg sig |
83 | | * - msg value |
84 | | * - tx gasprice |
85 | | * - tx origin |
86 | | */ |
87 | | class SymbolicState |
88 | | { |
89 | | public: |
90 | 15.6k | SymbolicState(EncodingContext& _context): m_context(_context) {} |
91 | | |
92 | | void reset(); |
93 | | |
94 | | /// Error flag. |
95 | | //@{ |
96 | 364k | SymbolicIntVariable& errorFlag() { return m_error; } |
97 | 524k | SymbolicIntVariable const& errorFlag() const { return m_error; } |
98 | 247k | smtutil::SortPointer const& errorFlagSort() const { return m_error.sort(); } |
99 | | //@} |
100 | | |
101 | | /// This. |
102 | | //@{ |
103 | | /// @returns the symbolic value of the currently executing contract's address. |
104 | 109k | smtutil::Expression thisAddress() const { return m_thisAddress.currentValue(); } |
105 | 536k | smtutil::Expression thisAddress(unsigned _idx) const { return m_thisAddress.valueAtIndex(_idx); } |
106 | 0 | smtutil::Expression newThisAddress() { return m_thisAddress.increaseIndex(); } |
107 | 265k | smtutil::SortPointer const& thisAddressSort() const { return m_thisAddress.sort(); } |
108 | | //@} |
109 | | |
110 | | /// Blockchain state. |
111 | | //@{ |
112 | 631k | smtutil::Expression state() const { solAssert(m_state, ""); return m_state->value(); } |
113 | 644k | smtutil::Expression state(unsigned _idx) const { solAssert(m_state, ""); return m_state->value(_idx); } |
114 | 578k | smtutil::SortPointer const& stateSort() const { solAssert(m_state, ""); return m_state->sort(); } |
115 | 251k | void newState() { solAssert(m_state, ""); m_state->newVar(); } |
116 | | |
117 | | void newBalances(); |
118 | | |
119 | | /// Balance. |
120 | | /// @returns the symbolic balances. |
121 | | smtutil::Expression balances() const; |
122 | | /// @returns the symbolic balance of address `this`. |
123 | | smtutil::Expression balance() const; |
124 | | /// @returns the symbolic balance of an address. |
125 | | smtutil::Expression balance(smtutil::Expression _address) const; |
126 | | /// Transfer _value from _from to _to. |
127 | | void transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value); |
128 | | |
129 | | /// Adds _value to _account's balance. |
130 | | void addBalance(smtutil::Expression _account, smtutil::Expression _value); |
131 | | |
132 | | /// Storage. |
133 | | smtutil::Expression storage(ContractDefinition const& _contract) const; |
134 | | smtutil::Expression storage(ContractDefinition const& _contract, smtutil::Expression _address) const; |
135 | | smtutil::Expression addressActive(smtutil::Expression _address) const; |
136 | | void setAddressActive(smtutil::Expression _address, bool _active); |
137 | | |
138 | | void newStorage(); |
139 | | void writeStateVars(ContractDefinition const& _contract, smtutil::Expression _address); |
140 | | void readStateVars(ContractDefinition const& _contract, smtutil::Expression _address); |
141 | | //@} |
142 | | |
143 | | /// Transaction data. |
144 | | //@{ |
145 | | /// @returns the tx data as a tuple. |
146 | 16.9k | smtutil::Expression tx() const { return m_tx.value(); } |
147 | 478k | smtutil::Expression tx(unsigned _idx) const { return m_tx.value(_idx); } |
148 | 229k | smtutil::SortPointer const& txSort() const { return m_tx.sort(); } |
149 | 856 | void newTx() { m_tx.newVar(); } |
150 | | smtutil::Expression txMember(std::string const& _member) const; |
151 | | smtutil::Expression txFunctionConstraints(FunctionDefinition const& _function) const; |
152 | | smtutil::Expression txTypeConstraints() const; |
153 | | smtutil::Expression txNonPayableConstraint() const; |
154 | | smtutil::Expression blobhash(smtutil::Expression _blobIndex) const; |
155 | | smtutil::Expression blockhash(smtutil::Expression _blockNumber) const; |
156 | | smtutil::Expression evmParisConstraints() const; |
157 | | //@} |
158 | | |
159 | | /// Crypto functions. |
160 | | //@{ |
161 | | /// @returns the crypto functions represented as a tuple of arrays. |
162 | 62.3k | smtutil::Expression crypto() const { return m_crypto.value(); } |
163 | 536k | smtutil::Expression crypto(unsigned _idx) const { return m_crypto.value(_idx); } |
164 | 265k | smtutil::SortPointer const& cryptoSort() const { return m_crypto.sort(); } |
165 | 0 | void newCrypto() { m_crypto.newVar(); } |
166 | 525 | smtutil::Expression cryptoFunction(std::string const& _member) const { return m_crypto.member(_member); } |
167 | | //@} |
168 | | |
169 | | /// Calls the internal methods that build |
170 | | /// - the symbolic ABI functions based on the abi.* calls |
171 | | /// in _source and referenced sources. |
172 | | /// - the symbolic storages for all contracts in _source and |
173 | | /// referenced sources. |
174 | | void prepareForSourceUnit(SourceUnit const& _source, bool _storage); |
175 | | |
176 | | /// ABI functions. |
177 | | //@{ |
178 | | smtutil::Expression abiFunction(FunctionCall const* _funCall); |
179 | | using SymbolicABIFunction = std::tuple< |
180 | | std::string, |
181 | | std::vector<frontend::Type const*>, |
182 | | std::vector<frontend::Type const*> |
183 | | >; |
184 | | SymbolicABIFunction const& abiFunctionTypes(FunctionCall const* _funCall) const; |
185 | | |
186 | 62.3k | smtutil::Expression abi() const { solAssert(m_abi, ""); return m_abi->value(); } |
187 | 536k | smtutil::Expression abi(unsigned _idx) const { solAssert(m_abi, ""); return m_abi->value(_idx); } |
188 | 265k | smtutil::SortPointer const& abiSort() const { solAssert(m_abi, ""); return m_abi->sort(); } |
189 | | //@} |
190 | | |
191 | | /// bytes.concat functions. |
192 | | //@{ |
193 | | smtutil::Expression bytesConcatFunction(FunctionCall const* _funCall); |
194 | | using SymbolicBytesConcatFunction = std::tuple< |
195 | | std::string, |
196 | | std::vector<frontend::Type const*>, |
197 | | frontend::Type const* |
198 | | >; |
199 | | SymbolicBytesConcatFunction const& bytesConcatFunctionTypes(FunctionCall const* _funCall) const; |
200 | 277 | smtutil::Expression bytesConcat() const { solAssert(m_bytesConcat, ""); return m_bytesConcat->value(); } |
201 | 2.25k | smtutil::Expression bytesConcat(unsigned _idx) const { solAssert(m_bytesConcat, ""); return m_bytesConcat->value(_idx); } |
202 | 1.08k | smtutil::SortPointer const& bytesConcatSort() const { solAssert(m_bytesConcat, ""); return m_bytesConcat->sort(); } |
203 | 1.15M | bool hasBytesConcatFunction() const {solAssert(m_bytesConcat, ""); return !m_bytesConcatMembers.empty(); } |
204 | | //@} |
205 | | |
206 | | private: |
207 | | std::string contractSuffix(ContractDefinition const& _contract) const; |
208 | | std::string contractStorageKey(ContractDefinition const& _contract) const; |
209 | | std::string stateVarStorageKey(VariableDeclaration const& _var, ContractDefinition const& _contract) const; |
210 | | |
211 | | /// Builds state.storage based on _contracts. |
212 | | void buildState(std::set<ContractDefinition const*, ASTCompareByID<ContractDefinition>> const& _contracts, bool _allStorages); |
213 | | |
214 | | /// Builds m_abi based on the abi.* calls _abiFunctions. |
215 | | void buildABIFunctions(std::set<FunctionCall const*, ASTCompareByID<FunctionCall>> const& _abiFunctions); |
216 | | |
217 | | /// Builds m_bytesConcat based on the bytes.concat calls |
218 | | void buildBytesConcatFunctions(std::set<FunctionCall const*, ASTCompareByID<FunctionCall>> const& _bytesConcatCalls); |
219 | | |
220 | | EncodingContext& m_context; |
221 | | |
222 | | SymbolicIntVariable m_error{ |
223 | | TypeProvider::uint256(), |
224 | | TypeProvider::uint256(), |
225 | | "error", |
226 | | m_context |
227 | | }; |
228 | | |
229 | | SymbolicAddressVariable m_thisAddress{ |
230 | | "this", |
231 | | m_context |
232 | | }; |
233 | | |
234 | | /// m_state is a tuple of |
235 | | /// - balances: array of address to balance of address. |
236 | | /// - isActive: array of address to Boolean, where element is true iff address is used. |
237 | | /// - storage: tuple containing the storage of every contract, where |
238 | | /// each element of the tuple represents a contract, |
239 | | /// and is defined by an array where the index is the contract's address |
240 | | /// and the element is a tuple containing the state variables of that contract. |
241 | | std::unique_ptr<BlockchainVariable> m_state; |
242 | | |
243 | | BlockchainVariable m_tx{"tx", transactionMemberSorts(), m_context}; |
244 | | |
245 | | BlockchainVariable m_crypto{ |
246 | | "crypto", |
247 | | { |
248 | | {"keccak256", std::make_shared<smtutil::ArraySort>( |
249 | | smt::smtSort(*TypeProvider::bytesStorage()), |
250 | | smtSort(*TypeProvider::fixedBytes(32)) |
251 | | )}, |
252 | | {"sha256", std::make_shared<smtutil::ArraySort>( |
253 | | smt::smtSort(*TypeProvider::bytesStorage()), |
254 | | smtSort(*TypeProvider::fixedBytes(32)) |
255 | | )}, |
256 | | {"ripemd160", std::make_shared<smtutil::ArraySort>( |
257 | | smt::smtSort(*TypeProvider::bytesStorage()), |
258 | | smtSort(*TypeProvider::fixedBytes(20)) |
259 | | )}, |
260 | | {"ecrecover", std::make_shared<smtutil::ArraySort>( |
261 | | std::make_shared<smtutil::TupleSort>( |
262 | | "ecrecover_input_type", |
263 | | std::vector<std::string>{"hash", "v", "r", "s"}, |
264 | | std::vector<smtutil::SortPointer>{ |
265 | | smt::smtSort(*TypeProvider::fixedBytes(32)), |
266 | | smt::smtSort(*TypeProvider::uint(8)), |
267 | | smt::smtSort(*TypeProvider::fixedBytes(32)), |
268 | | smt::smtSort(*TypeProvider::fixedBytes(32)) |
269 | | } |
270 | | ), |
271 | | smtSort(*TypeProvider::address()) |
272 | | )} |
273 | | }, |
274 | | m_context |
275 | | }; |
276 | | |
277 | | /// Tuple containing all used ABI functions. |
278 | | std::unique_ptr<BlockchainVariable> m_abi; |
279 | | /// Maps ABI functions calls to their tuple names generated by |
280 | | /// `buildABIFunctions`. |
281 | | std::map<FunctionCall const*, SymbolicABIFunction> m_abiMembers; |
282 | | |
283 | | /// Tuple containing all used bytes.concat functions. |
284 | | std::unique_ptr<BlockchainVariable> m_bytesConcat; |
285 | | /// Maps bytes.concat functions calls to their tuple names generated by |
286 | | /// `buildBytesConcatFunctions`. |
287 | | std::map<FunctionCall const*, SymbolicBytesConcatFunction> m_bytesConcatMembers; |
288 | | }; |
289 | | |
290 | | } |