From 2bc87858f06583d2e475cd63f96875ab602e3ae8 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 23 Sep 2024 13:00:05 +0200 Subject: [PATCH 1/4] Cleanup EvmInterpreterFunctions --- system-contracts/contracts/EvmInterpreter.yul | 300 +++--------------- .../EvmInterpreterFunctions.template.yul | 150 ++------- 2 files changed, 60 insertions(+), 390 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index dca506aab..a848321a4 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -80,10 +80,6 @@ object "EVMInterpreter" { returnGas := chargeGas(gasToReturn, gasForCode) } - function SYSTEM_CONTRACTS_OFFSET() -> offset { - offset := 0x8000 - } - function ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008002 } @@ -96,10 +92,6 @@ object "EVMInterpreter" { addr := 0x0000000000000000000000000000000000008006 } - function CODE_ADDRESS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFFE - } - function CODE_ORACLE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008012 } @@ -108,12 +100,8 @@ object "EVMInterpreter" { addr := 0x0000000000000000000000000000000000008013 } - function CALLFLAGS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFEF - } - function DEBUG_SLOT_OFFSET() -> offset { - offset := mul(32, 32) + offset := mul(32, 32) // TODO cleanup } function LAST_RETURNDATA_SIZE_OFFSET() -> offset { @@ -156,6 +144,25 @@ object "EVMInterpreter" { max_uint := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff } + // Essentially a NOP that will not get optimized away by the compiler + function $llvm_NoInline_llvm$_unoptimized() { + pop(1) + } + + function printHex(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() + } + + function printString(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() + } + // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { @@ -293,21 +300,6 @@ object "EVMInterpreter" { hash := mload(0) } - function _getCodeHash(account) -> hash { - // function getCodeHash(uint256 _input) external view override returns (bytes32) - mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) - mstore(4, account) - - let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) - - if iszero(success) { - // This error should never happen - revert(0, 0) - } - - hash := mload(0) - } - function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") isStatic := iszero(iszero(and(isStatic, 0x04))) @@ -424,13 +416,6 @@ object "EVMInterpreter" { } } - function getMin(a, b) -> min { - min := b - if lt(a, b) { - min := a - } - } - function bitLength(n) -> bitLen { for { } gt(n, 0) { } { // while(n > 0) if iszero(n) { @@ -586,13 +571,6 @@ object "EVMInterpreter" { } } - function checkMultipleOverflow(data1, data2, data3, evmGasLeft) { - checkOverflow(data1, data2, evmGasLeft) - checkOverflow(data1, data3, evmGasLeft) - checkOverflow(data2, data3, evmGasLeft) - checkOverflow(add(data1, data2), data3, evmGasLeft) - } - function checkOverflow(data1, data2, evmGasLeft) { if lt(add(data1, data2), data2) { revertWithGas(evmGasLeft) @@ -624,25 +602,6 @@ object "EVMInterpreter" { } } - // Essentially a NOP that will not get optimized away by the compiler - function $llvm_NoInline_llvm$_unoptimized() { - pop(1) - } - - function printHex(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() - } - - function printString(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() - } - function isSlotWarm(key) -> isWarm { mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) @@ -688,43 +647,6 @@ object "EVMInterpreter" { originalValue := mload(32) } - function MAX_SYSTEM_CONTRACT_ADDR() -> ret { - ret := 0x000000000000000000000000000000000000ffff - } - - /// @dev Checks whether an address is an EOA (i.e. has not code deployed on it) - /// @param addr The address to check - function isEOA(addr) -> ret { - ret := 0 - if gt(addr, MAX_SYSTEM_CONTRACT_ADDR()) { - ret := iszero(_getRawCodeHash(addr)) - } - } - - function incrementNonce(addr) { - mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) - mstore(4, addr) - - let farCallAbi := getFarCallABI( - 0, - 0, - 0, - 36, - gas(), - // Only rollup is supported for now - 0, - 0, - 0, - 1 - ) - let to := NONCE_HOLDER_SYSTEM_CONTRACT() - let result := verbatim_6i_1o("system_call", to, farCallAbi, 0, 0, 0, 0) - - if iszero(result) { - revert(0, 0) - } - } - function getFarCallABI( dataOffset, memoryPage, @@ -1230,38 +1152,6 @@ object "EVMInterpreter" { sp := pushStackItem(sp, success, evmGasLeft) } - function getMessageCallGas ( - _value, - _gas, - _gasLeft, - _memoryCost, - _extraGas - ) -> gasPlusExtra, gasPlusStipend { - let callStipend := 2300 - if iszero(_value) { - callStipend := 0 - } - - switch lt(_gasLeft, add(_extraGas, _memoryCost)) - case 0 - { - let _gasTemp := sub(sub(_gasLeft, _extraGas), _memoryCost) - // From the Tangerine Whistle fork, gas is capped at all but one 64th (remaining_gas / 64) - // of the remaining gas of the current context. If a call tries to send more, the gas is - // changed to match the maximum allowed. - let maxGasToPass := sub(_gasTemp, shr(6, _gasTemp)) // _gas >> 6 == _gas/64 - if gt(_gas, maxGasToPass) { - _gas := maxGasToPass - } - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } - default { - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } - } - function _performStaticCall( _calleeIsEVM, _calleeGas, @@ -3056,10 +2946,6 @@ object "EVMInterpreter" { } object "EVMInterpreter_deployed" { code { - function SYSTEM_CONTRACTS_OFFSET() -> offset { - offset := 0x8000 - } - function ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008002 } @@ -3072,10 +2958,6 @@ object "EVMInterpreter" { addr := 0x0000000000000000000000000000000000008006 } - function CODE_ADDRESS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFFE - } - function CODE_ORACLE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008012 } @@ -3084,12 +2966,8 @@ object "EVMInterpreter" { addr := 0x0000000000000000000000000000000000008013 } - function CALLFLAGS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFEF - } - function DEBUG_SLOT_OFFSET() -> offset { - offset := mul(32, 32) + offset := mul(32, 32) // TODO cleanup } function LAST_RETURNDATA_SIZE_OFFSET() -> offset { @@ -3132,6 +3010,25 @@ object "EVMInterpreter" { max_uint := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff } + // Essentially a NOP that will not get optimized away by the compiler + function $llvm_NoInline_llvm$_unoptimized() { + pop(1) + } + + function printHex(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() + } + + function printString(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() + } + // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { @@ -3269,21 +3166,6 @@ object "EVMInterpreter" { hash := mload(0) } - function _getCodeHash(account) -> hash { - // function getCodeHash(uint256 _input) external view override returns (bytes32) - mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) - mstore(4, account) - - let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) - - if iszero(success) { - // This error should never happen - revert(0, 0) - } - - hash := mload(0) - } - function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") isStatic := iszero(iszero(and(isStatic, 0x04))) @@ -3400,13 +3282,6 @@ object "EVMInterpreter" { } } - function getMin(a, b) -> min { - min := b - if lt(a, b) { - min := a - } - } - function bitLength(n) -> bitLen { for { } gt(n, 0) { } { // while(n > 0) if iszero(n) { @@ -3562,13 +3437,6 @@ object "EVMInterpreter" { } } - function checkMultipleOverflow(data1, data2, data3, evmGasLeft) { - checkOverflow(data1, data2, evmGasLeft) - checkOverflow(data1, data3, evmGasLeft) - checkOverflow(data2, data3, evmGasLeft) - checkOverflow(add(data1, data2), data3, evmGasLeft) - } - function checkOverflow(data1, data2, evmGasLeft) { if lt(add(data1, data2), data2) { revertWithGas(evmGasLeft) @@ -3600,25 +3468,6 @@ object "EVMInterpreter" { } } - // Essentially a NOP that will not get optimized away by the compiler - function $llvm_NoInline_llvm$_unoptimized() { - pop(1) - } - - function printHex(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() - } - - function printString(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() - } - function isSlotWarm(key) -> isWarm { mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) @@ -3664,43 +3513,6 @@ object "EVMInterpreter" { originalValue := mload(32) } - function MAX_SYSTEM_CONTRACT_ADDR() -> ret { - ret := 0x000000000000000000000000000000000000ffff - } - - /// @dev Checks whether an address is an EOA (i.e. has not code deployed on it) - /// @param addr The address to check - function isEOA(addr) -> ret { - ret := 0 - if gt(addr, MAX_SYSTEM_CONTRACT_ADDR()) { - ret := iszero(_getRawCodeHash(addr)) - } - } - - function incrementNonce(addr) { - mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) - mstore(4, addr) - - let farCallAbi := getFarCallABI( - 0, - 0, - 0, - 36, - gas(), - // Only rollup is supported for now - 0, - 0, - 0, - 1 - ) - let to := NONCE_HOLDER_SYSTEM_CONTRACT() - let result := verbatim_6i_1o("system_call", to, farCallAbi, 0, 0, 0, 0) - - if iszero(result) { - revert(0, 0) - } - } - function getFarCallABI( dataOffset, memoryPage, @@ -4206,38 +4018,6 @@ object "EVMInterpreter" { sp := pushStackItem(sp, success, evmGasLeft) } - function getMessageCallGas ( - _value, - _gas, - _gasLeft, - _memoryCost, - _extraGas - ) -> gasPlusExtra, gasPlusStipend { - let callStipend := 2300 - if iszero(_value) { - callStipend := 0 - } - - switch lt(_gasLeft, add(_extraGas, _memoryCost)) - case 0 - { - let _gasTemp := sub(sub(_gasLeft, _extraGas), _memoryCost) - // From the Tangerine Whistle fork, gas is capped at all but one 64th (remaining_gas / 64) - // of the remaining gas of the current context. If a call tries to send more, the gas is - // changed to match the maximum allowed. - let maxGasToPass := sub(_gasTemp, shr(6, _gasTemp)) // _gas >> 6 == _gas/64 - if gt(_gas, maxGasToPass) { - _gas := maxGasToPass - } - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } - default { - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } - } - function _performStaticCall( _calleeIsEVM, _calleeGas, diff --git a/system-contracts/evm-interpreter/EvmInterpreterFunctions.template.yul b/system-contracts/evm-interpreter/EvmInterpreterFunctions.template.yul index f600df165..4d2f6f3aa 100644 --- a/system-contracts/evm-interpreter/EvmInterpreterFunctions.template.yul +++ b/system-contracts/evm-interpreter/EvmInterpreterFunctions.template.yul @@ -1,7 +1,3 @@ -function SYSTEM_CONTRACTS_OFFSET() -> offset { - offset := 0x8000 -} - function ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008002 } @@ -14,10 +10,6 @@ function DEPLOYER_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008006 } -function CODE_ADDRESS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFFE -} - function CODE_ORACLE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008012 } @@ -26,12 +18,8 @@ function EVM_GAS_MANAGER_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008013 } -function CALLFLAGS_CALL_ADDRESS() -> addr { - addr := 0x000000000000000000000000000000000000FFEF -} - function DEBUG_SLOT_OFFSET() -> offset { - offset := mul(32, 32) + offset := mul(32, 32) // TODO cleanup } function LAST_RETURNDATA_SIZE_OFFSET() -> offset { @@ -74,6 +62,25 @@ function MAX_UINT() -> max_uint { max_uint := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff } +// Essentially a NOP that will not get optimized away by the compiler +function $llvm_NoInline_llvm$_unoptimized() { + pop(1) +} + +function printHex(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() +} + +function printString(value) { + mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) + mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) + mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) + $llvm_NoInline_llvm$_unoptimized() +} + // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { if gt(ip, maxAcceptablePos) { @@ -211,21 +218,6 @@ function _getRawCodeHash(account) -> hash { hash := mload(0) } -function _getCodeHash(account) -> hash { - // function getCodeHash(uint256 _input) external view override returns (bytes32) - mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) - mstore(4, account) - - let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) - - if iszero(success) { - // This error should never happen - revert(0, 0) - } - - hash := mload(0) -} - function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") isStatic := iszero(iszero(and(isStatic, 0x04))) @@ -342,13 +334,6 @@ function getMax(a, b) -> max { } } -function getMin(a, b) -> min { - min := b - if lt(a, b) { - min := a - } -} - function bitLength(n) -> bitLen { for { } gt(n, 0) { } { // while(n > 0) if iszero(n) { @@ -504,13 +489,6 @@ function checkMemOverflow(location, evmGasLeft) { } } -function checkMultipleOverflow(data1, data2, data3, evmGasLeft) { - checkOverflow(data1, data2, evmGasLeft) - checkOverflow(data1, data3, evmGasLeft) - checkOverflow(data2, data3, evmGasLeft) - checkOverflow(add(data1, data2), data3, evmGasLeft) -} - function checkOverflow(data1, data2, evmGasLeft) { if lt(add(data1, data2), data2) { revertWithGas(evmGasLeft) @@ -542,25 +520,6 @@ function expandMemory(newSize) -> gasCost { } } -// Essentially a NOP that will not get optimized away by the compiler -function $llvm_NoInline_llvm$_unoptimized() { - pop(1) -} - -function printHex(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebde) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() -} - -function printString(value) { - mstore(add(DEBUG_SLOT_OFFSET(), 0x20), 0x00debdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdebdf) - mstore(add(DEBUG_SLOT_OFFSET(), 0x40), value) - mstore(DEBUG_SLOT_OFFSET(), 0x4A15830341869CAA1E99840C97043A1EA15D2444DA366EFFF5C43B4BEF299681) - $llvm_NoInline_llvm$_unoptimized() -} - function isSlotWarm(key) -> isWarm { mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) @@ -606,43 +565,6 @@ function warmSlot(key,currentValue) -> isWarm, originalValue { originalValue := mload(32) } -function MAX_SYSTEM_CONTRACT_ADDR() -> ret { - ret := 0x000000000000000000000000000000000000ffff -} - -/// @dev Checks whether an address is an EOA (i.e. has not code deployed on it) -/// @param addr The address to check -function isEOA(addr) -> ret { - ret := 0 - if gt(addr, MAX_SYSTEM_CONTRACT_ADDR()) { - ret := iszero(_getRawCodeHash(addr)) - } -} - -function incrementNonce(addr) { - mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) - mstore(4, addr) - - let farCallAbi := getFarCallABI( - 0, - 0, - 0, - 36, - gas(), - // Only rollup is supported for now - 0, - 0, - 0, - 1 - ) - let to := NONCE_HOLDER_SYSTEM_CONTRACT() - let result := verbatim_6i_1o("system_call", to, farCallAbi, 0, 0, 0, 0) - - if iszero(result) { - revert(0, 0) - } -} - function getFarCallABI( dataOffset, memoryPage, @@ -1148,38 +1070,6 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost sp := pushStackItem(sp, success, evmGasLeft) } -function getMessageCallGas ( - _value, - _gas, - _gasLeft, - _memoryCost, - _extraGas -) -> gasPlusExtra, gasPlusStipend { - let callStipend := 2300 - if iszero(_value) { - callStipend := 0 - } - - switch lt(_gasLeft, add(_extraGas, _memoryCost)) - case 0 - { - let _gasTemp := sub(sub(_gasLeft, _extraGas), _memoryCost) - // From the Tangerine Whistle fork, gas is capped at all but one 64th (remaining_gas / 64) - // of the remaining gas of the current context. If a call tries to send more, the gas is - // changed to match the maximum allowed. - let maxGasToPass := sub(_gasTemp, shr(6, _gasTemp)) // _gas >> 6 == _gas/64 - if gt(_gas, maxGasToPass) { - _gas := maxGasToPass - } - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } - default { - gasPlusExtra := add(_gas, _extraGas) - gasPlusStipend := add(_gas, callStipend) - } -} - function _performStaticCall( _calleeIsEVM, _calleeGas, From 4892af86a2385cd1fa06d7c381e7d6c46fb5a500 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 23 Sep 2024 13:18:50 +0200 Subject: [PATCH 2/4] Cleanup in logs --- system-contracts/contracts/EvmInterpreter.yul | 36 +++++++++---------- .../EvmInterpreterLoop.template.yul | 18 +++++----- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.yul b/system-contracts/contracts/EvmInterpreter.yul index a848321a4..b16daad6a 100644 --- a/system-contracts/contracts/EvmInterpreter.yul +++ b/system-contracts/contracts/EvmInterpreter.yul @@ -2722,11 +2722,10 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - let offset, size, topic1 + let offset, size popStackCheck(sp, evmGasLeft, 3) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - topic1, sp := popStackItemWithoutCheck(sp) checkOverflow(offset, size, evmGasLeft) checkMemOverflowByOffset(add(offset, size), evmGasLeft) @@ -2736,7 +2735,11 @@ object "EVMInterpreter" { dynamicGas := add(dynamicGas, 375) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + { + let topic1 + topic1, sp := popStackItemWithoutCheck(sp) + log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + } ip := add(ip, 1) } case 0xA2 { // OP_LOG2 @@ -2746,7 +2749,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 4) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -2760,7 +2763,6 @@ object "EVMInterpreter" { { let topic1, topic2 - popStackCheck(sp, evmGasLeft, 2) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) @@ -2775,7 +2777,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 5) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -2789,7 +2791,6 @@ object "EVMInterpreter" { { let topic1, topic2, topic3 - popStackCheck(sp, evmGasLeft, 3) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) @@ -2805,7 +2806,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 6) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -2819,7 +2820,6 @@ object "EVMInterpreter" { { let topic1, topic2, topic3, topic4 - popStackCheck(sp, evmGasLeft, 4) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) @@ -5588,11 +5588,10 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - let offset, size, topic1 + let offset, size popStackCheck(sp, evmGasLeft, 3) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - topic1, sp := popStackItemWithoutCheck(sp) checkOverflow(offset, size, evmGasLeft) checkMemOverflowByOffset(add(offset, size), evmGasLeft) @@ -5602,7 +5601,11 @@ object "EVMInterpreter" { dynamicGas := add(dynamicGas, 375) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + { + let topic1 + topic1, sp := popStackItemWithoutCheck(sp) + log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + } ip := add(ip, 1) } case 0xA2 { // OP_LOG2 @@ -5612,7 +5615,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 4) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -5626,7 +5629,6 @@ object "EVMInterpreter" { { let topic1, topic2 - popStackCheck(sp, evmGasLeft, 2) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) @@ -5641,7 +5643,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 5) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -5655,7 +5657,6 @@ object "EVMInterpreter" { { let topic1, topic2, topic3 - popStackCheck(sp, evmGasLeft, 3) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) @@ -5671,7 +5672,7 @@ object "EVMInterpreter" { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 6) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -5685,7 +5686,6 @@ object "EVMInterpreter" { { let topic1, topic2, topic3, topic4 - popStackCheck(sp, evmGasLeft, 4) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) diff --git a/system-contracts/evm-interpreter/EvmInterpreterLoop.template.yul b/system-contracts/evm-interpreter/EvmInterpreterLoop.template.yul index eb2cac4ec..ae64735c0 100644 --- a/system-contracts/evm-interpreter/EvmInterpreterLoop.template.yul +++ b/system-contracts/evm-interpreter/EvmInterpreterLoop.template.yul @@ -1272,11 +1272,10 @@ for { } true { } { revertWithGas(evmGasLeft) } - let offset, size, topic1 + let offset, size popStackCheck(sp, evmGasLeft, 3) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - topic1, sp := popStackItemWithoutCheck(sp) checkOverflow(offset, size, evmGasLeft) checkMemOverflowByOffset(add(offset, size), evmGasLeft) @@ -1286,7 +1285,11 @@ for { } true { } { dynamicGas := add(dynamicGas, 375) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + { + let topic1 + topic1, sp := popStackItemWithoutCheck(sp) + log1(add(offset, MEM_OFFSET_INNER()), size, topic1) + } ip := add(ip, 1) } case 0xA2 { // OP_LOG2 @@ -1296,7 +1299,7 @@ for { } true { } { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 4) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -1310,7 +1313,6 @@ for { } true { } { { let topic1, topic2 - popStackCheck(sp, evmGasLeft, 2) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) log2(add(offset, MEM_OFFSET_INNER()), size, topic1, topic2) @@ -1325,7 +1327,7 @@ for { } true { } { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 5) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -1339,7 +1341,6 @@ for { } true { } { { let topic1, topic2, topic3 - popStackCheck(sp, evmGasLeft, 3) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) @@ -1355,7 +1356,7 @@ for { } true { } { } let offset, size - popStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 6) offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) @@ -1369,7 +1370,6 @@ for { } true { } { { let topic1, topic2, topic3, topic4 - popStackCheck(sp, evmGasLeft, 4) topic1, sp := popStackItemWithoutCheck(sp) topic2, sp := popStackItemWithoutCheck(sp) topic3, sp := popStackItemWithoutCheck(sp) From 2f6ea06c2cb6fc053198f36f0c9c3aad23fcc268 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 23 Sep 2024 15:16:16 +0200 Subject: [PATCH 3/4] Remove unneded changes --- system-contracts/contracts/Constants.sol | 4 +-- .../contracts/ContractDeployer.sol | 10 +----- system-contracts/contracts/NonceHolder.sol | 2 -- .../interfaces/IContractDeployer.sol | 2 -- .../contracts/interfaces/IEvmGasManager.sol | 25 ------------- .../libraries/SystemContractHelper.sol | 36 ------------------- .../contracts/libraries/Utils.sol | 2 -- 7 files changed, 3 insertions(+), 78 deletions(-) diff --git a/system-contracts/contracts/Constants.sol b/system-contracts/contracts/Constants.sol index 2bfdcc8bd..dab28bfdc 100644 --- a/system-contracts/contracts/Constants.sol +++ b/system-contracts/contracts/Constants.sol @@ -14,7 +14,7 @@ import {ICompressor} from "./interfaces/ICompressor.sol"; import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; import {IBootloaderUtilities} from "./interfaces/IBootloaderUtilities.sol"; import {IPubdataChunkPublisher} from "./interfaces/IPubdataChunkPublisher.sol"; -import "./EvmGasManager.sol"; +import {IEvmGasManager} from "./interfaces/IEvmGasManager.sol"; /// @dev All the system contracts introduced by ZKsync have their addresses /// started from 2^15 in order to avoid collision with Ethereum precompiles. @@ -85,7 +85,7 @@ address constant EVENT_WRITER_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x0d) ICompressor constant COMPRESSOR_CONTRACT = ICompressor(address(SYSTEM_CONTRACTS_OFFSET + 0x0e)); IComplexUpgrader constant COMPLEX_UPGRADER_CONTRACT = IComplexUpgrader(address(SYSTEM_CONTRACTS_OFFSET + 0x0f)); -EvmGasManager constant EVM_GAS_MANAGER = EvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); +IEvmGasManager constant EVM_GAS_MANAGER = IEvmGasManager(address(SYSTEM_CONTRACTS_OFFSET + 0x13)); IPubdataChunkPublisher constant PUBDATA_CHUNK_PUBLISHER = IPubdataChunkPublisher( address(SYSTEM_CONTRACTS_OFFSET + 0x11) diff --git a/system-contracts/contracts/ContractDeployer.sol b/system-contracts/contracts/ContractDeployer.sol index 848bee0cf..2e1d50f50 100644 --- a/system-contracts/contracts/ContractDeployer.sol +++ b/system-contracts/contracts/ContractDeployer.sol @@ -533,15 +533,7 @@ contract ContractDeployer is IContractDeployer, SystemContractBase { } // In case of EVM contracts returnData is the new deployed code - bool success = SystemContractHelper.mimicCall(uint32(gasleft()), _newAddress, msg.sender, _input, true, false); - - if (!success) { - assembly { - // Just propagate the error back - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) - } - } + EfficientCall.mimicCall(uint32(gasleft()), _newAddress, _input, msg.sender, true, false); bytes32 codeHash = _getEvmCodeHash(_newAddress); require(codeHash != 0x0, "The code hash must be set after the constructor call"); diff --git a/system-contracts/contracts/NonceHolder.sol b/system-contracts/contracts/NonceHolder.sol index 232c3e480..cca07b1b4 100644 --- a/system-contracts/contracts/NonceHolder.sol +++ b/system-contracts/contracts/NonceHolder.sol @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MIT -// solhint-disable reason-string, gas-custom-errors - pragma solidity 0.8.24; import {INonceHolder} from "./interfaces/INonceHolder.sol"; diff --git a/system-contracts/contracts/interfaces/IContractDeployer.sol b/system-contracts/contracts/interfaces/IContractDeployer.sol index 6fe0ae6c1..f42403d3a 100644 --- a/system-contracts/contracts/interfaces/IContractDeployer.sol +++ b/system-contracts/contracts/interfaces/IContractDeployer.sol @@ -40,8 +40,6 @@ interface IContractDeployer { event AccountVersionUpdated(address indexed accountAddress, AccountAbstractionVersion aaVersion); - event EVMProxyHashUpdated(bytes32 indexed oldHash, bytes32 indexed newHash); - function getNewAddressCreate2( address _sender, bytes32 _bytecodeHash, diff --git a/system-contracts/contracts/interfaces/IEvmGasManager.sol b/system-contracts/contracts/interfaces/IEvmGasManager.sol index 27c4e59b4..63c42ff2f 100644 --- a/system-contracts/contracts/interfaces/IEvmGasManager.sol +++ b/system-contracts/contracts/interfaces/IEvmGasManager.sol @@ -2,37 +2,12 @@ pragma solidity ^0.8.20; interface IEvmGasManager { - // We need trust to use `storage` pointers - struct WarmAccountInfo { - bool isWarm; - } - - struct SlotInfo { - bool warm; - uint256 originalValue; - } - - // We dont care about the size, since none of it will be stored/pub;ushed anyway. - struct EVMStackFrameInfo { - bool isStatic; - uint256 passGas; - } - function warmAccount(address account) external payable returns (bool wasWarm); function isSlotWarm(uint256 _slot) external view returns (bool); function warmSlot(uint256 _slot, uint256 _currentValue) external payable returns (bool, uint256); - /* - The flow is the following: - When conducting call: - 1. caller calls to an EVM contract pushEVMFrame with the corresponding gas - 2. callee calls consumeEvmFrame to get the gas & make sure that subsequent callee won't be able to read it. - 3. callee sets the return gas - 4. callee calls popEVMFrame to return the gas to the caller & remove the frame - */ - function pushEVMFrame(uint256 _passGas, bool _isStatic) external; function consumeEvmFrame() external returns (uint256 passGas, bool isStatic); diff --git a/system-contracts/contracts/libraries/SystemContractHelper.sol b/system-contracts/contracts/libraries/SystemContractHelper.sol index 43320c0ab..b5934e96a 100644 --- a/system-contracts/contracts/libraries/SystemContractHelper.sol +++ b/system-contracts/contracts/libraries/SystemContractHelper.sol @@ -359,40 +359,4 @@ library SystemContractHelper { revert FailedToChargeGas(); } } - - function mimicCall( - uint32 gasLimit, - address to, - address whoToMimic, - bytes memory data, - bool isConstructorCall, - bool isSystemCall - ) internal returns (bool success) { - address callAddr = MIMIC_CALL_CALL_ADDRESS; - - uint32 dataStart; - assembly { - dataStart := add(data, 0x20) - } - uint32 dataLength = uint32(Utils.safeCastToU32(data.length)); - - // solhint-disable func-named-parameters - uint256 farCallAbi = SystemContractsCaller.getFarCallABI( - 0, - 0, - dataStart, - dataLength, - gasLimit, - // Only rollup is supported for now - 0, - CalldataForwardingMode.UseHeap, - isConstructorCall, - isSystemCall - ); - - // Doing the system call directly - assembly { - success := call(to, callAddr, 0, farCallAbi, whoToMimic, 0, 0) - } - } } diff --git a/system-contracts/contracts/libraries/Utils.sol b/system-contracts/contracts/libraries/Utils.sol index 07e62476a..6ea897f28 100644 --- a/system-contracts/contracts/libraries/Utils.sol +++ b/system-contracts/contracts/libraries/Utils.sol @@ -2,8 +2,6 @@ // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; -// solhint-disable gas-custom-errors - import {EfficientCall} from "./EfficientCall.sol"; import {RLPEncoder} from "./RLPEncoder.sol"; import {MalformedBytecode, BytecodeError, Overflow} from "../SystemContractErrors.sol"; From 515e46f698cac9645472810e0393c7325fbf356f Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 23 Sep 2024 18:07:29 +0200 Subject: [PATCH 4/4] Use rawMimicCall --- system-contracts/contracts/ContractDeployer.sol | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/system-contracts/contracts/ContractDeployer.sol b/system-contracts/contracts/ContractDeployer.sol index 2e1d50f50..15656eda8 100644 --- a/system-contracts/contracts/ContractDeployer.sol +++ b/system-contracts/contracts/ContractDeployer.sol @@ -532,8 +532,18 @@ contract ContractDeployer is IContractDeployer, SystemContractBase { SystemContractHelper.setValueForNextFarCall(uint128(value)); } - // In case of EVM contracts returnData is the new deployed code - EfficientCall.mimicCall(uint32(gasleft()), _newAddress, _input, msg.sender, true, false); + bool success = EfficientCall.rawMimicCall({ + _gas: uint32(gasleft()), + _address: _newAddress, + _data: _input, + _whoToMimic: msg.sender, + _isConstructor: true, + _isSystem: false + }); + + if (!success) { + EfficientCall.propagateRevert(); + } bytes32 codeHash = _getEvmCodeHash(_newAddress); require(codeHash != 0x0, "The code hash must be set after the constructor call");