diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index 9c4377428..47888625b 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -86,8 +86,44 @@ object "EvmEmulator" { addr := 0x0000000000000000000000000000000000008009 } + function ORIGIN_CACHE_OFFSET() -> offset { + offset := mul(23, 32) + } + + function GASPRICE_CACHE_OFFSET() -> offset { + offset := mul(24, 32) + } + + function COINBASE_CACHE_OFFSET() -> offset { + offset := mul(25, 32) + } + + function BLOCKTIMESTAMP_CACHE_OFFSET() -> offset { + offset := mul(26, 32) + } + + function BLOCKNUMBER_CACHE_OFFSET() -> offset { + offset := mul(27, 32) + } + + function PREVRANDAO_CACHE_OFFSET() -> offset { + offset := mul(28, 32) + } + + function GASLIMIT_CACHE_OFFSET() -> offset { + offset := mul(29, 32) + } + + function CHAINID_CACHE_OFFSET() -> offset { + offset := mul(30, 32) + } + + function BASEFEE_CACHE_OFFSET() -> offset { + offset := mul(31, 32) + } + function LAST_RETURNDATA_SIZE_OFFSET() -> offset { - offset := mul(32, 32) + offset := add(BASEFEE_CACHE_OFFSET(), 32) } function STACK_OFFSET() -> offset { @@ -167,6 +203,11 @@ object "EvmEmulator" { revert(0, 32) } + function cached(cacheIndex, value) -> _value { + _value := value + mstore(cacheIndex, _value) + } + function chargeGas(prevGas, toCharge) -> gasRemaining { if lt(prevGas, toCharge) { panic() @@ -1592,7 +1633,6 @@ object "EvmEmulator" { } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, address(), stackHead) ip := add(ip, 1) } @@ -1612,8 +1652,11 @@ object "EvmEmulator" { } case 0x32 { // OP_ORIGIN evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, origin(), stackHead) + let _origin := mload(ORIGIN_CACHE_OFFSET()) + if iszero(_origin) { + _origin := cached(ORIGIN_CACHE_OFFSET(), origin()) + } + sp, stackHead := pushStackItem(sp, _origin, stackHead) ip := add(ip, 1) } case 0x33 { // OP_CALLER @@ -1701,8 +1744,11 @@ object "EvmEmulator" { } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, gasprice(), stackHead) + let _gasprice := mload(GASPRICE_CACHE_OFFSET()) + if iszero(_gasprice) { + _gasprice := cached(GASPRICE_CACHE_OFFSET(), gasprice()) + } + sp, stackHead := pushStackItem(sp, _gasprice, stackHead) ip := add(ip, 1) } case 0x3B { // OP_EXTCODESIZE @@ -1814,32 +1860,56 @@ object "EvmEmulator" { } case 0x41 { // OP_COINBASE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, coinbase(), stackHead) + let _coinbase := mload(COINBASE_CACHE_OFFSET()) + if iszero(_coinbase) { + _coinbase := cached(COINBASE_CACHE_OFFSET(), coinbase()) + } + sp, stackHead := pushStackItem(sp, _coinbase, stackHead) ip := add(ip, 1) } case 0x42 { // OP_TIMESTAMP evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, timestamp(), stackHead) + let _blocktimestamp := mload(BLOCKTIMESTAMP_CACHE_OFFSET()) + if iszero(_blocktimestamp) { + _blocktimestamp := cached(BLOCKTIMESTAMP_CACHE_OFFSET(), timestamp()) + } + sp, stackHead := pushStackItem(sp, _blocktimestamp, stackHead) ip := add(ip, 1) } case 0x43 { // OP_NUMBER evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, number(), stackHead) + let _blocknumber := mload(BLOCKNUMBER_CACHE_OFFSET()) + if iszero(_blocknumber) { + _blocknumber := cached(BLOCKNUMBER_CACHE_OFFSET(), number()) + } + sp, stackHead := pushStackItem(sp, _blocknumber, stackHead) ip := add(ip, 1) } case 0x44 { // OP_PREVRANDAO evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, prevrandao(), stackHead) + let _prevrandao := mload(PREVRANDAO_CACHE_OFFSET()) + if iszero(_prevrandao) { + _prevrandao := cached(PREVRANDAO_CACHE_OFFSET(), prevrandao()) + } + sp, stackHead := pushStackItem(sp, _prevrandao, stackHead) ip := add(ip, 1) } case 0x45 { // OP_GASLIMIT evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, gaslimit(), stackHead) + let _gasLimit := mload(GASLIMIT_CACHE_OFFSET()) + if iszero(_gasLimit) { + _gasLimit := cached(GASLIMIT_CACHE_OFFSET(), gaslimit()) + } + sp, stackHead := pushStackItem(sp, _gasLimit, stackHead) ip := add(ip, 1) } case 0x46 { // OP_CHAINID evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, chainid(), stackHead) + let _chainId := mload(CHAINID_CACHE_OFFSET()) + if iszero(_chainId) { + _chainId := cached(CHAINID_CACHE_OFFSET(), chainid()) + } + sp, stackHead := pushStackItem(sp, _chainId, stackHead) ip := add(ip, 1) } case 0x47 { // OP_SELFBALANCE @@ -1849,7 +1919,11 @@ object "EvmEmulator" { } case 0x48 { // OP_BASEFEE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, basefee(), stackHead) + let _baseFee := mload(BASEFEE_CACHE_OFFSET()) + if iszero(_baseFee) { + _baseFee := cached(BASEFEE_CACHE_OFFSET(), basefee()) + } + sp, stackHead := pushStackItem(sp, _baseFee, stackHead) ip := add(ip, 1) } case 0x50 { // OP_POP @@ -3119,8 +3193,44 @@ object "EvmEmulator" { addr := 0x0000000000000000000000000000000000008009 } + function ORIGIN_CACHE_OFFSET() -> offset { + offset := mul(23, 32) + } + + function GASPRICE_CACHE_OFFSET() -> offset { + offset := mul(24, 32) + } + + function COINBASE_CACHE_OFFSET() -> offset { + offset := mul(25, 32) + } + + function BLOCKTIMESTAMP_CACHE_OFFSET() -> offset { + offset := mul(26, 32) + } + + function BLOCKNUMBER_CACHE_OFFSET() -> offset { + offset := mul(27, 32) + } + + function PREVRANDAO_CACHE_OFFSET() -> offset { + offset := mul(28, 32) + } + + function GASLIMIT_CACHE_OFFSET() -> offset { + offset := mul(29, 32) + } + + function CHAINID_CACHE_OFFSET() -> offset { + offset := mul(30, 32) + } + + function BASEFEE_CACHE_OFFSET() -> offset { + offset := mul(31, 32) + } + function LAST_RETURNDATA_SIZE_OFFSET() -> offset { - offset := mul(32, 32) + offset := add(BASEFEE_CACHE_OFFSET(), 32) } function STACK_OFFSET() -> offset { @@ -3200,6 +3310,11 @@ object "EvmEmulator" { revert(0, 32) } + function cached(cacheIndex, value) -> _value { + _value := value + mstore(cacheIndex, _value) + } + function chargeGas(prevGas, toCharge) -> gasRemaining { if lt(prevGas, toCharge) { panic() @@ -4625,7 +4740,6 @@ object "EvmEmulator" { } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, address(), stackHead) ip := add(ip, 1) } @@ -4645,8 +4759,11 @@ object "EvmEmulator" { } case 0x32 { // OP_ORIGIN evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, origin(), stackHead) + let _origin := mload(ORIGIN_CACHE_OFFSET()) + if iszero(_origin) { + _origin := cached(ORIGIN_CACHE_OFFSET(), origin()) + } + sp, stackHead := pushStackItem(sp, _origin, stackHead) ip := add(ip, 1) } case 0x33 { // OP_CALLER @@ -4734,8 +4851,11 @@ object "EvmEmulator" { } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, gasprice(), stackHead) + let _gasprice := mload(GASPRICE_CACHE_OFFSET()) + if iszero(_gasprice) { + _gasprice := cached(GASPRICE_CACHE_OFFSET(), gasprice()) + } + sp, stackHead := pushStackItem(sp, _gasprice, stackHead) ip := add(ip, 1) } case 0x3B { // OP_EXTCODESIZE @@ -4847,32 +4967,56 @@ object "EvmEmulator" { } case 0x41 { // OP_COINBASE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, coinbase(), stackHead) + let _coinbase := mload(COINBASE_CACHE_OFFSET()) + if iszero(_coinbase) { + _coinbase := cached(COINBASE_CACHE_OFFSET(), coinbase()) + } + sp, stackHead := pushStackItem(sp, _coinbase, stackHead) ip := add(ip, 1) } case 0x42 { // OP_TIMESTAMP evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, timestamp(), stackHead) + let _blocktimestamp := mload(BLOCKTIMESTAMP_CACHE_OFFSET()) + if iszero(_blocktimestamp) { + _blocktimestamp := cached(BLOCKTIMESTAMP_CACHE_OFFSET(), timestamp()) + } + sp, stackHead := pushStackItem(sp, _blocktimestamp, stackHead) ip := add(ip, 1) } case 0x43 { // OP_NUMBER evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, number(), stackHead) + let _blocknumber := mload(BLOCKNUMBER_CACHE_OFFSET()) + if iszero(_blocknumber) { + _blocknumber := cached(BLOCKNUMBER_CACHE_OFFSET(), number()) + } + sp, stackHead := pushStackItem(sp, _blocknumber, stackHead) ip := add(ip, 1) } case 0x44 { // OP_PREVRANDAO evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, prevrandao(), stackHead) + let _prevrandao := mload(PREVRANDAO_CACHE_OFFSET()) + if iszero(_prevrandao) { + _prevrandao := cached(PREVRANDAO_CACHE_OFFSET(), prevrandao()) + } + sp, stackHead := pushStackItem(sp, _prevrandao, stackHead) ip := add(ip, 1) } case 0x45 { // OP_GASLIMIT evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, gaslimit(), stackHead) + let _gasLimit := mload(GASLIMIT_CACHE_OFFSET()) + if iszero(_gasLimit) { + _gasLimit := cached(GASLIMIT_CACHE_OFFSET(), gaslimit()) + } + sp, stackHead := pushStackItem(sp, _gasLimit, stackHead) ip := add(ip, 1) } case 0x46 { // OP_CHAINID evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, chainid(), stackHead) + let _chainId := mload(CHAINID_CACHE_OFFSET()) + if iszero(_chainId) { + _chainId := cached(CHAINID_CACHE_OFFSET(), chainid()) + } + sp, stackHead := pushStackItem(sp, _chainId, stackHead) ip := add(ip, 1) } case 0x47 { // OP_SELFBALANCE @@ -4882,7 +5026,11 @@ object "EvmEmulator" { } case 0x48 { // OP_BASEFEE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, basefee(), stackHead) + let _baseFee := mload(BASEFEE_CACHE_OFFSET()) + if iszero(_baseFee) { + _baseFee := cached(BASEFEE_CACHE_OFFSET(), basefee()) + } + sp, stackHead := pushStackItem(sp, _baseFee, stackHead) ip := add(ip, 1) } case 0x50 { // OP_POP diff --git a/system-contracts/contracts/SystemContext.sol b/system-contracts/contracts/SystemContext.sol index eab089e8f..10eef6901 100644 --- a/system-contracts/contracts/SystemContext.sol +++ b/system-contracts/contracts/SystemContext.sol @@ -42,6 +42,7 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, SystemContra /// @notice The `block.coinbase` in the current transaction. /// @dev For the support of coinbase, we will use the bootloader formal address for now + /// @dev (!) EVM emulator doesn't expect this value to change address public coinbase = BOOTLOADER_FORMAL_ADDRESS; /// @notice Formal `block.difficulty` parameter. diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index 8ca655213..78d06c31c 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -26,8 +26,44 @@ function MSG_VALUE_SYSTEM_CONTRACT() -> addr { addr := 0x0000000000000000000000000000000000008009 } +function ORIGIN_CACHE_OFFSET() -> offset { + offset := mul(23, 32) +} + +function GASPRICE_CACHE_OFFSET() -> offset { + offset := mul(24, 32) +} + +function COINBASE_CACHE_OFFSET() -> offset { + offset := mul(25, 32) +} + +function BLOCKTIMESTAMP_CACHE_OFFSET() -> offset { + offset := mul(26, 32) +} + +function BLOCKNUMBER_CACHE_OFFSET() -> offset { + offset := mul(27, 32) +} + +function PREVRANDAO_CACHE_OFFSET() -> offset { + offset := mul(28, 32) +} + +function GASLIMIT_CACHE_OFFSET() -> offset { + offset := mul(29, 32) +} + +function CHAINID_CACHE_OFFSET() -> offset { + offset := mul(30, 32) +} + +function BASEFEE_CACHE_OFFSET() -> offset { + offset := mul(31, 32) +} + function LAST_RETURNDATA_SIZE_OFFSET() -> offset { - offset := mul(32, 32) + offset := add(BASEFEE_CACHE_OFFSET(), 32) } function STACK_OFFSET() -> offset { @@ -107,6 +143,11 @@ function panic() { revert(0, 32) } +function cached(cacheIndex, value) -> _value { + _value := value + mstore(cacheIndex, _value) +} + function chargeGas(prevGas, toCharge) -> gasRemaining { if lt(prevGas, toCharge) { panic() diff --git a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul index c3bd57186..52d04d072 100644 --- a/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorLoop.template.yul @@ -299,7 +299,6 @@ for { } true { } { } case 0x30 { // OP_ADDRESS evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, address(), stackHead) ip := add(ip, 1) } @@ -319,8 +318,11 @@ for { } true { } { } case 0x32 { // OP_ORIGIN evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, origin(), stackHead) + let _origin := mload(ORIGIN_CACHE_OFFSET()) + if iszero(_origin) { + _origin := cached(ORIGIN_CACHE_OFFSET(), origin()) + } + sp, stackHead := pushStackItem(sp, _origin, stackHead) ip := add(ip, 1) } case 0x33 { // OP_CALLER @@ -408,8 +410,11 @@ for { } true { } { } case 0x3A { // OP_GASPRICE evmGasLeft := chargeGas(evmGasLeft, 2) - - sp, stackHead := pushStackItem(sp, gasprice(), stackHead) + let _gasprice := mload(GASPRICE_CACHE_OFFSET()) + if iszero(_gasprice) { + _gasprice := cached(GASPRICE_CACHE_OFFSET(), gasprice()) + } + sp, stackHead := pushStackItem(sp, _gasprice, stackHead) ip := add(ip, 1) } case 0x3B { // OP_EXTCODESIZE @@ -521,32 +526,56 @@ for { } true { } { } case 0x41 { // OP_COINBASE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, coinbase(), stackHead) + let _coinbase := mload(COINBASE_CACHE_OFFSET()) + if iszero(_coinbase) { + _coinbase := cached(COINBASE_CACHE_OFFSET(), coinbase()) + } + sp, stackHead := pushStackItem(sp, _coinbase, stackHead) ip := add(ip, 1) } case 0x42 { // OP_TIMESTAMP evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, timestamp(), stackHead) + let _blocktimestamp := mload(BLOCKTIMESTAMP_CACHE_OFFSET()) + if iszero(_blocktimestamp) { + _blocktimestamp := cached(BLOCKTIMESTAMP_CACHE_OFFSET(), timestamp()) + } + sp, stackHead := pushStackItem(sp, _blocktimestamp, stackHead) ip := add(ip, 1) } case 0x43 { // OP_NUMBER evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, number(), stackHead) + let _blocknumber := mload(BLOCKNUMBER_CACHE_OFFSET()) + if iszero(_blocknumber) { + _blocknumber := cached(BLOCKNUMBER_CACHE_OFFSET(), number()) + } + sp, stackHead := pushStackItem(sp, _blocknumber, stackHead) ip := add(ip, 1) } case 0x44 { // OP_PREVRANDAO evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, prevrandao(), stackHead) + let _prevrandao := mload(PREVRANDAO_CACHE_OFFSET()) + if iszero(_prevrandao) { + _prevrandao := cached(PREVRANDAO_CACHE_OFFSET(), prevrandao()) + } + sp, stackHead := pushStackItem(sp, _prevrandao, stackHead) ip := add(ip, 1) } case 0x45 { // OP_GASLIMIT evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, gaslimit(), stackHead) + let _gasLimit := mload(GASLIMIT_CACHE_OFFSET()) + if iszero(_gasLimit) { + _gasLimit := cached(GASLIMIT_CACHE_OFFSET(), gaslimit()) + } + sp, stackHead := pushStackItem(sp, _gasLimit, stackHead) ip := add(ip, 1) } case 0x46 { // OP_CHAINID evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, chainid(), stackHead) + let _chainId := mload(CHAINID_CACHE_OFFSET()) + if iszero(_chainId) { + _chainId := cached(CHAINID_CACHE_OFFSET(), chainid()) + } + sp, stackHead := pushStackItem(sp, _chainId, stackHead) ip := add(ip, 1) } case 0x47 { // OP_SELFBALANCE @@ -556,7 +585,11 @@ for { } true { } { } case 0x48 { // OP_BASEFEE evmGasLeft := chargeGas(evmGasLeft, 2) - sp, stackHead := pushStackItem(sp, basefee(), stackHead) + let _baseFee := mload(BASEFEE_CACHE_OFFSET()) + if iszero(_baseFee) { + _baseFee := cached(BASEFEE_CACHE_OFFSET(), basefee()) + } + sp, stackHead := pushStackItem(sp, _baseFee, stackHead) ip := add(ip, 1) } case 0x50 { // OP_POP