From 5a3e3f53264e55a13ef0651e6c2d7499b2970282 Mon Sep 17 00:00:00 2001 From: Javier Chatruc Date: Mon, 5 Aug 2024 14:40:35 -0300 Subject: [PATCH 01/16] Don't charge the regular cost of the call when calling precompiles --- .../EvmInterpreterFunctions.template.yul | 31 ++++++++-- .../contracts/EvmInterpreterPreprocessed.yul | 62 +++++++++++++++---- 2 files changed, 75 insertions(+), 18 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index fcf65915a..bdf2a5453 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -962,8 +962,15 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { } } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } + sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -1086,8 +1093,14 @@ function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -1150,8 +1163,14 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 2780a9625..096a3e2aa 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -1036,8 +1036,15 @@ object "EVMInterpreter" { } } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } + sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -1160,8 +1167,14 @@ object "EVMInterpreter" { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -1224,8 +1237,14 @@ object "EVMInterpreter" { _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } @@ -4031,8 +4050,15 @@ object "EVMInterpreter" { } } - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } + sp := pushStackItem(sp, success, evmGasLeft) } function capGas(evmGasLeft,oldGasToPass) -> gasToPass { @@ -4155,8 +4181,14 @@ object "EVMInterpreter" { isStatic ) - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp,success, evmGasLeft) } @@ -4219,8 +4251,14 @@ object "EVMInterpreter" { _popEVMFrame() - extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) - extraCost := add(extraCost, getGasForPrecompiles(addr, argsOffset, argsSize)) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + switch iszero(precompileCost) + case 1 { + extraCost := add(extraCost,sub(gasToPass,frameGasLeft)) + } + default { + extraCost := add(extraCost, precompileCost) + } sp := pushStackItem(sp, success, evmGasLeft) } From 94967b9a260f7996cde010483c3ed7058b42c056 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:46:36 -0300 Subject: [PATCH 02/16] Fix address code --- .../contracts/EvmInterpreterFunctions.template.yul | 5 +++-- .../contracts/EvmInterpreterPreprocessed.yul | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index fcf65915a..5d7c23efd 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -1345,10 +1345,12 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + let len_32 := shr(5, len) for {let i := 0} lt(i, len_32) { i := add(i, 1) } { mstore(add(dest,shl(5,i)),0) } + let size_32 := shl(5,len_32) let rest_32 := sub(len, size_32) for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { @@ -1356,10 +1358,9 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { } // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 2780a9625..57f7753e1 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -1419,10 +1419,12 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + let len_32 := shr(5, len) for {let i := 0} lt(i, len_32) { i := add(i, 1) } { mstore(add(dest,shl(5,i)),0) } + let size_32 := shl(5,len_32) let rest_32 := sub(len, size_32) for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { @@ -1430,10 +1432,9 @@ object "EVMInterpreter" { } // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { @@ -4414,10 +4415,12 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) + let len_32 := shr(5, len) for {let i := 0} lt(i, len_32) { i := add(i, 1) } { mstore(add(dest,shl(5,i)),0) } + let size_32 := shl(5,len_32) let rest_32 := sub(len, size_32) for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { @@ -4425,10 +4428,9 @@ object "EVMInterpreter" { } // Gets the code from the addr - if iszero(iszero(_getRawCodeHash(addr))) { + if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { pop(_fetchDeployedCodeWithDest(addr, offset, len,add(dest,MEM_OFFSET_INNER()))) } - } function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { From b19c855b6467374e10a36919c73d1b318a584bf0 Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Tue, 13 Aug 2024 14:14:19 +0200 Subject: [PATCH 03/16] Change consecutive mstore8 with immediate with mstore mstore8 call is expensive since it will use 4 instructions to store a single byte (load, and, or, store). Signed-off-by: Vladimir Radosavljevic --- .../contracts/EvmInterpreter.template.yul | 5 +- .../EvmInterpreterFunctions.template.yul | 79 ++------- .../contracts/EvmInterpreterPreprocessed.yul | 163 ++++-------------- 3 files changed, 44 insertions(+), 203 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.template.yul b/system-contracts/contracts/EvmInterpreter.template.yul index 615c5d1c8..f52f13838 100644 --- a/system-contracts/contracts/EvmInterpreter.template.yul +++ b/system-contracts/contracts/EvmInterpreter.template.yul @@ -21,10 +21,7 @@ object "EVMInterpreter" { // This error should never be triggered // require(offset > 100, "Offset too small"); - mstore8(sub(offset, 100), 0xd9) - mstore8(sub(offset, 99), 0xeb) - mstore8(sub(offset, 98), 0x76) - mstore8(sub(offset, 97), 0xb2) + mstore(sub(offset, 100), 0xD9EB76B200000000000000000000000000000000000000000000000000000000) mstore(sub(offset, 96), gasLeft) mstore(sub(offset, 64), 0x40) mstore(sub(offset, 32), len) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 5d7c23efd..2a6e8a447 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -202,11 +202,7 @@ function ptrShrinkIntoActive(_dest) { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -221,12 +217,7 @@ function _getRawCodeHash(account) -> hash { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -310,11 +301,7 @@ function getDeployedBytecode() { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -559,11 +546,7 @@ function printString(value) { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -577,11 +560,7 @@ function isSlotWarm(key) -> isWarm { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -674,10 +653,7 @@ function getNewAddress(addr) -> newAddr { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := call(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 0, 36, 0, 0) @@ -709,11 +685,7 @@ function addGasIfEvmRevert(isCallerEVM,offset,size,evmGasLeft) -> newOffset,newS } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -727,10 +699,7 @@ function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -743,10 +712,7 @@ function getNonce(addr) -> nonce { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -765,10 +731,7 @@ function _isEVM(_addr) -> isEVM { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -783,12 +746,8 @@ function _isEVM(_addr) -> isEVM { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -801,13 +760,8 @@ function _pushEVMFrame(_passGas, _isStatic) { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -1235,12 +1189,7 @@ function isAddrEmpty(addr) -> isEmpty { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -1448,7 +1397,7 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 57f7753e1..0660e69eb 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -21,10 +21,7 @@ object "EVMInterpreter" { // This error should never be triggered // require(offset > 100, "Offset too small"); - mstore8(sub(offset, 100), 0xd9) - mstore8(sub(offset, 99), 0xeb) - mstore8(sub(offset, 98), 0x76) - mstore8(sub(offset, 97), 0xb2) + mstore(sub(offset, 100), 0xD9EB76B200000000000000000000000000000000000000000000000000000000) mstore(sub(offset, 96), gasLeft) mstore(sub(offset, 64), 0x40) mstore(sub(offset, 32), len) @@ -276,11 +273,7 @@ object "EVMInterpreter" { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -295,12 +288,7 @@ object "EVMInterpreter" { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -384,11 +372,7 @@ object "EVMInterpreter" { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -633,11 +617,7 @@ object "EVMInterpreter" { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -651,11 +631,7 @@ object "EVMInterpreter" { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -748,10 +724,7 @@ object "EVMInterpreter" { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := call(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 0, 36, 0, 0) @@ -783,11 +756,7 @@ object "EVMInterpreter" { } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -801,10 +770,7 @@ object "EVMInterpreter" { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -817,10 +783,7 @@ object "EVMInterpreter" { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -839,10 +802,7 @@ object "EVMInterpreter" { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -857,12 +817,8 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -875,13 +831,8 @@ object "EVMInterpreter" { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -1309,12 +1260,7 @@ object "EVMInterpreter" { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -1522,7 +1468,7 @@ object "EVMInterpreter" { { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) @@ -3272,11 +3218,7 @@ object "EVMInterpreter" { } function _getRawCodeHash(account) -> hash { - // TODO: Unhardcode this selector - mstore8(0, 0x4d) - mstore8(1, 0xe2) - mstore8(2, 0xe4) - mstore8(3, 0x68) + mstore(0, 0x4DE2E46800000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3291,12 +3233,7 @@ object "EVMInterpreter" { function _getCodeHash(account) -> hash { // function getCodeHash(uint256 _input) external view override returns (bytes32) - // 0xe03fe177 - // TODO: Unhardcode this selector - mstore8(0, 0xe0) - mstore8(1, 0x3f) - mstore8(2, 0xe1) - mstore8(3, 0x77) + mstore(0, 0xE03FE17700000000000000000000000000000000000000000000000000000000) mstore(4, account) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3380,11 +3317,7 @@ object "EVMInterpreter" { function consumeEvmFrame() -> passGas, isStatic, callerEVM { // function consumeEvmFrame() external returns (uint256 passGas, bool isStatic) - // TODO: Unhardcode selector - mstore8(0, 0x04) - mstore8(1, 0xc1) - mstore8(2, 0x4e) - mstore8(3, 0x9e) + mstore(0, 0x04C14E9E00000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 64) @@ -3629,11 +3562,7 @@ object "EVMInterpreter" { } function isSlotWarm(key) -> isWarm { - // TODO: Unhardcode this selector 0x482d2e74 - mstore8(0, 0x48) - mstore8(1, 0x2d) - mstore8(2, 0x2e) - mstore8(3, 0x74) + mstore(0, 0x482D2E7400000000000000000000000000000000000000000000000000000000) mstore(4, key) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -3647,11 +3576,7 @@ object "EVMInterpreter" { } function warmSlot(key,currentValue) -> isWarm, originalValue { - // TODO: Unhardcode this selector 0xbdf78160 - mstore8(0, 0xbd) - mstore8(1, 0xf7) - mstore8(2, 0x81) - mstore8(3, 0x60) + mstore(0, 0xBDF7816000000000000000000000000000000000000000000000000000000000) mstore(4, key) mstore(36,currentValue) @@ -3744,10 +3669,7 @@ object "EVMInterpreter" { } function incrementNonce(addr) { - mstore8(0, 0x30) - mstore8(1, 0x63) - mstore8(2, 0x95) - mstore8(3, 0xc6) + mstore(0, 0x306395C600000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := call(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 0, 36, 0, 0) @@ -3779,11 +3701,7 @@ object "EVMInterpreter" { } function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm { - // TODO: Unhardcode this selector 0x8db2ba78 - mstore8(0, 0x8d) - mstore8(1, 0xb2) - mstore8(2, 0xba) - mstore8(3, 0x78) + mstore(0, 0x8DB2BA7800000000000000000000000000000000000000000000000000000000) mstore(4, addr) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 36, 0, 32) @@ -3797,10 +3715,7 @@ object "EVMInterpreter" { } function getNonce(addr) -> nonce { - mstore8(0, 0xfb) - mstore8(1, 0x1a) - mstore8(2, 0x9a) - mstore8(3, 0x57) + mstore(0, 0xFB1A9A5700000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3813,10 +3728,7 @@ object "EVMInterpreter" { } function getRawNonce(addr) -> nonce { - mstore8(0, 0x5a) - mstore8(1, 0xa9) - mstore8(2, 0xb6) - mstore8(3, 0xb5) + mstore(0, 0x5AA9B6B500000000000000000000000000000000000000000000000000000000) mstore(4, addr) let result := staticcall(gas(), NONCE_HOLDER_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3835,10 +3747,7 @@ object "EVMInterpreter" { // address(SYSTEM_CONTRACTS_OFFSET + 0x02) // ); - mstore8(0, 0x8c) - mstore8(1, 0x04) - mstore8(2, 0x04) - mstore8(3, 0x77) + mstore(0, 0x8C04047700000000000000000000000000000000000000000000000000000000) mstore(4, _addr) let success := staticcall(gas(), ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT(), 0, 36, 0, 32) @@ -3853,12 +3762,8 @@ object "EVMInterpreter" { function _pushEVMFrame(_passGas, _isStatic) { // function pushEVMFrame(uint256 _passGas, bool _isStatic) external - let selector := 0xead77156 - mstore8(0, 0xea) - mstore8(1, 0xd7) - mstore8(2, 0x71) - mstore8(3, 0x56) + mstore(0, 0xEAD7715600000000000000000000000000000000000000000000000000000000) mstore(4, _passGas) mstore(36, _isStatic) @@ -3871,13 +3776,8 @@ object "EVMInterpreter" { function _popEVMFrame() { // function popEVMFrame() external - // 0xe467d2f0 - let selector := 0xe467d2f0 - mstore8(0, 0xe4) - mstore8(1, 0x67) - mstore8(2, 0xd2) - mstore8(3, 0xf0) + mstore(0, 0xE467D2F000000000000000000000000000000000000000000000000000000000) let success := call(gas(), EVM_GAS_MANAGER_CONTRACT(), 0, 0, 4, 0, 0) if iszero(success) { @@ -4305,12 +4205,7 @@ object "EVMInterpreter" { } function _fetchConstructorReturnGas() -> gasLeft { - //selector is 0x24e5ab4a - - mstore8(0, 0x24) - mstore8(1, 0xe5) - mstore8(2, 0xab) - mstore8(3, 0x4a) + mstore(0, 0x24E5AB4A00000000000000000000000000000000000000000000000000000000) let success := staticcall(gas(), DEPLOYER_SYSTEM_CONTRACT(), 0, 4, 0, 32) @@ -4518,7 +4413,7 @@ object "EVMInterpreter" { { let hashedBytecode := keccak256(add(MEM_OFFSET_INNER(), offset), size) - mstore8(0, 0xFF) + mstore(0, 0xFF00000000000000000000000000000000000000000000000000000000000000) mstore(0x01, shl(0x60, address())) mstore(0x15, salt) mstore(0x35, hashedBytecode) From 413d63706c41c31f3308b5120f17c3a51c30d278 Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Tue, 13 Aug 2024 14:16:02 +0200 Subject: [PATCH 04/16] Implement memset to zero Implement memset to zero function and call it in performExtCodeCopy and OP_CALLDATACOPY. Main loop of this implementation is done in 3 instructions (store with increment, compare and conditional jump) compared to the old implementation that was done 6 instructions. For processing rest bytes, calls to mstore8 are removed and changed to do in a single store. Signed-off-by: Vladimir Radosavljevic --- .../EvmInterpreterFunctions.template.yul | 27 +++++--- .../contracts/EvmInterpreterLoop.template.yul | 7 +- .../contracts/EvmInterpreterPreprocessed.yul | 68 +++++++++---------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 2a6e8a447..d95224aef 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -1272,6 +1272,21 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa mstore(sub(offset, 0x80), back) } +function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + let rest_bits := shl(3, rest_len) + let mask := shr(rest_bits, MAX_UINT()) + let value := mload(dest_end) + mstore(dest_end, and(value, mask)) + } +} + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -1294,17 +1309,7 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 931ede4c5..b08467f4c 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -414,12 +414,7 @@ for { } true { } { checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 0660e69eb..199ac759f 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -1343,6 +1343,21 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + let rest_bits := shl(3, rest_len) + let mask := shr(rest_bits, MAX_UINT()) + let value := mload(dest_end) + mstore(dest_end, and(value, mask)) + } + } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -1365,17 +1380,7 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { @@ -1908,12 +1913,7 @@ object "EVMInterpreter" { checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost @@ -4288,6 +4288,21 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { + let dest_end := add(dest, and(len, sub(0, 32))) + for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { + mstore(i, 0) + } + + let rest_len := and(len, 31) + if rest_len { + let rest_bits := shl(3, rest_len) + let mask := shr(rest_bits, MAX_UINT()) + let value := mload(dest_end) + mstore(dest_end, and(value, mask)) + } + } + function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp { evmGasLeft := chargeGas(evmGas, 100) @@ -4310,17 +4325,7 @@ object "EVMInterpreter" { } evmGasLeft := chargeGas(evmGasLeft, dynamicGas) - - let len_32 := shr(5, len) - for {let i := 0} lt(i, len_32) { i := add(i, 1) } { - mstore(add(dest,shl(5,i)),0) - } - - let size_32 := shl(5,len_32) - let rest_32 := sub(len, size_32) - for {let i := 0} lt(i, rest_32) { i := add(i, 1) } { - mstore8(add(dest,add(size_32,i)),0) - } + $llvm_AlwaysInline_llvm$_memsetToZero(dest, len) // Gets the code from the addr if and(iszero(iszero(_getRawCodeHash(addr))),gt(len,0)) { @@ -4853,12 +4858,7 @@ object "EVMInterpreter" { checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset, MEM_OFFSET_INNER()), i), - 0 - ) - } + $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } // dynamicGas = 3 * minimum_word_size + memory_expansion_cost From 40d84fdc172e0b9e96f0d7c01741644f4400c082 Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Tue, 13 Aug 2024 14:20:31 +0200 Subject: [PATCH 05/16] Implement memcpy function Instead of using loop to store bytes for OP_CODECOPY, call optimized memcpy function. Signed-off-by: Vladimir Radosavljevic --- .../EvmInterpreterFunctions.template.yul | 32 +++++++- .../contracts/EvmInterpreterLoop.template.yul | 7 +- .../contracts/EvmInterpreterPreprocessed.yul | 78 ++++++++++++++----- 3 files changed, 87 insertions(+), 30 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index d95224aef..57f7c9375 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -1272,6 +1272,33 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa mstore(sub(offset, 0x80), back) } +function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) +} + +function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } +} + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { let dest_end := add(dest, and(len, sub(0, 32))) for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { @@ -1280,10 +1307,7 @@ function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { let rest_len := and(len, 31) if rest_len { - let rest_bits := shl(3, rest_len) - let mask := shr(rest_bits, MAX_UINT()) - let value := mload(dest_end) - mstore(dest_end, and(value, mask)) + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) } } diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index b08467f4c..5e833117f 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -459,12 +459,7 @@ for { } true { } { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 199ac759f..591cb3cdd 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -1343,6 +1343,33 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) + } + + function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } + } + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { let dest_end := add(dest, and(len, sub(0, 32))) for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { @@ -1351,10 +1378,7 @@ object "EVMInterpreter" { let rest_len := and(len, 31) if rest_len { - let rest_bits := shl(3, rest_len) - let mask := shr(rest_bits, MAX_UINT()) - let value := mload(dest_end) - mstore(dest_end, and(value, mask)) + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) } } @@ -1958,12 +1982,7 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE @@ -4288,6 +4307,33 @@ object "EVMInterpreter" { mstore(sub(offset, 0x80), back) } + function $llvm_AlwaysInline_llvm$_copyRest(dest, val, len) { + let rest_bits := shl(3, len) + let upper_bits := sub(256, rest_bits) + let val_mask := shl(upper_bits, MAX_UINT()) + let val_masked := and(val, val_mask) + let dst_val := mload(dest) + let dst_mask := shr(rest_bits, MAX_UINT()) + let dst_masked := and(dst_val, dst_mask) + mstore(dest, or(val_masked, dst_masked)) + } + + function $llvm_AlwaysInline_llvm$_memcpy(dest, src, len) { + let dest_addr := dest + let src_addr := src + let dest_end := add(dest, and(len, sub(0, 32))) + for { } lt(dest_addr, dest_end) {} { + mstore(dest_addr, mload(src_addr)) + dest_addr := add(dest_addr, 32) + src_addr := add(src_addr, 32) + } + + let rest_len := and(len, 31) + if rest_len { + $llvm_AlwaysInline_llvm$_copyRest(dest_addr, mload(src_addr), rest_len) + } + } + function $llvm_AlwaysInline_llvm$_memsetToZero(dest,len) { let dest_end := add(dest, and(len, sub(0, 32))) for {let i := dest} lt(i, dest_end) { i := add(i, 32) } { @@ -4296,10 +4342,7 @@ object "EVMInterpreter" { let rest_len := and(len, 31) if rest_len { - let rest_bits := shl(3, rest_len) - let mask := shr(rest_bits, MAX_UINT()) - let value := mload(dest_end) - mstore(dest_end, and(value, mask)) + $llvm_AlwaysInline_llvm$_copyRest(dest_end, 0, rest_len) } } @@ -4903,12 +4946,7 @@ object "EVMInterpreter" { revertWithGas(evmGasLeft) } - for { let i := 0 } lt(i, len) { i := add(i, 1) } { - mstore8( - add(dst, i), - shr(248, mload(add(offset, i))) - ) - } + $llvm_AlwaysInline_llvm$_memcpy(dst, offset, len) ip := add(ip, 1) } case 0x3A { // OP_GASPRICE From e4175ac08df91d69d9038f6b4f98ba81d6dda38d Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Thu, 15 Aug 2024 15:43:07 +0200 Subject: [PATCH 06/16] Remove calls to mstore8 in OP_MCOPY and fix checks Instead, call mcopy that is is essentially optimized implementation of memmove. Add checks for memory overflow. This patch is a joint work by: Gianbelinche Vladimir Radosavljevic Signed-off-by: Vladimir Radosavljevic --- .../contracts/EvmInterpreterLoop.template.yul | 21 ++-------- .../contracts/EvmInterpreterPreprocessed.yul | 42 ++++--------------- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 5e833117f..fe800f5f1 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -814,26 +814,13 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 591cb3cdd..70492f182 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -2337,26 +2337,13 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 @@ -5301,26 +5288,13 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) - let oldSize := mul(mload(MEM_OFFSET()),32) - if gt(add(oldSize,size),MAX_POSSIBLE_MEM()) { - revertWithGas(evmGasLeft) - } - - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(oldSize,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(offset,MEM_OFFSET_INNER()), i))) - ) - } - for { let i := 0 } lt(i, size) { i := add(i, 1) } { - mstore8( - add(add(destOffset,MEM_OFFSET_INNER()), i), - shr(248,mload(add(add(oldSize,MEM_OFFSET_INNER()), i))) - ) - } + mcopy(add(destOffset, MEM_OFFSET_INNER()), add(offset, MEM_OFFSET_INNER()), size) ip := add(ip, 1) } case 0x5F { // OP_PUSH0 From 1b2b0f9fb527817600432cd950ef180fcdb7294b Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 15 Aug 2024 19:51:36 +0200 Subject: [PATCH 07/16] Check offset overflow earlier in memory opcodes --- .../contracts/EvmInterpreterLoop.template.yul | 6 +++--- .../contracts/EvmInterpreterPreprocessed.yul | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 931ede4c5..5448f156a 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -619,11 +619,11 @@ for { } true { } { offset, sp := popStackItem(sp, evmGasLeft) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) sp := pushStackItem(sp, memValue, evmGasLeft) ip := add(ip, 1) @@ -637,11 +637,11 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -654,11 +654,11 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 57f7753e1..eedb9665c 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -2167,11 +2167,11 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) sp := pushStackItem(sp, memValue, evmGasLeft) ip := add(ip, 1) @@ -2185,11 +2185,11 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -2202,11 +2202,11 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -5163,11 +5163,11 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) sp := pushStackItem(sp, memValue, evmGasLeft) ip := add(ip, 1) @@ -5181,11 +5181,11 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } @@ -5198,11 +5198,11 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) + checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) - checkOverflow(offset,MEM_OFFSET_INNER(), evmGasLeft) mstore8(add(MEM_OFFSET_INNER(), offset), value) ip := add(ip, 1) } From d272a7ec43f9fa0247e607d8055c928380845c7d Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 19 Aug 2024 11:05:51 +0200 Subject: [PATCH 08/16] Remove pop push check --- .../EvmInterpreterFunctions.template.yul | 9 -- .../contracts/EvmInterpreterLoop.template.yul | 54 ++++---- .../contracts/EvmInterpreterPreprocessed.yul | 126 ++++++++---------- 3 files changed, 81 insertions(+), 108 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 5d7c23efd..c886a163b 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -164,15 +164,6 @@ function popStackCheck(sp, evmGasLeft, numInputs) { } } -function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { - revertWithGas(evmGasLeft) - } -} - function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 5448f156a..92998f339 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -19,7 +19,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -31,7 +31,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -43,7 +43,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -55,7 +55,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -67,7 +67,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -79,7 +79,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -91,7 +91,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -103,7 +103,7 @@ for { } true { } { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -129,7 +129,7 @@ for { } true { } { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -148,7 +148,7 @@ for { } true { } { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -160,7 +160,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -172,7 +172,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -184,7 +184,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -196,7 +196,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -208,7 +208,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -220,7 +220,7 @@ for { } true { } { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -231,7 +231,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -243,7 +243,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -255,7 +255,7 @@ for { } true { } { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -267,7 +267,7 @@ for { } true { } { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -278,7 +278,7 @@ for { } true { } { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -290,7 +290,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -302,7 +302,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -314,7 +314,7 @@ for { } true { } { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -388,7 +388,7 @@ for { } true { } { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -558,7 +558,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -796,7 +796,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index eedb9665c..2bfc57041 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -238,15 +238,6 @@ object "EVMInterpreter" { } } - function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { - revertWithGas(evmGasLeft) - } - } - function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } @@ -1567,7 +1558,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1579,7 +1570,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1591,7 +1582,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1603,7 +1594,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1615,7 +1606,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1627,7 +1618,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1639,7 +1630,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1651,7 +1642,7 @@ object "EVMInterpreter" { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -1677,7 +1668,7 @@ object "EVMInterpreter" { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -1696,7 +1687,7 @@ object "EVMInterpreter" { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -1708,7 +1699,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1720,7 +1711,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1732,7 +1723,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1744,7 +1735,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1756,7 +1747,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1768,7 +1759,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -1779,7 +1770,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1791,7 +1782,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1803,7 +1794,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -1815,7 +1806,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -1826,7 +1817,7 @@ object "EVMInterpreter" { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -1838,7 +1829,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1850,7 +1841,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1862,7 +1853,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -1936,7 +1927,7 @@ object "EVMInterpreter" { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -2106,7 +2097,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -2344,7 +2335,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) @@ -3234,15 +3225,6 @@ object "EVMInterpreter" { } } - function popPushStackCheck(sp, evmGasLeft, numInputs) { - let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) - let pushOffset := sub(sp, mul(0x20, numInputs)) - let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET())) - if or(popCheck, pushCheck) { - revertWithGas(evmGasLeft) - } - } - function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } @@ -4563,7 +4545,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4575,7 +4557,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4587,7 +4569,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4599,7 +4581,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4611,7 +4593,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4623,7 +4605,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4635,7 +4617,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4647,7 +4629,7 @@ object "EVMInterpreter" { let a, b, N - popPushStackCheck(sp, evmGasLeft, 3) + popStackCheck(sp, evmGasLeft, 3) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) N, sp := popStackItemWithoutCheck(sp) @@ -4673,7 +4655,7 @@ object "EVMInterpreter" { let a, exponent - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) exponent, sp := popStackItemWithoutCheck(sp) @@ -4692,7 +4674,7 @@ object "EVMInterpreter" { let b, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) b, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -4704,7 +4686,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4716,7 +4698,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4728,7 +4710,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4740,7 +4722,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4752,7 +4734,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4764,7 +4746,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, iszero(a)) @@ -4775,7 +4757,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4787,7 +4769,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4799,7 +4781,7 @@ object "EVMInterpreter" { let a, b - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) a, sp := popStackItemWithoutCheck(sp) b, sp := popStackItemWithoutCheck(sp) @@ -4811,7 +4793,7 @@ object "EVMInterpreter" { let a - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) a, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, not(a)) @@ -4822,7 +4804,7 @@ object "EVMInterpreter" { let i, x - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) i, sp := popStackItemWithoutCheck(sp) x, sp := popStackItemWithoutCheck(sp) @@ -4834,7 +4816,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4846,7 +4828,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4858,7 +4840,7 @@ object "EVMInterpreter" { let shift, value - popPushStackCheck(sp, evmGasLeft, 2) + popStackCheck(sp, evmGasLeft, 2) shift, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) @@ -4932,7 +4914,7 @@ object "EVMInterpreter" { let i - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) i, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, calldataload(i)) @@ -5102,7 +5084,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 20) let blockNumber - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) blockNumber, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, blockhash(blockNumber)) @@ -5340,7 +5322,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 100) let key - popPushStackCheck(sp, evmGasLeft, 1) + popStackCheck(sp, evmGasLeft, 1) key, sp := popStackItemWithoutCheck(sp) sp := pushStackItemWithoutCheck(sp, tload(key)) From 3d766a2fa369c7be0bb49665f0bc8bc0ee7931a7 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 19 Aug 2024 11:36:22 +0200 Subject: [PATCH 09/16] Use unchecked push in safe cases --- .../contracts/EvmInterpreterLoop.template.yul | 14 +++++----- .../contracts/EvmInterpreterPreprocessed.yul | 28 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 92998f339..8b8342aaa 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -362,7 +362,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -495,8 +495,8 @@ for { } true { } { // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -549,10 +549,10 @@ for { } true { } { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) @@ -625,7 +625,7 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, expansionGas) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -682,7 +682,7 @@ for { } true { } { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 2bfc57041..d1dff19bb 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -1901,7 +1901,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -2034,8 +2034,8 @@ object "EVMInterpreter" { // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -2088,10 +2088,10 @@ object "EVMInterpreter" { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) @@ -2164,7 +2164,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, expansionGas) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -2221,7 +2221,7 @@ object "EVMInterpreter" { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE @@ -4888,7 +4888,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - sp := pushStackItem(sp, balance(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, balance(addr)) ip := add(ip, 1) } case 0x32 { // OP_ORIGIN @@ -5021,8 +5021,8 @@ object "EVMInterpreter" { // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) switch _isEVM(addr) - case 0 { sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) } - default { sp := pushStackItem(sp, _fetchDeployedCodeLen(addr), evmGasLeft) } + case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } + default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } ip := add(ip, 1) } case 0x3C { // OP_EXTCODECOPY @@ -5075,10 +5075,10 @@ object "EVMInterpreter" { ip := add(ip, 1) if iszero(addr) { - sp := pushStackItem(sp, 0, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, 0) continue } - sp := pushStackItem(sp, extcodehash(addr), evmGasLeft) + sp := pushStackItemWithoutCheck(sp, extcodehash(addr)) } case 0x40 { // OP_BLOCKHASH evmGasLeft := chargeGas(evmGasLeft, 20) @@ -5151,7 +5151,7 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, expansionGas) let memValue := mload(add(MEM_OFFSET_INNER(), offset)) - sp := pushStackItem(sp, memValue, evmGasLeft) + sp := pushStackItemWithoutCheck(sp, memValue) ip := add(ip, 1) } case 0x52 { // OP_MSTORE @@ -5208,7 +5208,7 @@ object "EVMInterpreter" { let _wasW, _orgV := warmSlot(key, value) } - sp := pushStackItem(sp,value, evmGasLeft) + sp := pushStackItemWithoutCheck(sp,value) ip := add(ip, 1) } case 0x55 { // OP_SSTORE From 6691c881c3e7ed00e19f35b4d880d9aa631e28b7 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Mon, 19 Aug 2024 17:14:37 +0200 Subject: [PATCH 10/16] Execute JUMPDEST immediately after JUMP/JUMPI --- .../contracts/EvmInterpreterLoop.template.yul | 8 ++++++++ .../contracts/EvmInterpreterPreprocessed.yul | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 5448f156a..4d6aecaaa 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -742,6 +742,10 @@ for { } true { } { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -764,6 +768,10 @@ for { } true { } { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index eedb9665c..f133d38a6 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -2290,6 +2290,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -2312,6 +2316,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) @@ -5286,6 +5294,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x57 { // OP_JUMPI evmGasLeft := chargeGas(evmGasLeft, 10) @@ -5308,6 +5320,10 @@ object "EVMInterpreter" { if iszero(eq(nextOpcode, 0x5B)) { revertWithGas(evmGasLeft) } + + // execute JUMPDEST immediately + evmGasLeft := chargeGas(evmGasLeft, 1) + ip := add(ip, 1) } case 0x58 { // OP_PC evmGasLeft := chargeGas(evmGasLeft, 2) From 77eb85460136716ef078075ca1881abf9e2a3c00 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:34:35 -0300 Subject: [PATCH 11/16] Remove TODOs --- .../contracts/EvmInterpreter.template.yul | 2 - .../EvmInterpreterFunctions.template.yul | 14 ------ .../contracts/EvmInterpreterLoop.template.yul | 8 ---- .../contracts/EvmInterpreterPreprocessed.yul | 46 ------------------- 4 files changed, 70 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreter.template.yul b/system-contracts/contracts/EvmInterpreter.template.yul index f52f13838..32ca6ed92 100644 --- a/system-contracts/contracts/EvmInterpreter.template.yul +++ b/system-contracts/contracts/EvmInterpreter.template.yul @@ -57,8 +57,6 @@ object "EVMInterpreter" { function validateCorrectBytecode(offset, len, gasToReturn) -> returnGas { if len { - // let firstByte := shr(mload(offset), 248) - // FIXME: Check this. let firstByte := shr(248, mload(offset)) if eq(firstByte, 0xEF) { revert(0, 0) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 26661ec03..663b56402 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -76,7 +76,6 @@ function MAX_UINT() -> max_uint { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -223,7 +222,6 @@ function _getCodeHash(account) -> hash { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -762,7 +760,6 @@ function _popEVMFrame() { } // 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 } @@ -884,8 +881,6 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { let success if _isEVM(addr) { _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -1086,13 +1081,6 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -1162,8 +1150,6 @@ function _performStaticCall( ) -> 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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 8645147c4..8e007867f 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -479,11 +479,6 @@ for { } true { } { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } @@ -509,9 +504,6 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 5a11bec7a..51ac4ee36 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -57,8 +57,6 @@ object "EVMInterpreter" { function validateCorrectBytecode(offset, len, gasToReturn) -> returnGas { if len { - // let firstByte := shr(mload(offset), 248) - // FIXME: Check this. let firstByte := shr(248, mload(offset)) if eq(firstByte, 0xEF) { revert(0, 0) @@ -147,7 +145,6 @@ object "EVMInterpreter" { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -294,7 +291,6 @@ object "EVMInterpreter" { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -833,7 +829,6 @@ 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 } @@ -955,8 +950,6 @@ object "EVMInterpreter" { let success if _isEVM(addr) { _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -1157,13 +1150,6 @@ object "EVMInterpreter" { } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -1233,8 +1219,6 @@ object "EVMInterpreter" { ) -> 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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) @@ -2012,11 +1996,6 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } @@ -2042,9 +2021,6 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) @@ -3116,7 +3092,6 @@ object "EVMInterpreter" { // It is the responsibility of the caller to ensure that ip >= BYTECODE_OFFSET + 32 function readIP(ip,maxAcceptablePos) -> opcode { - // TODO: Why not do this at the beginning once instead of every time? if gt(ip, maxAcceptablePos) { revert(0, 0) } @@ -3263,7 +3238,6 @@ object "EVMInterpreter" { function getIsStaticFromCallFlags() -> isStatic { isStatic := verbatim_0i_1o("get_global::call_flags") - // TODO: make it a constnat isStatic := iszero(iszero(and(isStatic, 0x04))) } @@ -3802,7 +3776,6 @@ 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 } @@ -3924,8 +3897,6 @@ object "EVMInterpreter" { let success if _isEVM(addr) { _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -4126,13 +4097,6 @@ object "EVMInterpreter" { } gasToPass := capGas(evmGasLeft,gasToPass) - // TODO: Do this - // if warmAccount(addr) { - // extraCost = GAS_WARM_ACCESS; - // } else { - // extraCost = GAS_COLD_ACCOUNT_ACCESS; - // } - _pushEVMFrame(gasToPass, isStatic) let success := delegatecall( // We can not just pass all gas here to prevert overflow of zkEVM gas counter @@ -4202,8 +4166,6 @@ object "EVMInterpreter" { ) -> 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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) @@ -4981,11 +4943,6 @@ object "EVMInterpreter" { evmGasLeft := chargeGas(evmGasLeft, 2500) } - // TODO: check, the .sol uses extcodesize directly, but it doesnt seem to work - // if a contract is created it works, but if the address is a zkSync's contract - // what happens? - // sp := pushStackItem(sp, extcodesize(addr), evmGasLeft) - switch _isEVM(addr) case 0 { sp := pushStackItemWithoutCheck(sp, extcodesize(addr)) } default { sp := pushStackItemWithoutCheck(sp, _fetchDeployedCodeLen(addr)) } @@ -5011,9 +4968,6 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) len, sp := popStackItemWithoutCheck(sp) - // TODO: check if these conditions are met - // The addition offset + size overflows. - // offset + size is larger than RETURNDATASIZE. checkOverflow(offset,len, evmGasLeft) if gt(add(offset, len), mload(LAST_RETURNDATA_SIZE_OFFSET())) { revertWithGas(evmGasLeft) From 7356c2c8050b4e30dc0eb32c4858d77ea5a0f3cb Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 21 Aug 2024 15:50:36 +0200 Subject: [PATCH 12/16] Use switch/case in calls --- .../EvmInterpreterFunctions.template.yul | 95 +++--- .../contracts/EvmInterpreterPreprocessed.yul | 292 +++++++++--------- 2 files changed, 201 insertions(+), 186 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 26661ec03..284b20c5d 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -882,18 +882,9 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -906,6 +897,15 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) switch iszero(precompileCost) @@ -940,7 +940,31 @@ function getMaxExpansionMemory(retOffset,retSize,argsOffset,argsSize) -> maxExpa function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -954,27 +978,6 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -1160,18 +1163,9 @@ function _performStaticCall( _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -1185,6 +1179,15 @@ function _performStaticCall( _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 5a11bec7a..eac6bb5e3 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -662,32 +662,35 @@ object "EVMInterpreter" { nonceEncoded := nonce nonceEncodedLength := 1 - if iszero(nonce) { + switch nonce + case 0 { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 - } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 4 bytes + if gt(nonce, 0xFFFFFF) { + nonceEncoded := shl(32, 0x84) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 5 + } + // The nonce has 3 bytes + if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { + nonceEncoded := shl(24, 0x83) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 4 + } + // The nonce has 2 bytes + if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -953,18 +956,9 @@ object "EVMInterpreter" { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -977,6 +971,15 @@ object "EVMInterpreter" { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) switch iszero(precompileCost) @@ -1011,7 +1014,31 @@ object "EVMInterpreter" { function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -1025,27 +1052,6 @@ object "EVMInterpreter" { retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -1231,18 +1237,9 @@ object "EVMInterpreter" { _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -1256,6 +1253,15 @@ object "EVMInterpreter" { _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { @@ -3631,32 +3637,35 @@ object "EVMInterpreter" { nonceEncoded := nonce nonceEncodedLength := 1 - if iszero(nonce) { + switch nonce + case 0 { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 - } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 4 bytes + if gt(nonce, 0xFFFFFF) { + nonceEncoded := shl(32, 0x84) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 5 + } + // The nonce has 3 bytes + if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { + nonceEncoded := shl(24, 0x83) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 4 + } + // The nonce has 2 bytes + if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -3922,18 +3931,9 @@ object "EVMInterpreter" { let frameGasLeft let success - if _isEVM(addr) { - _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) - - frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) - _popEVMFrame() - } - - // zkEVM native - if iszero(_isEVM(addr)) { + switch _isEVM(addr) + case 0 { + // zkEVM native gasToPass := _getZkEVMGas(gasToPass, addr) let zkevmGasBefore := gas() success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize) @@ -3946,6 +3946,15 @@ object "EVMInterpreter" { frameGasLeft := sub(gasToPass, gasUsed) } } + default { + _pushEVMFrame(gasToPass, 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(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, 0, 0) + + frameGasLeft := _saveReturndataAfterEVMCall(add(MEM_OFFSET_INNER(), retOffset), retSize) + _popEVMFrame() + } let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) switch iszero(precompileCost) @@ -3980,7 +3989,31 @@ object "EVMInterpreter" { function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize,isStatic) -> success, frameGasLeft, gasToPassNew{ gasToPassNew := gasToPass let is_evm := _isEVM(addr) - if isStatic { + + switch isStatic + case 0 { + switch is_evm + case 0 { + // zkEVM native + gasToPassNew := _getZkEVMGas(gasToPassNew, addr) + let zkevmGasBefore := gas() + success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) + _saveReturndataAfterZkEVMCall() + let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) + + frameGasLeft := 0 + if gt(gasToPassNew, gasUsed) { + frameGasLeft := sub(gasToPassNew, gasUsed) + } + } + default { + _pushEVMFrame(gasToPassNew, isStatic) + success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + _popEVMFrame() + } + } + default { if value { revertWithGas(gasToPassNew) } @@ -3994,27 +4027,6 @@ object "EVMInterpreter" { retSize ) } - - if and(is_evm, iszero(isStatic)) { - _pushEVMFrame(gasToPassNew, isStatic) - success := call(EVM_GAS_STIPEND(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - _popEVMFrame() - } - - // zkEVM native - if and(iszero(is_evm), iszero(isStatic)) { - gasToPassNew := _getZkEVMGas(gasToPassNew, addr) - let zkevmGasBefore := gas() - success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize) - _saveReturndataAfterZkEVMCall() - let gasUsed := _calcEVMGas(sub(zkevmGasBefore, gas())) - - frameGasLeft := 0 - if gt(gasToPassNew, gasUsed) { - frameGasLeft := sub(gasToPassNew, gasUsed) - } - } } function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp { @@ -4200,18 +4212,9 @@ object "EVMInterpreter" { _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) - - _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) - _popEVMFrame() - } - - // zkEVM native - if iszero(_calleeIsEVM) { + switch _calleeIsEVM + case 0 { + // zkEVM native _calleeGas := _getZkEVMGas(_calleeGas, _callee) let zkevmGasBefore := gas() success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen) @@ -4225,6 +4228,15 @@ object "EVMInterpreter" { _gasLeft := sub(_calleeGas, gasUsed) } } + default { + _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(EVM_GAS_STIPEND(), _callee, _inputOffset, _inputLen, 0, 0) + + _gasLeft := _saveReturndataAfterEVMCall(_outputOffset, _outputLen) + _popEVMFrame() + } } function isAddrEmpty(addr) -> isEmpty { From 2611e6188630f395a8b875872f8aa0bd870fe96a Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 21 Aug 2024 15:51:13 +0200 Subject: [PATCH 13/16] Fix --- .../contracts/EvmInterpreterPreprocessed.yul | 102 +++++++++--------- 1 file changed, 48 insertions(+), 54 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index eac6bb5e3..331ba506f 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -662,35 +662,32 @@ object "EVMInterpreter" { nonceEncoded := nonce nonceEncodedLength := 1 - switch nonce - case 0 { + if iszero(nonce) { nonceEncoded := 128 } - default { - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 - } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 - } + // The nonce has 4 bytes + if gt(nonce, 0xFFFFFF) { + nonceEncoded := shl(32, 0x84) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 5 + } + // The nonce has 3 bytes + if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { + nonceEncoded := shl(24, 0x83) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 4 + } + // The nonce has 2 bytes + if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 } listLength := add(21, nonceEncodedLength) @@ -3637,35 +3634,32 @@ object "EVMInterpreter" { nonceEncoded := nonce nonceEncodedLength := 1 - switch nonce - case 0 { + if iszero(nonce) { nonceEncoded := 128 } - default { - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 - } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 - } + // The nonce has 4 bytes + if gt(nonce, 0xFFFFFF) { + nonceEncoded := shl(32, 0x84) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 5 + } + // The nonce has 3 bytes + if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { + nonceEncoded := shl(24, 0x83) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 4 + } + // The nonce has 2 bytes + if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 } listLength := add(21, nonceEncodedLength) From fefa6cebef22db5b3321d01e4a13b465c0984f87 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 21 Aug 2024 16:29:05 +0200 Subject: [PATCH 14/16] Optimize getNewAddress --- .../EvmInterpreterFunctions.template.yul | 47 +++++----- .../contracts/EvmInterpreterPreprocessed.yul | 94 ++++++++++--------- 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 284b20c5d..622c45227 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -594,29 +594,34 @@ function getNewAddress(addr) -> newAddr { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 331ba506f..52c245b43 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -665,29 +665,34 @@ object "EVMInterpreter" { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) @@ -3637,29 +3642,34 @@ object "EVMInterpreter" { if iszero(nonce) { nonceEncoded := 128 } - // The nonce has 4 bytes - if gt(nonce, 0xFFFFFF) { - nonceEncoded := shl(32, 0x84) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 5 - } - // The nonce has 3 bytes - if and(gt(nonce, 0xFFFF), lt(nonce, 0x1000000)) { - nonceEncoded := shl(24, 0x83) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 4 - } - // The nonce has 2 bytes - if and(gt(nonce, 0xFF), lt(nonce, 0x10000)) { - nonceEncoded := shl(16, 0x82) + switch gt(nonce, 0xFFFF) + case 1 { + switch gt(nonce, 0xFFFFFF) + case 1 { + // The nonce has 4 bytes + nonceEncoded := shl(32, 0x84) + nonceEncodedLength := 5 + } + default { + // The nonce has 3 bytes + nonceEncoded := shl(24, 0x83) + nonceEncodedLength := 4 + } nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 3 } - // The nonce has 1 byte and it's in [0x80, 0xFF] - if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { - nonceEncoded := shl(8, 0x81) - nonceEncoded := add(nonceEncoded, nonce) - nonceEncodedLength := 2 + default { + // The nonce has 2 bytes + if gt(nonce, 0xFF) { + nonceEncoded := shl(16, 0x82) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 3 + } + // The nonce has 1 byte and it's in [0x80, 0xFF] + if and(gt(nonce, 0x7F), lt(nonce, 0x100)) { + nonceEncoded := shl(8, 0x81) + nonceEncoded := add(nonceEncoded, nonce) + nonceEncodedLength := 2 + } } listLength := add(21, nonceEncodedLength) From 7a98198348c2bf9b96b954188c152fc4a986ec9f Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 21 Aug 2024 17:03:14 +0200 Subject: [PATCH 15/16] Add and use pushStackCheck --- .../EvmInterpreterFunctions.template.yul | 17 +++++++--- .../contracts/EvmInterpreterPreprocessed.yul | 34 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index 622c45227..dd6ce421c 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -164,6 +164,12 @@ function popStackCheck(sp, evmGasLeft, numInputs) { } } +function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + revertWithGas(evmGasLeft) + } +} + function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } @@ -1232,10 +1238,11 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -1279,7 +1286,7 @@ function $llvm_NoInline_llvm$_genericCreate(addr, offset, size, sp, value, evmGa let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index 52c245b43..a0d2f2b5f 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -235,6 +235,12 @@ object "EVMInterpreter" { } } + function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + revertWithGas(evmGasLeft) + } + } + function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } @@ -1303,10 +1309,11 @@ object "EVMInterpreter" { offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -1350,7 +1357,7 @@ object "EVMInterpreter" { let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) @@ -3212,6 +3219,12 @@ object "EVMInterpreter" { } } + function pushStackCheck(sp, evmGasLeft, numInputs) { + if iszero(lt(add(sp, mul(0x20, sub(numInputs, 1))), BYTECODE_OFFSET())) { + revertWithGas(evmGasLeft) + } + } + function getCodeAddress() -> addr { addr := verbatim_0i_1o("code_source") } @@ -4280,10 +4293,11 @@ object "EVMInterpreter" { offset := add(MEM_OFFSET_INNER(), offset) - sp := pushStackItem(sp, mload(sub(offset, 0x80)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x60)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x40)), evmGasLeftOld) - sp := pushStackItem(sp, mload(sub(offset, 0x20)), evmGasLeftOld) + pushStackCheck(sp, evmGasLeftOld, 4) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x80))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x60))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x40))) + sp := pushStackItemWithoutCheck(sp, mload(sub(offset, 0x20))) // Selector mstore(sub(offset, 0x80), 0x5b16a23c) @@ -4327,7 +4341,7 @@ object "EVMInterpreter" { let back - popStackCheck(sp, evmGasLeft, 4) + // skipping check since we pushed exactly 4 items earlier back, sp := popStackItemWithoutCheck(sp) mstore(sub(offset, 0x20), back) back, sp := popStackItemWithoutCheck(sp) From 83d9aa711dce9614edf166e719aeafde89874009 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 21 Aug 2024 17:44:54 +0200 Subject: [PATCH 16/16] Initial overflow checks remake --- .../EvmInterpreterFunctions.template.yul | 33 ++-- .../contracts/EvmInterpreterLoop.template.yul | 43 +++-- .../contracts/EvmInterpreterPreprocessed.yul | 152 +++++++++--------- 3 files changed, 120 insertions(+), 108 deletions(-) diff --git a/system-contracts/contracts/EvmInterpreterFunctions.template.yul b/system-contracts/contracts/EvmInterpreterFunctions.template.yul index dd6ce421c..dbd250527 100644 --- a/system-contracts/contracts/EvmInterpreterFunctions.template.yul +++ b/system-contracts/contracts/EvmInterpreterFunctions.template.yul @@ -478,6 +478,13 @@ function getGasForPrecompiles(addr, argsOffset, argsSize) -> gasToCharge { } } +function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } +} + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -871,11 +878,11 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -1079,11 +1086,11 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -1380,9 +1387,8 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1427,9 +1433,8 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) diff --git a/system-contracts/contracts/EvmInterpreterLoop.template.yul b/system-contracts/contracts/EvmInterpreterLoop.template.yul index 8645147c4..d8811143a 100644 --- a/system-contracts/contracts/EvmInterpreterLoop.template.yul +++ b/system-contracts/contracts/EvmInterpreterLoop.template.yul @@ -330,8 +330,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -413,6 +413,7 @@ for { } true { } { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } @@ -519,7 +520,7 @@ for { } true { } { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -609,8 +610,7 @@ for { } true { } { offset, sp := popStackItem(sp, evmGasLeft) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -627,8 +627,7 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -644,8 +643,7 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -822,8 +820,9 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) - checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) @@ -1267,8 +1266,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1290,8 +1289,8 @@ for { } true { } { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1312,8 +1311,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1341,9 +1340,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1372,8 +1370,8 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -1454,6 +1452,7 @@ for { } true { } { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size))) diff --git a/system-contracts/contracts/EvmInterpreterPreprocessed.yul b/system-contracts/contracts/EvmInterpreterPreprocessed.yul index a0d2f2b5f..663b07495 100644 --- a/system-contracts/contracts/EvmInterpreterPreprocessed.yul +++ b/system-contracts/contracts/EvmInterpreterPreprocessed.yul @@ -549,6 +549,13 @@ object "EVMInterpreter" { } } + function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } + } + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -942,11 +949,11 @@ object "EVMInterpreter" { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -1150,11 +1157,11 @@ object "EVMInterpreter" { // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -1451,9 +1458,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1498,9 +1504,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -1878,8 +1883,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -1961,6 +1966,7 @@ object "EVMInterpreter" { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } @@ -2067,7 +2073,7 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -2157,8 +2163,7 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -2175,8 +2180,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -2192,8 +2196,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -2370,8 +2373,9 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) - checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) @@ -2815,8 +2819,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2838,8 +2842,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2860,8 +2864,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2889,9 +2893,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -2920,8 +2923,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -3002,6 +3005,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size))) @@ -3533,6 +3537,13 @@ object "EVMInterpreter" { } } + function checkMemOverflowByOffset(offset, evmGasLeft) { + if gt(offset, MAX_POSSIBLE_MEM()) { + mstore(0, evmGasLeft) + revert(0, 32) + } + } + function checkMemOverflow(location, evmGasLeft) { if gt(location, MAX_MEMORY_FRAME()) { mstore(0, evmGasLeft) @@ -3926,11 +3937,11 @@ object "EVMInterpreter" { addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset,argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) extraCost := 0 if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) { @@ -4134,11 +4145,11 @@ object "EVMInterpreter" { // addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff) - checkMultipleOverflow(argsOffset,argsSize,MEM_OFFSET_INNER(), evmGasLeft) - checkMultipleOverflow(retOffset, retSize,MEM_OFFSET_INNER(), evmGasLeft) + checkOverflow(argsOffset, argsSize, evmGasLeft) + checkOverflow(retOffset, retSize, evmGasLeft) - checkMemOverflow(add(add(argsOffset, argsSize), MEM_OFFSET_INNER()), evmGasLeft) - checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(add(argsOffset, argsSize), evmGasLeft) + checkMemOverflowByOffset(add(retOffset, retSize), evmGasLeft) if iszero(_isEVM(addr)) { revertWithGas(evmGasLeft) @@ -4435,9 +4446,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -4482,9 +4492,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) salt, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) if gt(size, mul(2, MAX_POSSIBLE_BYTECODE())) { revertWithGas(evmGasLeft) @@ -4862,8 +4871,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(MEM_OFFSET_INNER(), add(offset, size)), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) let keccak := keccak256(add(MEM_OFFSET_INNER(), offset), size) // When an offset is first accessed (either read or write), memory may trigger @@ -4945,6 +4954,7 @@ object "EVMInterpreter" { checkMultipleOverflow(offset,size,MEM_OFFSET_INNER(), evmGasLeft) checkMultipleOverflow(destOffset,size,MEM_OFFSET_INNER(), evmGasLeft) + // TODO invalid? if or(gt(add(add(offset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM()), gt(add(add(destOffset, size), MEM_OFFSET_INNER()), MAX_POSSIBLE_MEM())) { $llvm_AlwaysInline_llvm$_memsetToZero(add(destOffset, MEM_OFFSET_INNER()), size) } @@ -5051,7 +5061,7 @@ object "EVMInterpreter" { // minimum_word_size = (size + 31) / 32 // dynamicGas = 3 * minimum_word_size + memory_expansion_cost - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let dynamicGas := add(mul(3, shr(5, add(len, 31))), expandMemory(add(dest, len))) evmGasLeft := chargeGas(evmGasLeft, dynamicGas) @@ -5141,8 +5151,7 @@ object "EVMInterpreter" { offset, sp := popStackItem(sp, evmGasLeft) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -5159,8 +5168,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 32)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -5176,8 +5184,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) value, sp := popStackItemWithoutCheck(sp) - checkOverflow(offset, MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(offset, MEM_OFFSET_INNER()), evmGasLeft) + checkMemOverflowByOffset(offset, evmGasLeft) let expansionGas := expandMemory(add(offset, 1)) evmGasLeft := chargeGas(evmGasLeft, expansionGas) @@ -5354,8 +5361,9 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) - checkMemOverflow(add(add(destOffset, MEM_OFFSET_INNER()), size), evmGasLeft) + // TODO overflow checks + checkMemOverflowByOffset(add(offset, size), evmGasLeft) + checkMemOverflowByOffset(add(destOffset, size), evmGasLeft) expandMemory(add(destOffset, size)) expandMemory(add(offset, size)) @@ -5799,8 +5807,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5822,8 +5830,8 @@ object "EVMInterpreter" { size, sp := popStackItemWithoutCheck(sp) topic1, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5844,8 +5852,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5873,9 +5881,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5904,8 +5911,8 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) - checkMultipleOverflow(offset, size,MEM_OFFSET_INNER(), evmGasLeft) - checkMemOverflow(add(add(offset, MEM_OFFSET_INNER()), size), evmGasLeft) + checkOverflow(offset, size, evmGasLeft) + checkMemOverflowByOffset(add(offset, size), evmGasLeft) // dynamicGas = 375 * topic_count + 8 * size + memory_expansion_cost let dynamicGas := add(shl(3, size), expandMemory(add(offset, size))) @@ -5986,6 +5993,7 @@ object "EVMInterpreter" { offset, sp := popStackItemWithoutCheck(sp) size, sp := popStackItemWithoutCheck(sp) + // TODO invalid? ensureAcceptableMemLocation(offset) ensureAcceptableMemLocation(size) evmGasLeft := chargeGas(evmGasLeft,expandMemory(add(offset,size)))