From 15417c418be4b8a18df60bb04189a6786fedbebe Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 16 Apr 2024 17:03:21 -0300 Subject: [PATCH 01/14] feat(call-opcode): Implement CALL More rigourous checks are needed --- system-contracts/contracts/EvmInterpreter.yul | 90 +++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 5badfcdaf..0737e1431 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -402,18 +402,80 @@ object "EVMInterpreter" { originalValue := mload(32) } - function getNonce() -> nonce { + + function warmAddress(addr) -> isWarm { + // TODO: Unhardcode this selector 0x8db2ba78 + mstore8(0, 0x8d) + mstore8(1, 0xb2) + mstore8(2, 0xba) + mstore8(3, 0x78) + mstore(4, addr) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) + + if iszero(success) { + // This error should never happen + revert(0, 0) + } + + isWarm := mload(0) + } + + function getNonce(addr) -> nonce { mstore8(0, 0xfb) mstore8(1, 0x1a) mstore8(2, 0x9a) mstore8(3, 0x57) - mstore(4, address()) - + mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) - nonce := mload(0) } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { + let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize + + gasSend, sp := popStackItem(oldSp) + addr, sp := popStackItem(sp) + value, sp := popStackItem(sp) + argsOffset, sp := popStackItem(sp) + argsSize, sp := popStackItem(sp) + retOffset, sp := popStackItem(sp) + retSize, sp := popStackItem(sp) + + + // code_execution_cost is the cost of the called code execution (limited by the gas parameter). + // If address is warm, then address_access_cost is 100, otherwise it is 2600. See section access sets. + // If value is not 0, then positive_value_cost is 9000. In this case there is also a call stipend that is given to make sure that a basic fallback function can be called. 2300 is thus removed from the cost, and also added to the gas input. + // If value is not 0 and the address given points to an empty account, then value_to_empty_account_cost is 25000. An account is empty if its balance is 0, its nonce is 0 and it has no code. + dynamicGas := expandMemory(add(retOffset,retSize)) + switch warmAddress(addr) + case 0 { dynamicGas := add(dynamicGas,2600) } + default { dynamicGas := add(dynamicGas,100) } + + if not(iszero(value)) { + dynamicGas := add(dynamicGas,6700) + gasSend := add(gasSend,2300) + + if isAddrEmpty(addr) { + dynamicGas := add(dynamicGas,25000) + } + } + + if gt(gasSend,div(mul(evmGasLeft,63),64)) { + gasSend := div(mul(evmGasLeft,63),64) + } + argsOffset := add(argsOffset,MEM_OFFSET_INNER()) + retOffset := add(retOffset,MEM_OFFSET_INNER()) + // TODO: More Checks are needed + let success := call(gasSend,addr,value,argsOffset,argsSize,retOffset,retSize) + + sp := pushStackItem(sp,success) + + // TODO: dynamicGas := add(dynamicGas,codeExecutionCost) how to do this? + // Check if the following is ok + dynamicGas := add(dynamicGas,gasSend) + evmGasLeft := chargeGas(evmGasLeft,dynamicGas) + } + function getEVMGas() -> evmGas { let GAS_DIVISOR, EVM_GAS_STIPEND, OVERHEAD := GAS_CONSTANTS() @@ -439,6 +501,17 @@ object "EVMInterpreter" { returnGas := chargeGas(gasToReturn, gasForCode) } + function isAddrEmpty(addr) -> isEmpty { + isEmpty := 0 + if and( and( + iszero(balance(addr)), + iszero(extcodesize(addr)) ), + iszero(getNonce(addr)) + ) { + isEmpty := 1 + } + } + function simulate( isCallerEVM, evmGasLeft, @@ -1286,7 +1359,7 @@ object "EVMInterpreter" { { let digest, nonce, addressEncoded, nonceEncoded, listLength, listLengthEconded - nonce := getNonce() + //nonce := getNonce() printString("getNonce") printHex(nonce) @@ -1360,6 +1433,13 @@ object "EVMInterpreter" { sp := pushStackItem(sp, addr) } + case 0xF1 { // OP_CALL + let dynamicGas + // A function was implemented in order to avoid stack depth errors. + dynamicGas, sp := performCall(sp,evmGasLeft) + + evmGasLeft := chargeGas(evmGasLeft,dynamicGas) + } // TODO: REST OF OPCODES default { // TODO: Revert properly here and report the unrecognized opcode From ad1dabe9c2306e0e96fe363b586f8ff72e3c534d Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 16 Apr 2024 17:21:53 -0300 Subject: [PATCH 02/14] fix(call-opcode): fix Merge --- system-contracts/contracts/EvmInterpreter.yul | 89 +++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index f700d6aee..bf1581e94 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1809,18 +1809,88 @@ object "EVMInterpreter" { originalValue := mload(32) } - function getNonce() -> nonce { + function warmAddress(addr) -> isWarm { + // TODO: Unhardcode this selector 0x8db2ba78 + mstore8(0, 0x8d) + mstore8(1, 0xb2) + mstore8(2, 0xba) + mstore8(3, 0x78) + mstore(4, addr) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) + + if iszero(success) { + // This error should never happen + revert(0, 0) + } + + isWarm := mload(0) + } + + function getNonce(addr) -> nonce { mstore8(0, 0xfb) mstore8(1, 0x1a) mstore8(2, 0x9a) mstore8(3, 0x57) - mstore(4, address()) - + mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) - nonce := mload(0) } - + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { + let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize + + gasSend, sp := popStackItem(oldSp) + addr, sp := popStackItem(sp) + value, sp := popStackItem(sp) + argsOffset, sp := popStackItem(sp) + argsSize, sp := popStackItem(sp) + retOffset, sp := popStackItem(sp) + retSize, sp := popStackItem(sp) + + + // code_execution_cost is the cost of the called code execution (limited by the gas parameter). + // If address is warm, then address_access_cost is 100, otherwise it is 2600. See section access sets. + // If value is not 0, then positive_value_cost is 9000. In this case there is also a call stipend that is given to make sure that a basic fallback function can be called. 2300 is thus removed from the cost, and also added to the gas input. + // If value is not 0 and the address given points to an empty account, then value_to_empty_account_cost is 25000. An account is empty if its balance is 0, its nonce is 0 and it has no code. + dynamicGas := expandMemory(add(retOffset,retSize)) + switch warmAddress(addr) + case 0 { dynamicGas := add(dynamicGas,2600) } + default { dynamicGas := add(dynamicGas,100) } + + if not(iszero(value)) { + dynamicGas := add(dynamicGas,6700) + gasSend := add(gasSend,2300) + + if isAddrEmpty(addr) { + dynamicGas := add(dynamicGas,25000) + } + } + + if gt(gasSend,div(mul(evmGasLeft,63),64)) { + gasSend := div(mul(evmGasLeft,63),64) + } + argsOffset := add(argsOffset,MEM_OFFSET_INNER()) + retOffset := add(retOffset,MEM_OFFSET_INNER()) + // TODO: More Checks are needed + let success := call(gasSend,addr,value,argsOffset,argsSize,retOffset,retSize) + + sp := pushStackItem(sp,success) + + // TODO: dynamicGas := add(dynamicGas,codeExecutionCost) how to do this? + // Check if the following is ok + dynamicGas := add(dynamicGas,gasSend) + evmGasLeft := chargeGas(evmGasLeft,dynamicGas) + } + + function isAddrEmpty(addr) -> isEmpty { + isEmpty := 0 + if and( and( + iszero(balance(addr)), + iszero(extcodesize(addr)) ), + iszero(getNonce(addr)) + ) { + isEmpty := 1 + } + } //////////////////////////////////////////////////////////////// // FALLBACK //////////////////////////////////////////////////////////////// @@ -2679,7 +2749,7 @@ object "EVMInterpreter" { { let digest, nonce, addressEncoded, nonceEncoded, listLength, listLengthEconded - nonce := getNonce() + //nonce := getNonce() addressEncoded := and( add(address(), shl(160, 0x94)), @@ -2744,6 +2814,13 @@ object "EVMInterpreter" { sp := pushStackItem(sp, addr) } + case 0xF1 { // OP_CALL + let dynamicGas + // A function was implemented in order to avoid stack depth errors. + dynamicGas, sp := performCall(sp,evmGasLeft) + + evmGasLeft := chargeGas(evmGasLeft,dynamicGas) + } // TODO: REST OF OPCODES default { // TODO: Revert properly here and report the unrecognized opcode From 55b32a640243545ef17f11cd57d2b675cb3160cb Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 10:47:30 -0300 Subject: [PATCH 03/14] feat(call-opcode): Add function _isEVM() --- system-contracts/contracts/EvmInterpreter.yul | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index bf1581e94..9c16e68c1 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1835,6 +1835,29 @@ object "EVMInterpreter" { let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) nonce := mload(0) } + + function _isEVM(_addr) -> isEVM { + // bytes4 selector = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.isAccountEVM.selector; + // function isAccountEVM(address _addr) external view returns (bool); + let selector := 0x8c040477 + // IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( + // address(SYSTEM_CONTRACTS_OFFSET + 0x02) + // ); + // SYSTEM_COTNRACTS_OFFSET == 0x8000 // 2^15 -> defined by zkSync + let addr := add(0x8000, 0x02) + + mstore(0, selector) + mstore(4, _addr) + let success := staticcall(gas(), addr, 0, 36, 0, 32) + + if iszero(success) { + // This error should never happen + revert(0, 0) + } + + isEVM := mload(0) + } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize @@ -1880,7 +1903,7 @@ object "EVMInterpreter" { dynamicGas := add(dynamicGas,gasSend) evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } - + function isAddrEmpty(addr) -> isEmpty { isEmpty := 0 if and( and( From 101e4c16184a59ee86da75158bc22af3e8c19da6 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 11:05:53 -0300 Subject: [PATCH 04/14] feat(call-opcode): Add function _pushEVMFrame() and _popEVMFrame() --- system-contracts/contracts/EvmInterpreter.yul | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 9c16e68c1..5646a0847 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1858,6 +1858,39 @@ object "EVMInterpreter" { isEVM := mload(0) } + function _pushEVMFrame(_passGas, _isStatic) { + // function pushEVMFrame(uint256 _passGas, bool _isStatic) external + let selector := 0xead77156 + // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); + let addr := add(0x8000, 0x13) + + mstore(0, selector) + mstore(4, _passGas) + mstore(36, _isStatic) + + let success := call(gas(), addr, 0, 0, 68, 0, 0) + if iszero(success) { + // This error should never happen + revert(0, 0) + } + } + + function _popEVMFrame() { + // function popEVMFrame() external + // 0xe467d2f0 + let selector := 0xe467d2f0 + // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); + let addr := add(0x8000, 0x13) + + mstore(0, selector) + + let success := call(gas(), addr, 0, 0, 4, 0, 0) + if iszero(success) { + // This error should never happen + revert(0, 0) + } + } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize From f6a2575f36340fe43fae8bb8ecd9daa030437a14 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 11:41:35 -0300 Subject: [PATCH 05/14] feat(gas-related-function): Add gas related functions, needed for OP_CALL --- system-contracts/contracts/EvmInterpreter.yul | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 5646a0847..040ae20f2 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1891,6 +1891,32 @@ object "EVMInterpreter" { } } + // Each evm gas is 5 zkEVM one + // FIXME: change this variable to reflect real ergs : gas ratio + function GAS_DIVISOR() -> gas_div { gas_div := 5 } + function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 + function OVERHEAD() -> overhead { overhead := 2000 } + + function _calcEVMGas(_zkevmGas) -> calczkevmGas { + calczkevmGas := div(_zkevmGas, GAS_DIVISOR()) + } + + function _getEVMGas() -> evmGas { + let _gas := gas() + let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + + if or(gt(requiredGas, _gas), eq(requiredGas, _gas)) { + evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR()) + } + } + + function _getZkEVMGas(_evmGas) -> zkevmGas { + /* + TODO: refine the formula, especially with regard to decommitment costs + */ + zkevmGas := mul(_evmGas, GAS_DIVISOR()) + } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize From b723f3cad2cbbc73c6999c2a87f5f4c907006d78 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 14:02:07 -0300 Subject: [PATCH 06/14] chore: indent properly --- system-contracts/contracts/EvmInterpreter.yul | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 040ae20f2..9b67bca0e 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1891,31 +1891,31 @@ object "EVMInterpreter" { } } - // Each evm gas is 5 zkEVM one - // FIXME: change this variable to reflect real ergs : gas ratio - function GAS_DIVISOR() -> gas_div { gas_div := 5 } - function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 - function OVERHEAD() -> overhead { overhead := 2000 } + // Each evm gas is 5 zkEVM one + // FIXME: change this variable to reflect real ergs : gas ratio + function GAS_DIVISOR() -> gas_div { gas_div := 5 } + function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 + function OVERHEAD() -> overhead { overhead := 2000 } - function _calcEVMGas(_zkevmGas) -> calczkevmGas { - calczkevmGas := div(_zkevmGas, GAS_DIVISOR()) - } + function _calcEVMGas(_zkevmGas) -> calczkevmGas { + calczkevmGas := div(_zkevmGas, GAS_DIVISOR()) + } - function _getEVMGas() -> evmGas { - let _gas := gas() - let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + function _getEVMGas() -> evmGas { + let _gas := gas() + let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) - if or(gt(requiredGas, _gas), eq(requiredGas, _gas)) { - evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR()) - } + if or(gt(requiredGas, _gas), eq(requiredGas, _gas)) { + evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR()) } + } - function _getZkEVMGas(_evmGas) -> zkevmGas { - /* - TODO: refine the formula, especially with regard to decommitment costs - */ - zkevmGas := mul(_evmGas, GAS_DIVISOR()) - } + function _getZkEVMGas(_evmGas) -> zkevmGas { + /* + TODO: refine the formula, especially with regard to decommitment costs + */ + zkevmGas := mul(_evmGas, GAS_DIVISOR()) + } function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize From b807d10b9c0217e4577f3c99c6630e0850c13b46 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 14:54:17 -0300 Subject: [PATCH 07/14] feat(verbatims-functions): Add verbatims --- system-contracts/contracts/EvmInterpreter.yul | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 9b67bca0e..4ec943ca8 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1483,6 +1483,32 @@ object "EVMInterpreter" { } object "EVMInterpreter_deployed" { code { + + function loadCalldataIntoActivePtr() { + verbatim_1i_0o("active_ptr_data_load", 0xFFFF) + } + + // TODO: Check if the verbatim is ok + function loadReturndataIntoActivePtr() { + verbatim_0i_0o("return_data_ptr_to_active") + } + + function getActivePtrDataSize() -> size { + size := verbatim_0i_1o("active_ptr_data_size") + } + + function copyActivePtrData(_dest, _source, _size) { + verbatim_3i_0o("active_ptr_data_copy", _dest, _source, _size) + } + + function ptrAddIntoActive(_dest) { + verbatim_1i_0o("active_ptr_add_assign", _dest) + } + + function ptrShrinkIntoActive(_dest) { + verbatim_1i_0o("active_ptr_shrink_assign", _dest) + } + function SYSTEM_CONTRACTS_OFFSET() -> offset { offset := 0x8000 } @@ -1917,6 +1943,39 @@ object "EVMInterpreter" { zkevmGas := mul(_evmGas, GAS_DIVISOR()) } + function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{ + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shr(5, 5))// 5 << 5 == 5 * 32 + let rtsz := returndatasize() + + loadReturndataIntoActivePtr() + + // if (rtsz > 31) + switch gt(31, rtsz) + case true { + returndatacopy(0, 0, 32) + _gasLeft := mload(0) + returndatacopy(_outputOffset, 32, _outputLen) + mstore(lastRtSzOffset, sub(rtsz, 32)) + + // Skip the returnData + ptrAddIntoActive(32) + } + case false { + _gasLeft := 0 + _eraseReturndataPointer() + } + } + + function _eraseReturndataPointer() { + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + + let activePtrSize := getActivePtrDataSize() + ptrShrinkIntoActive(and(activePtrSize, 0xFFFFFFFF))// uint32(activePtrSize) + mstore(lastRtSzOffset, 0) + } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize From 72847ca1038283cd0c466aa6d45e0747898081c9 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 15:08:30 -0300 Subject: [PATCH 08/14] feat(call-related-functions): Add _saveReturnDataAfterZkEVMCall() --- system-contracts/contracts/EvmInterpreter.yul | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 4ec943ca8..008d92ebc 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1488,7 +1488,6 @@ object "EVMInterpreter" { verbatim_1i_0o("active_ptr_data_load", 0xFFFF) } - // TODO: Check if the verbatim is ok function loadReturndataIntoActivePtr() { verbatim_0i_0o("return_data_ptr_to_active") } @@ -1976,6 +1975,13 @@ object "EVMInterpreter" { mstore(lastRtSzOffset, 0) } + function _saveReturndataAfterZkEVMCall() { + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + + mstore(lastRtSzOffset, returndatasize()) + } + function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize From 849f040d8c7a39e24601d41f4b0a155e29ce3437 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 16:08:15 -0300 Subject: [PATCH 09/14] feat(call-related-functions): Add _performCall() // Stack depth errors (WIP) --- system-contracts/contracts/EvmInterpreter.yul | 112 +++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 008d92ebc..b57ff29da 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -1982,7 +1982,7 @@ object "EVMInterpreter" { mstore(lastRtSzOffset, returndatasize()) } - function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { + function performCall(oldSp, evmGasLeft, isStatic) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize gasSend, sp := popStackItem(oldSp) @@ -2018,7 +2018,19 @@ object "EVMInterpreter" { argsOffset := add(argsOffset,MEM_OFFSET_INNER()) retOffset := add(retOffset,MEM_OFFSET_INNER()) // TODO: More Checks are needed - let success := call(gasSend,addr,value,argsOffset,argsSize,retOffset,retSize) + // Check gas + let success + success, evmGasLeft := _performCall( + _isEVM(addr), + isStatic, + gasSend, + addr, + value, + argsOffset, + argsSize, + retOffset, + retSize + ) sp := pushStackItem(sp,success) @@ -2028,6 +2040,99 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } + // This function is called inside performCall() + // TODO: optimize after it works + function _performCall( + _calleeIsEVM, + _isStatic, + _calleeGas, + _callee, + _value, + _inputOffset, + _inputLen, + _outputOffset, + _outputLen + ) -> success, _gasLeft { + // From evm_codes, reverts if: + // The current execution context is from a STATICCALL + // and the value (stack index 2) is not 0 (since Byzantium fork). + if _isStatic { + if not(iszero(_value)) { + revert(0, 0) + } + success, _gasLeft := _performStaticCall( + _calleeIsEVM, + _calleeGas, + _callee, + _inputOffset, + _inputLen, + _outputOffset, + _outputLen + ) + } + + if _calleeIsEVM { + _pushEVMFrame(_calleeGas, _isStatic) + success := call(_calleeGas, _callee, _value, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } + + // zkEVM native + if and(not(_calleeIsEVM), not(_isStatic)) { + _calleeGas := _getZkEVMGas(_calleeGas) + let zkevmGasBefore := gas() + success := call(_calleeGas, _callee, _value, _inputOffset, _inputLen, _outputOffset, _outputLen) + + _saveReturndataAfterZkEVMCall() + + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + _gasLeft := 0 + if gt(_calleeGas, gasUsed) { + _gasLeft := sub(_calleeGas, gasUsed) + } + } + + } + + function _performStaticCall( + _calleeIsEVM, + _calleeGas, + _callee, + _inputOffset, + _inputLen, + _outputOffset, + _outputLen + ) -> success, _gasLeft { + if _calleeIsEVM { + _pushEVMFrame(_calleeGas, true) + // TODO Check the following comment from zkSync .sol. + // We can not just pass all gas here to prevert overflow of zkEVM gas counter + success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } + + // zkEVM native + if not(_calleeIsEVM) { + _calleeGas := _getZkEVMGas(_calleeGas) + let zkevmGasBefore := gas() + success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) + + _saveReturndataAfterZkEVMCall() + + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + _gasLeft := 0 + if gt(_calleeGas, gasUsed) { + _gasLeft := sub(_calleeGas, gasUsed) + } + } + } + function isAddrEmpty(addr) -> isEmpty { isEmpty := 0 if and( and( @@ -2038,6 +2143,7 @@ object "EVMInterpreter" { isEmpty := 1 } } + //////////////////////////////////////////////////////////////// // FALLBACK //////////////////////////////////////////////////////////////// @@ -2964,7 +3070,7 @@ object "EVMInterpreter" { case 0xF1 { // OP_CALL let dynamicGas // A function was implemented in order to avoid stack depth errors. - dynamicGas, sp := performCall(sp,evmGasLeft) + dynamicGas, sp := performCall(sp, evmGasLeft, isStatic) evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } From e3380330a1ae960ab09439a64b90855496bea362 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Wed, 17 Apr 2024 17:06:26 -0300 Subject: [PATCH 10/14] Fix stack too deep error --- system-contracts/contracts/EvmInterpreter.yul | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index b57ff29da..3c5b43366 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -2020,17 +2020,45 @@ object "EVMInterpreter" { // TODO: More Checks are needed // Check gas let success - success, evmGasLeft := _performCall( - _isEVM(addr), - isStatic, - gasSend, - addr, - value, - argsOffset, - argsSize, - retOffset, - retSize - ) + + if isStatic { + if not(iszero(value)) { + revert(0, 0) + } + success, evmGasLeft := _performStaticCall( + _isEVM(addr), + gasSend, + addr, + argsOffset, + argsSize, + retOffset, + retSize + ) + } + + if _isEVM(addr) { + _pushEVMFrame(gasSend, isStatic) + success := call(gasSend, addr, value, argsOffset, argsSize, 0, 0) + + evmGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + + // zkEVM native + if and(not(_isEVM(addr)), not(isStatic)) { + gasSend := _getZkEVMGas(gasSend) + let zkevmGasBefore := gas() + success := call(gasSend, addr, value, argsOffset, argsSize, retOffset, retSize) + + _saveReturndataAfterZkEVMCall() + + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + evmGasLeft := 0 + if gt(gasSend, gasUsed) { + evmGasLeft := sub(gasSend, gasUsed) + } + } sp := pushStackItem(sp,success) From 7b1b7b1bd4dd17415b97742d1ce9afa419913d35 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 17:11:38 -0300 Subject: [PATCH 11/14] chore(remove dead code): Remove _performCall() --- system-contracts/contracts/EvmInterpreter.yul | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index 3c5b43366..d23deca44 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -2068,63 +2068,6 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } - // This function is called inside performCall() - // TODO: optimize after it works - function _performCall( - _calleeIsEVM, - _isStatic, - _calleeGas, - _callee, - _value, - _inputOffset, - _inputLen, - _outputOffset, - _outputLen - ) -> success, _gasLeft { - // From evm_codes, reverts if: - // The current execution context is from a STATICCALL - // and the value (stack index 2) is not 0 (since Byzantium fork). - if _isStatic { - if not(iszero(_value)) { - revert(0, 0) - } - success, _gasLeft := _performStaticCall( - _calleeIsEVM, - _calleeGas, - _callee, - _inputOffset, - _inputLen, - _outputOffset, - _outputLen - ) - } - - if _calleeIsEVM { - _pushEVMFrame(_calleeGas, _isStatic) - success := call(_calleeGas, _callee, _value, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if and(not(_calleeIsEVM), not(_isStatic)) { - _calleeGas := _getZkEVMGas(_calleeGas) - let zkevmGasBefore := gas() - success := call(_calleeGas, _callee, _value, _inputOffset, _inputLen, _outputOffset, _outputLen) - - _saveReturndataAfterZkEVMCall() - - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - _gasLeft := 0 - if gt(_calleeGas, gasUsed) { - _gasLeft := sub(_calleeGas, gasUsed) - } - } - - } - function _performStaticCall( _calleeIsEVM, _calleeGas, From badd8ccbad78aec77471e4bd8328d301ee86b34f Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 17 Apr 2024 17:27:46 -0300 Subject: [PATCH 12/14] chore(copy code): Copy code inside the two objects --- system-contracts/contracts/EvmInterpreter.yul | 222 +++++++++++++++++- 1 file changed, 209 insertions(+), 13 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index d23deca44..a643fccdb 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -62,6 +62,10 @@ object "EVMInterpreter" { verbatim_1i_0o("active_ptr_data_load", 0xFFFF) } + function loadReturndataIntoActivePtr() { + verbatim_0i_0o("return_data_ptr_to_active") + } + function getActivePtrDataSize() -> size { size := verbatim_0i_1o("active_ptr_data_size") } @@ -70,6 +74,14 @@ object "EVMInterpreter" { verbatim_3i_0o("active_ptr_data_copy", _dest, _source, _size) } + function ptrAddIntoActive(_dest) { + verbatim_1i_0o("active_ptr_add_assign", _dest) + } + + function ptrShrinkIntoActive(_dest) { + verbatim_1i_0o("active_ptr_shrink_assign", _dest) + } + function SYSTEM_CONTRACTS_OFFSET() -> offset { offset := 0x8000 } @@ -430,7 +442,128 @@ object "EVMInterpreter" { nonce := mload(0) } - function performCall(oldSp,evmGasLeft) -> dynamicGas,sp { + function _isEVM(_addr) -> isEVM { + // bytes4 selector = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.isAccountEVM.selector; + // function isAccountEVM(address _addr) external view returns (bool); + let selector := 0x8c040477 + // IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( + // address(SYSTEM_CONTRACTS_OFFSET + 0x02) + // ); + // SYSTEM_COTNRACTS_OFFSET == 0x8000 // 2^15 -> defined by zkSync + let addr := add(0x8000, 0x02) + + mstore(0, selector) + mstore(4, _addr) + let success := staticcall(gas(), addr, 0, 36, 0, 32) + + if iszero(success) { + // This error should never happen + revert(0, 0) + } + + isEVM := mload(0) + } + + function _pushEVMFrame(_passGas, _isStatic) { + // function pushEVMFrame(uint256 _passGas, bool _isStatic) external + let selector := 0xead77156 + // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); + let addr := add(0x8000, 0x13) + + mstore(0, selector) + mstore(4, _passGas) + mstore(36, _isStatic) + + let success := call(gas(), addr, 0, 0, 68, 0, 0) + if iszero(success) { + // This error should never happen + revert(0, 0) + } + } + + function _popEVMFrame() { + // function popEVMFrame() external + // 0xe467d2f0 + let selector := 0xe467d2f0 + // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); + let addr := add(0x8000, 0x13) + + mstore(0, selector) + + let success := call(gas(), addr, 0, 0, 4, 0, 0) + if iszero(success) { + // This error should never happen + revert(0, 0) + } + } + + // Each evm gas is 5 zkEVM one + // FIXME: change this variable to reflect real ergs : gas ratio + function GAS_DIVISOR() -> gas_div { gas_div := 5 } + function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 + function OVERHEAD() -> overhead { overhead := 2000 } + + function _calcEVMGas(_zkevmGas) -> calczkevmGas { + calczkevmGas := div(_zkevmGas, GAS_DIVISOR()) + } + + function getEVMGas() -> evmGas { + let _gas := gas() + let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + + if or(gt(requiredGas, _gas), eq(requiredGas, _gas)) { + evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR()) + } + } + + function _getZkEVMGas(_evmGas) -> zkevmGas { + /* + TODO: refine the formula, especially with regard to decommitment costs + */ + zkevmGas := mul(_evmGas, GAS_DIVISOR()) + } + + function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{ + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shr(5, 5))// 5 << 5 == 5 * 32 + let rtsz := returndatasize() + + loadReturndataIntoActivePtr() + + // if (rtsz > 31) + switch gt(31, rtsz) + case true { + returndatacopy(0, 0, 32) + _gasLeft := mload(0) + returndatacopy(_outputOffset, 32, _outputLen) + mstore(lastRtSzOffset, sub(rtsz, 32)) + + // Skip the returnData + ptrAddIntoActive(32) + } + case false { + _gasLeft := 0 + _eraseReturndataPointer() + } + } + + function _eraseReturndataPointer() { + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + + let activePtrSize := getActivePtrDataSize() + ptrShrinkIntoActive(and(activePtrSize, 0xFFFFFFFF))// uint32(activePtrSize) + mstore(lastRtSzOffset, 0) + } + + function _saveReturndataAfterZkEVMCall() { + //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; + let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + + mstore(lastRtSzOffset, returndatasize()) + } + + function performCall(oldSp, evmGasLeft, isStatic) -> dynamicGas,sp { let gasSend,addr,value,argsOffset,argsSize,retOffset,retSize gasSend, sp := popStackItem(oldSp) @@ -466,7 +599,47 @@ object "EVMInterpreter" { argsOffset := add(argsOffset,MEM_OFFSET_INNER()) retOffset := add(retOffset,MEM_OFFSET_INNER()) // TODO: More Checks are needed - let success := call(gasSend,addr,value,argsOffset,argsSize,retOffset,retSize) + // Check gas + let success + + if isStatic { + if not(iszero(value)) { + revert(0, 0) + } + success, evmGasLeft := _performStaticCall( + _isEVM(addr), + gasSend, + addr, + argsOffset, + argsSize, + retOffset, + retSize + ) + } + + if _isEVM(addr) { + _pushEVMFrame(gasSend, isStatic) + success := call(gasSend, addr, value, argsOffset, argsSize, 0, 0) + + evmGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + + // zkEVM native + if and(not(_isEVM(addr)), not(isStatic)) { + gasSend := _getZkEVMGas(gasSend) + let zkevmGasBefore := gas() + success := call(gasSend, addr, value, argsOffset, argsSize, retOffset, retSize) + + _saveReturndataAfterZkEVMCall() + + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + evmGasLeft := 0 + if gt(gasSend, gasUsed) { + evmGasLeft := sub(gasSend, gasUsed) + } + } sp := pushStackItem(sp,success) @@ -476,16 +649,39 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } - function getEVMGas() -> evmGas { - let GAS_DIVISOR, EVM_GAS_STIPEND, OVERHEAD := GAS_CONSTANTS() - - let gasLeft := gas() - let requiredGas := add(EVM_GAS_STIPEND, OVERHEAD) - - evmGas := div(sub(gasLeft, requiredGas), GAS_DIVISOR) + function _performStaticCall( + _calleeIsEVM, + _calleeGas, + _callee, + _inputOffset, + _inputLen, + _outputOffset, + _outputLen + ) -> success, _gasLeft { + if _calleeIsEVM { + _pushEVMFrame(_calleeGas, true) + // TODO Check the following comment from zkSync .sol. + // We can not just pass all gas here to prevert overflow of zkEVM gas counter + success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } + + // zkEVM native + if not(_calleeIsEVM) { + _calleeGas := _getZkEVMGas(_calleeGas) + let zkevmGasBefore := gas() + success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) + + _saveReturndataAfterZkEVMCall() + + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - if lt(gasLeft, requiredGas) { - evmGas := 0 + _gasLeft := 0 + if gt(_calleeGas, gasUsed) { + _gasLeft := sub(_calleeGas, gasUsed) + } } } @@ -1436,7 +1632,7 @@ object "EVMInterpreter" { case 0xF1 { // OP_CALL let dynamicGas // A function was implemented in order to avoid stack depth errors. - dynamicGas, sp := performCall(sp,evmGasLeft) + dynamicGas, sp := performCall(sp, evmGasLeft, isStatic) evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } @@ -1926,7 +2122,7 @@ object "EVMInterpreter" { calczkevmGas := div(_zkevmGas, GAS_DIVISOR()) } - function _getEVMGas() -> evmGas { + function getEVMGas() -> evmGas { let _gas := gas() let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) From fcaa58427b2e8677d57db42ac97f0b0917b8ed31 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 18 Apr 2024 10:39:33 -0300 Subject: [PATCH 13/14] fix(call tests): Fix selector store inside _isEVM() --- system-contracts/contracts/EvmInterpreter.yul | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index ee3664f05..f45c44ca5 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -527,12 +527,13 @@ object "EVMInterpreter" { // IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - // SYSTEM_COTNRACTS_OFFSET == 0x8000 // 2^15 -> defined by zkSync - let addr := add(0x8000, 0x02) - mstore(0, selector) + mstore8(0, 0x8c) + mstore8(1, 0x04) + mstore8(2, 0x04) + mstore8(3, 0x77) mstore(4, _addr) - let success := staticcall(gas(), addr, 0, 36, 0, 32) + let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) if iszero(success) { // This error should never happen @@ -767,7 +768,6 @@ object "EVMInterpreter" { // TODO: dynamicGas := add(dynamicGas,codeExecutionCost) how to do this? // Check if the following is ok dynamicGas := add(dynamicGas,gasSend) - evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } function _performStaticCall( @@ -2255,12 +2255,14 @@ object "EVMInterpreter" { // IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - // SYSTEM_COTNRACTS_OFFSET == 0x8000 // 2^15 -> defined by zkSync - let addr := add(0x8000, 0x02) - mstore(0, selector) + mstore8(0, 0x8c) + mstore8(1, 0x04) + mstore8(2, 0x04) + mstore8(3, 0x77) mstore(4, _addr) - let success := staticcall(gas(), addr, 0, 36, 0, 32) + + let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) if iszero(success) { // This error should never happen @@ -2407,7 +2409,7 @@ object "EVMInterpreter" { // TODO: More Checks are needed // Check gas let success - + if isStatic { if not(iszero(value)) { revert(0, 0) @@ -2436,9 +2438,7 @@ object "EVMInterpreter" { gasSend := _getZkEVMGas(gasSend) let zkevmGasBefore := gas() success := call(gasSend, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) evmGasLeft := 0 @@ -2448,11 +2448,10 @@ object "EVMInterpreter" { } sp := pushStackItem(sp,success) - + // TODO: dynamicGas := add(dynamicGas,codeExecutionCost) how to do this? // Check if the following is ok dynamicGas := add(dynamicGas,gasSend) - evmGasLeft := chargeGas(evmGasLeft,dynamicGas) } function _performStaticCall( From 9900480d1118b55bd1583a497b4a3f533175fc93 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 18 Apr 2024 13:44:30 -0300 Subject: [PATCH 14/14] fix(call tests): Fix constants and Add prints (WIP) --- system-contracts/contracts/EvmInterpreter.yul | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index f45c44ca5..c6a1c1e75 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -546,14 +546,15 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external let selector := 0xead77156 - // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); - let addr := add(0x8000, 0x13) - mstore(0, selector) + mstore8(0, 0xea) + mstore8(1, 0xd7) + mstore8(2, 0x71) + mstore8(3, 0x56) mstore(4, _passGas) mstore(36, _isStatic) - let success := call(gas(), addr, 0, 0, 68, 0, 0) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 68, 0, 0) if iszero(success) { // This error should never happen revert(0, 0) @@ -564,12 +565,13 @@ object "EVMInterpreter" { // function popEVMFrame() external // 0xe467d2f0 let selector := 0xe467d2f0 - // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); - let addr := add(0x8000, 0x13) - mstore(0, selector) + mstore8(0, 0xe4) + mstore8(1, 0x67) + mstore8(2, 0xd2) + mstore8(3, 0xf0) - let success := call(gas(), addr, 0, 0, 4, 0, 0) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { // This error should never happen revert(0, 0) @@ -646,15 +648,18 @@ object "EVMInterpreter" { } function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{ - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shr(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() let rtsz := returndatasize() loadReturndataIntoActivePtr() // if (rtsz > 31) - switch gt(31, rtsz) - case true { + switch gt(rtsz, 31) + case 0 { + _gasLeft := 0 + _eraseReturndataPointer() + } + default { returndatacopy(0, 0, 32) _gasLeft := mload(0) returndatacopy(_outputOffset, 32, _outputLen) @@ -663,15 +668,10 @@ object "EVMInterpreter" { // Skip the returnData ptrAddIntoActive(32) } - case false { - _gasLeft := 0 - _eraseReturndataPointer() - } } function _eraseReturndataPointer() { - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() let activePtrSize := getActivePtrDataSize() ptrShrinkIntoActive(and(activePtrSize, 0xFFFFFFFF))// uint32(activePtrSize) @@ -679,8 +679,7 @@ object "EVMInterpreter" { } function _saveReturndataAfterZkEVMCall() { - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() mstore(lastRtSzOffset, returndatasize()) } @@ -2275,14 +2274,15 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external let selector := 0xead77156 - // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); - let addr := add(0x8000, 0x13) - mstore(0, selector) + mstore8(0, 0xea) + mstore8(1, 0xd7) + mstore8(2, 0x71) + mstore8(3, 0x56) mstore(4, _passGas) mstore(36, _isStatic) - let success := call(gas(), addr, 0, 0, 68, 0, 0) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 68, 0, 0) if iszero(success) { // This error should never happen revert(0, 0) @@ -2293,12 +2293,13 @@ object "EVMInterpreter" { // function popEVMFrame() external // 0xe467d2f0 let selector := 0xe467d2f0 - // EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); - let addr := add(0x8000, 0x13) - mstore(0, selector) + mstore8(0, 0xe4) + mstore8(1, 0x67) + mstore8(2, 0xd2) + mstore8(3, 0xf0) - let success := call(gas(), addr, 0, 0, 4, 0, 0) + let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { // This error should never happen revert(0, 0) @@ -2332,15 +2333,22 @@ object "EVMInterpreter" { } function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{ - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shr(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() let rtsz := returndatasize() loadReturndataIntoActivePtr() // if (rtsz > 31) - switch gt(31, rtsz) - case true { + printHex(returndatasize()) + switch gt(rtsz, 31) + case 0 { + // Unexpected return data. + printString("Unexpected return data") + _gasLeft := 0 + _eraseReturndataPointer() + } + default { + printString("SHOULD ENTER") returndatacopy(0, 0, 32) _gasLeft := mload(0) returndatacopy(_outputOffset, 32, _outputLen) @@ -2349,15 +2357,10 @@ object "EVMInterpreter" { // Skip the returnData ptrAddIntoActive(32) } - case false { - _gasLeft := 0 - _eraseReturndataPointer() - } } function _eraseReturndataPointer() { - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() let activePtrSize := getActivePtrDataSize() ptrShrinkIntoActive(and(activePtrSize, 0xFFFFFFFF))// uint32(activePtrSize) @@ -2365,8 +2368,7 @@ object "EVMInterpreter" { } function _saveReturndataAfterZkEVMCall() { - //uint256 constant LAST_RETURNDATA_SIZE_OFFSET = DEBUG_SLOT_OFFSET + 5 * 32; - let lastRtSzOffset := add(DEBUG_SLOT_OFFSET(), shl(5, 5))// 5 << 5 == 5 * 32 + let lastRtSzOffset := LAST_RETURNDATA_SIZE_OFFSET() mstore(lastRtSzOffset, returndatasize()) } @@ -2411,6 +2413,7 @@ object "EVMInterpreter" { let success if isStatic { + printString("Static") if not(iszero(value)) { revert(0, 0) } @@ -2426,15 +2429,18 @@ object "EVMInterpreter" { } if _isEVM(addr) { + printString("isEVM") _pushEVMFrame(gasSend, isStatic) success := call(gasSend, addr, value, argsOffset, argsSize, 0, 0) - + printHex(success) evmGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) _popEVMFrame() + printString("EVM Done") } // zkEVM native - if and(not(_isEVM(addr)), not(isStatic)) { + if and(iszero(_isEVM(addr)), iszero(isStatic)) { + printString("is zkEVM") gasSend := _getZkEVMGas(gasSend) let zkevmGasBefore := gas() success := call(gasSend, addr, value, argsOffset, argsSize, retOffset, retSize) @@ -2445,6 +2451,7 @@ object "EVMInterpreter" { if gt(gasSend, gasUsed) { evmGasLeft := sub(gasSend, gasUsed) } + printString("zkEVM Done") } sp := pushStackItem(sp,success)