diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index a4b60bb0f..ef42bf940 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -178,8 +178,6 @@ object "EvmEmulator" { // Each evm gas is 5 zkEVM one function GAS_DIVISOR() -> gas_div { gas_div := 5 } - function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 - // We need to pass some gas for MsgValueSimulator internal logic to decommit emulator etc function MSG_VALUE_SIMULATOR_STIPEND_GAS() -> gas_stipend { gas_stipend := 35000 // 27000 + a little bit more @@ -196,6 +194,11 @@ object "EvmEmulator" { // GENERAL FUNCTIONS //////////////////////////////////////////////////////////////// + // abort the whole EVM execution environment, including parent frames + function abortEvmEnvironment() { + revert(0, 0) + } + function $llvm_NoInline_llvm$_panic() { // revert consuming all EVM gas mstore(0, 0) revert(0, 32) @@ -225,8 +228,9 @@ object "EvmEmulator" { } function getEvmGasFromContext() -> evmGas { + let gasStipend := shl(30, 1) // TODO remove stipend // Caller must pass at least OVERHEAD() ergs - let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + let requiredGas := add(gasStipend, OVERHEAD()) let _gas := gas() if gt(_gas, requiredGas) { @@ -234,13 +238,6 @@ object "EvmEmulator" { } } - function providedErgs() -> ergs { - let _gas := gas() - if gt(_gas, EVM_GAS_STIPEND()) { - ergs := sub(_gas, EVM_GAS_STIPEND()) - } - } - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(offset, size) -> gasCost { @@ -350,7 +347,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } returndatacopy(0, 0, 32) @@ -443,7 +440,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } } @@ -568,7 +565,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } if returndatasize() { @@ -763,7 +760,7 @@ object "EvmEmulator" { pushEvmFrame(gasToPass, isStatic) let success := delegatecall( - providedErgs(), + gas(), // pass all remaining native gas addr, add(MEM_OFFSET(), argsOffset), argsSize, @@ -794,13 +791,8 @@ object "EvmEmulator" { } default { pushEvmFrame(gasToPass, isStatic) - // VM will add EVM_GAS_STIPEND() to gas for this call, but if value != 0 we will firstly call MsgValueSimulator contract - // which is zkVM system contract. So we need to add some gas for MsgValueSimulator - let ergsToPass := providedErgs() - if value { - ergsToPass := add(MSG_VALUE_SIMULATOR_STIPEND_GAS(), ergsToPass) - } - success := call(ergsToPass, addr, value, argsOffset, argsSize, 0, 0) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) } } @@ -954,8 +946,8 @@ object "EvmEmulator" { switch gt(rtsz, 31) case 0 { // Unexpected return data. - _gasLeft := 0 - _eraseReturndataPointer() + // Most likely out-of-ergs or unexpected error in the emulator or system contracts + abortEvmEnvironment() } default { returndatacopy(0, 0, 32) @@ -1135,13 +1127,15 @@ object "EvmEmulator" { function _saveConstructorReturnGas() -> gasLeft, addr { loadReturndataIntoActivePtr() - if gt(returndatasize(), 63) { // >= 64 - // ContractDeployer returns (uint256 gasLeft, address createdContract) - returndatacopy(0, 0, 64) - gasLeft := mload(0) - addr := mload(32) + if lt(returndatasize(), 64) { + // unexpected return data after constructor succeeded, should never happen. + abortEvmEnvironment() } - // else: unexpected return data after constructor succeeded, should never happen. + + // ContractDeployer returns (uint256 gasLeft, address createdContract) + returndatacopy(0, 0, 64) + gasLeft := mload(0) + addr := mload(32) _eraseReturndataPointer() } @@ -3020,7 +3014,7 @@ object "EvmEmulator" { let evmGasLeft, isStatic, isCallerEVM := consumeEvmFrame() if isStatic { - revert(0, 0) + abortEvmEnvironment() // should never happen } getConstructorBytecode() @@ -3175,8 +3169,6 @@ object "EvmEmulator" { // Each evm gas is 5 zkEVM one function GAS_DIVISOR() -> gas_div { gas_div := 5 } - function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 - // We need to pass some gas for MsgValueSimulator internal logic to decommit emulator etc function MSG_VALUE_SIMULATOR_STIPEND_GAS() -> gas_stipend { gas_stipend := 35000 // 27000 + a little bit more @@ -3193,6 +3185,11 @@ object "EvmEmulator" { // GENERAL FUNCTIONS //////////////////////////////////////////////////////////////// + // abort the whole EVM execution environment, including parent frames + function abortEvmEnvironment() { + revert(0, 0) + } + function $llvm_NoInline_llvm$_panic() { // revert consuming all EVM gas mstore(0, 0) revert(0, 32) @@ -3222,8 +3219,9 @@ object "EvmEmulator" { } function getEvmGasFromContext() -> evmGas { + let gasStipend := shl(30, 1) // TODO remove stipend // Caller must pass at least OVERHEAD() ergs - let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + let requiredGas := add(gasStipend, OVERHEAD()) let _gas := gas() if gt(_gas, requiredGas) { @@ -3231,13 +3229,6 @@ object "EvmEmulator" { } } - function providedErgs() -> ergs { - let _gas := gas() - if gt(_gas, EVM_GAS_STIPEND()) { - ergs := sub(_gas, EVM_GAS_STIPEND()) - } - } - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(offset, size) -> gasCost { @@ -3347,7 +3338,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } returndatacopy(0, 0, 32) @@ -3440,7 +3431,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } } @@ -3565,7 +3556,7 @@ object "EvmEmulator" { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } if returndatasize() { @@ -3760,7 +3751,7 @@ object "EvmEmulator" { pushEvmFrame(gasToPass, isStatic) let success := delegatecall( - providedErgs(), + gas(), // pass all remaining native gas addr, add(MEM_OFFSET(), argsOffset), argsSize, @@ -3791,13 +3782,8 @@ object "EvmEmulator" { } default { pushEvmFrame(gasToPass, isStatic) - // VM will add EVM_GAS_STIPEND() to gas for this call, but if value != 0 we will firstly call MsgValueSimulator contract - // which is zkVM system contract. So we need to add some gas for MsgValueSimulator - let ergsToPass := providedErgs() - if value { - ergsToPass := add(MSG_VALUE_SIMULATOR_STIPEND_GAS(), ergsToPass) - } - success := call(ergsToPass, addr, value, argsOffset, argsSize, 0, 0) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) } } @@ -3951,8 +3937,8 @@ object "EvmEmulator" { switch gt(rtsz, 31) case 0 { // Unexpected return data. - _gasLeft := 0 - _eraseReturndataPointer() + // Most likely out-of-ergs or unexpected error in the emulator or system contracts + abortEvmEnvironment() } default { returndatacopy(0, 0, 32) @@ -4132,13 +4118,15 @@ object "EvmEmulator" { function _saveConstructorReturnGas() -> gasLeft, addr { loadReturndataIntoActivePtr() - if gt(returndatasize(), 63) { // >= 64 - // ContractDeployer returns (uint256 gasLeft, address createdContract) - returndatacopy(0, 0, 64) - gasLeft := mload(0) - addr := mload(32) + if lt(returndatasize(), 64) { + // unexpected return data after constructor succeeded, should never happen. + abortEvmEnvironment() } - // else: unexpected return data after constructor succeeded, should never happen. + + // ContractDeployer returns (uint256 gasLeft, address createdContract) + returndatacopy(0, 0, 64) + gasLeft := mload(0) + addr := mload(32) _eraseReturndataPointer() } diff --git a/system-contracts/evm-emulator/EvmEmulator.template.yul b/system-contracts/evm-emulator/EvmEmulator.template.yul index 5f4c2a0dd..247cfd786 100644 --- a/system-contracts/evm-emulator/EvmEmulator.template.yul +++ b/system-contracts/evm-emulator/EvmEmulator.template.yul @@ -85,7 +85,7 @@ object "EvmEmulator" { let evmGasLeft, isStatic, isCallerEVM := consumeEvmFrame() if isStatic { - revert(0, 0) + abortEvmEnvironment() // should never happen } getConstructorBytecode() diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index 494ef7540..a1dd6f356 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -116,8 +116,6 @@ function MAX_UINT() -> max_uint { // Each evm gas is 5 zkEVM one function GAS_DIVISOR() -> gas_div { gas_div := 5 } -function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30 - // We need to pass some gas for MsgValueSimulator internal logic to decommit emulator etc function MSG_VALUE_SIMULATOR_STIPEND_GAS() -> gas_stipend { gas_stipend := 35000 // 27000 + a little bit more @@ -134,6 +132,11 @@ function UINT32_MAX() -> ret { ret := 4294967295 } // 2^32 - 1 // GENERAL FUNCTIONS //////////////////////////////////////////////////////////////// +// abort the whole EVM execution environment, including parent frames +function abortEvmEnvironment() { + revert(0, 0) +} + function $llvm_NoInline_llvm$_panic() { // revert consuming all EVM gas mstore(0, 0) revert(0, 32) @@ -163,8 +166,9 @@ function chargeGas(prevGas, toCharge) -> gasRemaining { } function getEvmGasFromContext() -> evmGas { + let gasStipend := shl(30, 1) // TODO remove stipend // Caller must pass at least OVERHEAD() ergs - let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD()) + let requiredGas := add(gasStipend, OVERHEAD()) let _gas := gas() if gt(_gas, requiredGas) { @@ -172,13 +176,6 @@ function getEvmGasFromContext() -> evmGas { } } -function providedErgs() -> ergs { - let _gas := gas() - if gt(_gas, EVM_GAS_STIPEND()) { - ergs := sub(_gas, EVM_GAS_STIPEND()) - } -} - // This function can overflow, it is the job of the caller to ensure that it does not. // The argument to this function is the offset into the memory region IN BYTES. function expandMemory(offset, size) -> gasCost { @@ -288,7 +285,7 @@ function fetchFromSystemContract(to, argSize) -> res { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } returndatacopy(0, 0, 32) @@ -381,7 +378,7 @@ function performSystemCall(to, dataLength) { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } } @@ -506,7 +503,7 @@ function isSlotWarm(key) -> isWarm { if iszero(success) { // This error should never happen - revert(0, 0) + abortEvmEnvironment() } if returndatasize() { @@ -701,7 +698,7 @@ function performDelegateCall(oldSp, evmGasLeft, isStatic, oldStackHead) -> newGa pushEvmFrame(gasToPass, isStatic) let success := delegatecall( - providedErgs(), + gas(), // pass all remaining native gas addr, add(MEM_OFFSET(), argsOffset), argsSize, @@ -732,13 +729,8 @@ function _genericCall(addr, gasToPass, value, argsOffset, argsSize, retOffset, r } default { pushEvmFrame(gasToPass, isStatic) - // VM will add EVM_GAS_STIPEND() to gas for this call, but if value != 0 we will firstly call MsgValueSimulator contract - // which is zkVM system contract. So we need to add some gas for MsgValueSimulator - let ergsToPass := providedErgs() - if value { - ergsToPass := add(MSG_VALUE_SIMULATOR_STIPEND_GAS(), ergsToPass) - } - success := call(ergsToPass, addr, value, argsOffset, argsSize, 0, 0) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) } } @@ -892,8 +884,8 @@ function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft { switch gt(rtsz, 31) case 0 { // Unexpected return data. - _gasLeft := 0 - _eraseReturndataPointer() + // Most likely out-of-ergs or unexpected error in the emulator or system contracts + abortEvmEnvironment() } default { returndatacopy(0, 0, 32) @@ -1073,13 +1065,15 @@ function performSystemCallForCreate(value, bytecodeStart, bytecodeLen) -> succes function _saveConstructorReturnGas() -> gasLeft, addr { loadReturndataIntoActivePtr() - if gt(returndatasize(), 63) { // >= 64 - // ContractDeployer returns (uint256 gasLeft, address createdContract) - returndatacopy(0, 0, 64) - gasLeft := mload(0) - addr := mload(32) + if lt(returndatasize(), 64) { + // unexpected return data after constructor succeeded, should never happen. + abortEvmEnvironment() } - // else: unexpected return data after constructor succeeded, should never happen. + + // ContractDeployer returns (uint256 gasLeft, address createdContract) + returndatacopy(0, 0, 64) + gasLeft := mload(0) + addr := mload(32) _eraseReturndataPointer() }