Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Side-effect-free Yul interpreter #15464

Open
wants to merge 101 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
fa5c029
Copy interpreter tool from test as basis
quangloc99 Sep 18, 2024
5b63c18
Add new Result type
quangloc99 Sep 18, 2024
4f30344
Change interface of the interpreter to have custom return type
quangloc99 Sep 18, 2024
d78dc8d
Implement visit function with new return type
quangloc99 Sep 18, 2024
5e3c790
Remove runExternalCall
quangloc99 Sep 18, 2024
a1a9721
Minor comment edit
quangloc99 Sep 24, 2024
92d8894
Implement visit(Expression) for ExpressionEvaluator
quangloc99 Sep 24, 2024
f4078ad
Force incrementStep logic to be done at visit function
quangloc99 Sep 24, 2024
ba8d515
Merge ExpressionEvaluator into Interpreter
quangloc99 Sep 24, 2024
cdbb05c
Reorder methods
quangloc99 Sep 24, 2024
02877d1
Reset expressionNestingLevel after each incrementStatementStep
quangloc99 Sep 24, 2024
352fb64
Remove redundant makeInterpreterNew function
quangloc99 Sep 24, 2024
05b6540
Remove unused disableMemoryTrace
quangloc99 Sep 24, 2024
e94f923
Remove state with side effect from InterpreterState
quangloc99 Sep 24, 2024
bfd8e8e
Move Interpreter Config to a separate struct
quangloc99 Sep 24, 2024
89f005a
Remove redundant numInstance
quangloc99 Sep 24, 2024
f1e68e5
Add recursion depth check
quangloc99 Sep 24, 2024
4ff53cb
Remove functions with side-effect from EVMInstructionInterpreter
quangloc99 Sep 24, 2024
2563fb3
Declare ImpureBuiltinEncountered and EVMInstructionInterpretedResult
quangloc99 Sep 24, 2024
f48f2ef
Return ImpureBuiltinEncountered for all builtin with side-effect
quangloc99 Sep 24, 2024
e996ec4
Use EVMInstructionInterpretedResult in Interpreter
quangloc99 Sep 24, 2024
749e850
Bring back empty body and post check when visiting ForLoop
quangloc99 Sep 24, 2024
d3d86ba
Remove unused function in EVMInstructionInterpreter
quangloc99 Sep 24, 2024
63a6d6d
Move result types into a separate file
quangloc99 Sep 24, 2024
2d89cc3
Add Pure* prefix
quangloc99 Sep 28, 2024
d1a2c37
Move PureInterpreterState into a separate file
quangloc99 Sep 28, 2024
0b4c039
Add Results and PureInterpreterState into CMakeLists
quangloc99 Sep 28, 2024
3b791fc
Separate function definition and variable declaration in Scope
quangloc99 Sep 28, 2024
8ad17ce
Make Scope parent constant pointer
quangloc99 Sep 28, 2024
429d5a5
Move Scope to a separate file
quangloc99 Sep 28, 2024
4511ccc
Make Scope class. Add utilities to Scope.
quangloc99 Sep 28, 2024
6d1dd0d
Use new Scope class in PureInterpreter
quangloc99 Sep 28, 2024
626b794
Create VariableValuesMap alias
quangloc99 Sep 28, 2024
f2b3b69
Fix behavior of POP instruction
quangloc99 Sep 28, 2024
15abbcc
Add stack trace to state
quangloc99 Sep 28, 2024
17bf46b
Remove TraceLimitReached from ExecutionTerminated
quangloc99 Sep 28, 2024
e219ef3
Add dumpTraces function
quangloc99 Sep 28, 2024
6cde83c
Add execute statements function
quangloc99 Sep 28, 2024
840ce76
Add UnlimitedLiteralEncountered result type
quangloc99 Sep 28, 2024
e1834b9
Change calculation flow for evaluateArgs
quangloc99 Sep 28, 2024
07e619b
Add move constructor for EvaluationOk
quangloc99 Sep 28, 2024
ec48256
Disable EvaluationOk lvalue constructor
quangloc99 Sep 28, 2024
de3fb60
Make EvaluationOk constructor explicit
quangloc99 Sep 28, 2024
62f005f
Optimize std::vector<u256> usage
quangloc99 Sep 28, 2024
f597107
Copy YulInterpreterTest suite to YulPureInterpreterTest
quangloc99 Sep 28, 2024
06f972a
Read interpreter config from test settings
quangloc99 Sep 28, 2024
0e85389
Make PureInterpreter.run returns ExecutionResult
quangloc99 Sep 28, 2024
b2526f0
Add default value for traces
quangloc99 Sep 28, 2024
0d4397d
Use new PureInterpreter in test
quangloc99 Sep 28, 2024
62c1896
Make TraceLimitReached a ExecutionTerminated result again
quangloc99 Sep 28, 2024
a50e6b3
Remove PureInterpreter.run method
quangloc99 Sep 29, 2024
563cca2
Add function to get allVariables from interpreter
quangloc99 Sep 29, 2024
6c4c975
Dump more data after interpreter
quangloc99 Sep 29, 2024
cc68c2b
Register YulPureInterpreterTest
quangloc99 Sep 29, 2024
7768be9
Add hex printing and sort variable names
quangloc99 Sep 29, 2024
ba93892
Filter and add existing interpreter tests to pure interpreterTest
quangloc99 Sep 29, 2024
3a08b5e
Add tests for all impure instructions
quangloc99 Sep 29, 2024
96db373
Add test for all pure instructions
quangloc99 Sep 29, 2024
1ac087f
Change expr_nesting_depth_not_exceeded to run expression multiple time
quangloc99 Sep 29, 2024
41a382b
Add test for StepLimitReached
quangloc99 Sep 29, 2024
965697e
Add test for impure non instructions
quangloc99 Sep 29, 2024
3ac9195
Add check for verbatim
quangloc99 Sep 29, 2024
50acc29
Add verbatim test
quangloc99 Sep 29, 2024
2dd4543
Remove redundant public:
quangloc99 Sep 29, 2024
62a0a96
Optimize map usage
quangloc99 Sep 29, 2024
7cda001
Remove redundant terminated check
quangloc99 Sep 29, 2024
1e46f78
Remove redundant terminated result
quangloc99 Sep 29, 2024
bfba77c
Add test for stop instruction
quangloc99 Sep 29, 2024
7d6255e
Update tests to remove trailing space
quangloc99 Sep 29, 2024
a8f4d16
Fix styling for addTrace
quangloc99 Sep 29, 2024
38e4cc6
Fix spelling
quangloc99 Sep 29, 2024
326bdfe
Fix linting error for generate-test.py
quangloc99 Sep 29, 2024
6d7a4ba
Update EVMVersion in tests
quangloc99 Sep 29, 2024
0d52233
Add encoding when open file when generate test
quangloc99 Sep 29, 2024
ea1c297
Fix spelling Expection -> Expectation
quangloc99 Sep 29, 2024
4fc66ca
Remove virtual modifier from PureInterpreter functions
quangloc99 Sep 29, 2024
3483faa
Remove unused m_state
quangloc99 Sep 29, 2024
82a8d36
Drop tools/ subdirectory
quangloc99 Oct 8, 2024
c3f7dd8
Move u512 to libsolutil/Numeric.h
quangloc99 Oct 8, 2024
3fc0d14
Remove comment about instruction being _impure_
quangloc99 Oct 8, 2024
808ff96
Use util::unreachable in PureEVMInstructionInterpreter::eval
quangloc99 Oct 8, 2024
a42757c
Fix styling: return on separate line
quangloc99 Oct 8, 2024
d61e952
Fix styling: spacing surround constructor call
quangloc99 Oct 8, 2024
2b1d4b1
Fix styling: format python code
quangloc99 Oct 8, 2024
0ffe4fe
Fix styling: yul test indentation
quangloc99 Oct 8, 2024
1e57604
Remove empty string message in assert
quangloc99 Oct 8, 2024
99cc80b
Make variable name explicit
quangloc99 Oct 8, 2024
fba9c0a
Move pure_instructions test generator into test comment
quangloc99 Oct 14, 2024
9b8ab44
Add DATALOADN to PureEVMInstructionInterpreter
quangloc99 Oct 24, 2024
15cbd51
Adapt to new EOF changes
quangloc99 Oct 24, 2024
b068bc4
Use boost::outcome
quangloc99 Oct 24, 2024
7980df8
Change makeInterpreterCopy to allocate on stack
quangloc99 Oct 24, 2024
bd01649
Replace hardcoded builtin with ImpureBuiltinEncountered error
quangloc99 Oct 24, 2024
014f66e
Make PureEVMInstructionInterpreter just a function
quangloc99 Oct 24, 2024
282718e
Return UnlimitedLiteralEncountered early
quangloc99 Oct 24, 2024
6b7fd78
Default initialization for fields
quangloc99 Oct 24, 2024
a5eeede
Move function initialization part of scope to scope's constructor
quangloc99 Oct 24, 2024
407daf4
Rename getSubscope -> createSubscope
quangloc99 Oct 24, 2024
1ac52aa
Initialize test subscope with block in test suite
quangloc99 Oct 24, 2024
101cb6b
Remove operator== of Terminated outcome
quangloc99 Oct 24, 2024
559124e
Remove unused imports
quangloc99 Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions libyul/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ add_library(yul
optimiser/VarDeclInitializer.h
optimiser/VarNameCleaner.cpp
optimiser/VarNameCleaner.h
interpreter/Results.h
interpreter/PureInterpreterState.h
interpreter/PureInterpreterState.cpp
interpreter/Scope.h
interpreter/Scope.cpp
interpreter/types.h
interpreter/PureInterpreter.cpp
interpreter/PureInterpreter.h
interpreter/PureEVMInstructionInterpreter.cpp
interpreter/PureEVMInstructionInterpreter.h
)

target_link_libraries(yul PUBLIC evmasm solutil langutil smtutil fmt::fmt-header-only)
272 changes: 272 additions & 0 deletions libyul/interpreter/PureEVMInstructionInterpreter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/*
This file is part of solidity.

solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Yul interpreter module that evaluates EVM instructions.
*/

#include <libyul/interpreter/PureEVMInstructionInterpreter.h>

#include <libyul/backends/evm/EVMDialect.h>

#include <libsolutil/FixedHash.h>

using namespace solidity;
using namespace solidity::evmasm;
using namespace solidity::yul;
using namespace solidity::yul::interpreter;

namespace solidity::yul::interpreter::PureEVMInstructionInterpreter {

using solidity::util::h160;
using solidity::util::h256;

EvaluationResult eval(
langutil::EVMVersion _evmVersion,
BuiltinFunctionForEVM const& _builtinFunction,
std::vector<u256> const& _arguments
)
{
if (!_builtinFunction.instruction)
return ImpureBuiltinEncountered();
evmasm::Instruction instruction = *_builtinFunction.instruction;

auto info = instructionInfo(instruction, _evmVersion);
yulAssert(static_cast<size_t>(info.args) == _arguments.size());

auto const& arg = _arguments;
switch (instruction)
{
case Instruction::STOP:
return ExplicitlyTerminated();
// --------------- arithmetic ---------------
case Instruction::ADD:
return EvaluationOk(arg[0] + arg[1]);
case Instruction::MUL:
return EvaluationOk(arg[0] * arg[1]);
case Instruction::SUB:
return EvaluationOk(arg[0] - arg[1]);
case Instruction::DIV:
return EvaluationOk(arg[1] == 0 ? 0 : arg[0] / arg[1]);
case Instruction::SDIV:
return EvaluationOk(arg[1] == 0 ? 0 : s2u(u2s(arg[0]) / u2s(arg[1])));
case Instruction::MOD:
return EvaluationOk(arg[1] == 0 ? 0 : arg[0] % arg[1]);
case Instruction::SMOD:
return EvaluationOk(arg[1] == 0 ? 0 : s2u(u2s(arg[0]) % u2s(arg[1])));
case Instruction::EXP:
return EvaluationOk(exp256(arg[0], arg[1]));
case Instruction::NOT:
return EvaluationOk(~arg[0]);
case Instruction::LT:
return EvaluationOk(arg[0] < arg[1] ? u256(1) : u256(0));
case Instruction::GT:
return EvaluationOk(arg[0] > arg[1] ? u256(1) : u256(0));
case Instruction::SLT:
return EvaluationOk(u2s(arg[0]) < u2s(arg[1]) ? u256(1) : u256(0));
case Instruction::SGT:
return EvaluationOk(u2s(arg[0]) > u2s(arg[1]) ? u256(1) : u256(0));
case Instruction::EQ:
return EvaluationOk(arg[0] == arg[1] ? u256(1) : u256(0));
case Instruction::ISZERO:
return EvaluationOk(arg[0] == 0 ? u256(1) : u256(0));
case Instruction::AND:
return EvaluationOk(arg[0] & arg[1]);
case Instruction::OR:
return EvaluationOk(arg[0] | arg[1]);
case Instruction::XOR:
return EvaluationOk(arg[0] ^ arg[1]);
case Instruction::BYTE:
return EvaluationOk(arg[0] >= 32 ? 0 : (arg[1] >> unsigned(8 * (31 - arg[0]))) & 0xff);
case Instruction::SHL:
return EvaluationOk(arg[0] > 255 ? 0 : (arg[1] << unsigned(arg[0])));
case Instruction::SHR:
return EvaluationOk(arg[0] > 255 ? 0 : (arg[1] >> unsigned(arg[0])));
case Instruction::SAR:
{
static u256 const hibit = u256(1) << 255;
if (arg[0] >= 256)
return EvaluationOk(arg[1] & hibit ? u256(-1) : 0);
else
{
unsigned amount = unsigned(arg[0]);
u256 v = arg[1] >> amount;
if (arg[1] & hibit)
v |= u256(-1) << (256 - amount);
return EvaluationOk(v);
}
}
case Instruction::ADDMOD:
return EvaluationOk(arg[2] == 0 ? 0 : u256((u512(arg[0]) + u512(arg[1])) % arg[2]));
case Instruction::MULMOD:
return EvaluationOk(arg[2] == 0 ? 0 : u256((u512(arg[0]) * u512(arg[1])) % arg[2]));
case Instruction::SIGNEXTEND:
if (arg[0] >= 31)
return EvaluationOk(arg[1]);
else
{
unsigned testBit = unsigned(arg[0]) * 8 + 7;
u256 ret = arg[1];
u256 mask = ((u256(1) << testBit) - 1);
if (boost::multiprecision::bit_test(ret, testBit))
ret |= ~mask;
else
ret &= mask;
return EvaluationOk(ret);
}
// --------------- blockchain stuff ---------------
case Instruction::KECCAK256:
case Instruction::ADDRESS:
case Instruction::BALANCE:
case Instruction::SELFBALANCE:
case Instruction::ORIGIN:
case Instruction::CALLER:
case Instruction::CALLVALUE:
case Instruction::CALLDATALOAD:
case Instruction::CALLDATASIZE:
case Instruction::CALLDATACOPY:
case Instruction::CODESIZE:
case Instruction::CODECOPY:
case Instruction::GASPRICE:
case Instruction::CHAINID:
case Instruction::BASEFEE:
case Instruction::BLOBHASH:
case Instruction::BLOBBASEFEE:
case Instruction::EXTCODESIZE:
case Instruction::EXTCODEHASH:
case Instruction::EXTCODECOPY:
case Instruction::RETURNDATASIZE:
case Instruction::RETURNDATACOPY:
case Instruction::MCOPY:
case Instruction::BLOCKHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
case Instruction::PREVRANDAO:
case Instruction::GASLIMIT:
return ImpureBuiltinEncountered();
// --------------- memory / storage / logs ---------------
case Instruction::MLOAD:
case Instruction::MSTORE:
case Instruction::MSTORE8:
case Instruction::SLOAD:
case Instruction::SSTORE:
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
case Instruction::TLOAD:
case Instruction::TSTORE:
return ImpureBuiltinEncountered();
// --------------- calls ---------------
case Instruction::DATALOADN:
case Instruction::CREATE:
case Instruction::CREATE2:
case Instruction::CALL:
case Instruction::CALLCODE:
case Instruction::DELEGATECALL:
case Instruction::STATICCALL:
case Instruction::RETURN:
case Instruction::REVERT:
case Instruction::INVALID:
case Instruction::SELFDESTRUCT:
return ImpureBuiltinEncountered();

case Instruction::POP:
return EvaluationOk();
// --------------- invalid in strict assembly ---------------
case Instruction::JUMP:
case Instruction::JUMPI:
case Instruction::JUMPDEST:
case Instruction::PUSH0:
case Instruction::PUSH1:
case Instruction::PUSH2:
case Instruction::PUSH3:
case Instruction::PUSH4:
case Instruction::PUSH5:
case Instruction::PUSH6:
case Instruction::PUSH7:
case Instruction::PUSH8:
case Instruction::PUSH9:
case Instruction::PUSH10:
case Instruction::PUSH11:
case Instruction::PUSH12:
case Instruction::PUSH13:
case Instruction::PUSH14:
case Instruction::PUSH15:
case Instruction::PUSH16:
case Instruction::PUSH17:
case Instruction::PUSH18:
case Instruction::PUSH19:
case Instruction::PUSH20:
case Instruction::PUSH21:
case Instruction::PUSH22:
case Instruction::PUSH23:
case Instruction::PUSH24:
case Instruction::PUSH25:
case Instruction::PUSH26:
case Instruction::PUSH27:
case Instruction::PUSH28:
case Instruction::PUSH29:
case Instruction::PUSH30:
case Instruction::PUSH31:
case Instruction::PUSH32:
case Instruction::DUP1:
case Instruction::DUP2:
case Instruction::DUP3:
case Instruction::DUP4:
case Instruction::DUP5:
case Instruction::DUP6:
case Instruction::DUP7:
case Instruction::DUP8:
case Instruction::DUP9:
case Instruction::DUP10:
case Instruction::DUP11:
case Instruction::DUP12:
case Instruction::DUP13:
case Instruction::DUP14:
case Instruction::DUP15:
case Instruction::DUP16:
case Instruction::SWAP1:
case Instruction::SWAP2:
case Instruction::SWAP3:
case Instruction::SWAP4:
case Instruction::SWAP5:
case Instruction::SWAP6:
case Instruction::SWAP7:
case Instruction::SWAP8:
case Instruction::SWAP9:
case Instruction::SWAP10:
case Instruction::SWAP11:
case Instruction::SWAP12:
case Instruction::SWAP13:
case Instruction::SWAP14:
case Instruction::SWAP15:
case Instruction::SWAP16:
{
yulAssert(false, "Instruction not allowed in strict assembly.");
}
}

util::unreachable();
}

}
52 changes: 52 additions & 0 deletions libyul/interpreter/PureEVMInstructionInterpreter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
This file is part of solidity.

solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Yul interpreter module that evaluates EVM instructions.
*/

#pragma once

#include <libyul/interpreter/Results.h>

#include <libsolutil/Numeric.h>

#include <liblangutil/EVMVersion.h>

#include <vector>

namespace solidity::evmasm
{
enum class Instruction: uint8_t;
}

namespace solidity::yul
{
class YulString;
struct BuiltinFunctionForEVM;
}

namespace solidity::yul::interpreter::PureEVMInstructionInterpreter
{

EvaluationResult eval(
langutil::EVMVersion _evmVersion,
BuiltinFunctionForEVM const& _builtinFunction,
std::vector<u256> const& _arguments
);

}
Loading