From 9555afc5e808c621c8934f7cf0ea4e7ce6b25983 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Fri, 25 Oct 2024 18:08:19 +0200 Subject: [PATCH] fix(EVM): Fix precompiles gas flow (#998) --- system-contracts/SystemContractsHashes.json | 4 +- system-contracts/contracts/EvmEmulator.yul | 112 ++++++++++++------ .../EvmEmulatorFunctions.template.yul | 56 ++++++--- 3 files changed, 113 insertions(+), 59 deletions(-) diff --git a/system-contracts/SystemContractsHashes.json b/system-contracts/SystemContractsHashes.json index 35a0c1b1c..2c7cc6eb1 100644 --- a/system-contracts/SystemContractsHashes.json +++ b/system-contracts/SystemContractsHashes.json @@ -122,8 +122,8 @@ "contractName": "EvmEmulator", "bytecodePath": "contracts-preprocessed/artifacts/EvmEmulator.yul/EvmEmulator.yul.zbin", "sourceCodePath": "contracts-preprocessed/EvmEmulator.yul", - "bytecodeHash": "0x01000cd17989fbfbda00c1058d3cbe559dcd05ff07a71e9182f198e22d622cc0", - "sourceCodeHash": "0x43c82a32662ed95d5ecb809535f8487a04c14cbeedcd67eeb29bb33bf5bc74fd" + "bytecodeHash": "0x01000cfb8eb0e02f35ed77623c89d2d3c34783721996aa70190c90b187ed851e", + "sourceCodeHash": "0x2bb96c3957fdee6343c64d00921914c4b01aaad70d6c3ff2bd263c1fbd67110a" }, { "contractName": "EvmGasManager", diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index ad8595955..0074f1a9c 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -631,6 +631,14 @@ object "EvmEmulator" { gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performCall( addr, gasToPass, @@ -641,19 +649,20 @@ object "EvmEmulator" { retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - // TODO precompile should be called, but return nothing if gasPassed is too low - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) + stackHead := success } @@ -686,6 +695,14 @@ object "EvmEmulator" { gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performStaticCall( addr, gasToPass, @@ -695,18 +712,19 @@ object "EvmEmulator" { retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) stackHead := success } @@ -3640,6 +3658,14 @@ object "EvmEmulator" { gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performCall( addr, gasToPass, @@ -3650,19 +3676,20 @@ object "EvmEmulator" { retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - // TODO precompile should be called, but return nothing if gasPassed is too low - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) + stackHead := success } @@ -3695,6 +3722,14 @@ object "EvmEmulator" { gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performStaticCall( addr, gasToPass, @@ -3704,18 +3739,19 @@ object "EvmEmulator" { retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) stackHead := success } diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index 65839af46..7c0d35b61 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -577,6 +577,14 @@ function performCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, stackHe gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performCall( addr, gasToPass, @@ -587,19 +595,20 @@ function performCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, stackHe retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - // TODO precompile should be called, but return nothing if gasPassed is too low - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) + stackHead := success } @@ -632,6 +641,14 @@ function performStaticCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, s gasToPass := capGasForCall(evmGasLeft, gasToPass) + let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) + if precompileCost { + if lt(gasToPass, precompileCost) { + evmGasLeft := chargeGas(evmGasLeft, gasToPass) + gasToPass := 0 + } + } + let success, frameGasLeft := _performStaticCall( addr, gasToPass, @@ -641,18 +658,19 @@ function performStaticCall(oldSp, evmGasLeft, oldStackHead) -> newGasLeft, sp, s retSize ) - let gasUsed := 0 + let gasUsedByCall := sub(gasToPass, frameGasLeft) - let precompileCost := getGasForPrecompiles(addr, argsOffset, argsSize) - switch iszero(precompileCost) - case 1 { - gasUsed := sub(gasToPass, frameGasLeft) - } - default { - gasUsed := precompileCost + if precompileCost { + switch success + case 0 { + gasUsedByCall := gasToPass + } + default { + gasUsedByCall := precompileCost + } } - newGasLeft := chargeGas(evmGasLeft, gasUsed) + newGasLeft := chargeGas(evmGasLeft, gasUsedByCall) stackHead := success }