From 782446b1e0e49fddc9425cbb3d24a686f7d18ff1 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Wed, 27 Nov 2024 17:52:25 +0100 Subject: [PATCH] fix(EVM): Fix insufficient balance panics (#1095) --- system-contracts/contracts/EvmEmulator.yul | 62 ++++++++++++------- .../EvmEmulatorFunctions.template.yul | 31 ++++++---- 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/system-contracts/contracts/EvmEmulator.yul b/system-contracts/contracts/EvmEmulator.yul index 3d754f38f..b4a088450 100644 --- a/system-contracts/contracts/EvmEmulator.yul +++ b/system-contracts/contracts/EvmEmulator.yul @@ -293,6 +293,12 @@ object "EvmEmulator" { } } + function insufficientBalance(value) -> res { + if value { + res := gt(value, selfbalance()) + } + } + // It is the responsibility of the caller to ensure that ip is correct function readIP(ip, bytecodeEndOffset) -> opcode { if lt(ip, bytecodeEndOffset) { @@ -825,12 +831,18 @@ object "EvmEmulator" { } } default { - pushEvmFrame(gasToPass, isStatic) - // pass all remaining native gas - success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - if iszero(success) { - resetEvmFrame() + switch insufficientBalance(value) + case 0 { + pushEvmFrame(gasToPass, isStatic) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + if iszero(success) { + resetEvmFrame() + } + } + default { + frameGasLeft := gasToPass } } } @@ -1041,12 +1053,7 @@ object "EvmEmulator" { _eraseReturndataPointer() - let err := 0 - if value { - if gt(value, selfbalance()) { - err := 1 - } - } + let err := insufficientBalance(value) if iszero(err) { offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow @@ -3325,6 +3332,12 @@ object "EvmEmulator" { } } + function insufficientBalance(value) -> res { + if value { + res := gt(value, selfbalance()) + } + } + // It is the responsibility of the caller to ensure that ip is correct function readIP(ip, bytecodeEndOffset) -> opcode { if lt(ip, bytecodeEndOffset) { @@ -3857,12 +3870,18 @@ object "EvmEmulator" { } } default { - pushEvmFrame(gasToPass, isStatic) - // pass all remaining native gas - success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - if iszero(success) { - resetEvmFrame() + switch insufficientBalance(value) + case 0 { + pushEvmFrame(gasToPass, isStatic) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + if iszero(success) { + resetEvmFrame() + } + } + default { + frameGasLeft := gasToPass } } } @@ -4073,12 +4092,7 @@ object "EvmEmulator" { _eraseReturndataPointer() - let err := 0 - if value { - if gt(value, selfbalance()) { - err := 1 - } - } + let err := insufficientBalance(value) if iszero(err) { offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow diff --git a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul index d8131e1a8..4bfa3b6ea 100644 --- a/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul +++ b/system-contracts/evm-emulator/EvmEmulatorFunctions.template.yul @@ -231,6 +231,12 @@ function checkOverflow(data1, data2) { } } +function insufficientBalance(value) -> res { + if value { + res := gt(value, selfbalance()) + } +} + // It is the responsibility of the caller to ensure that ip is correct function readIP(ip, bytecodeEndOffset) -> opcode { if lt(ip, bytecodeEndOffset) { @@ -763,12 +769,18 @@ function _genericCall(addr, gasToPass, value, argsOffset, argsSize, retOffset, r } } default { - pushEvmFrame(gasToPass, isStatic) - // pass all remaining native gas - success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) - frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) - if iszero(success) { - resetEvmFrame() + switch insufficientBalance(value) + case 0 { + pushEvmFrame(gasToPass, isStatic) + // pass all remaining native gas + success := call(gas(), addr, value, argsOffset, argsSize, 0, 0) + frameGasLeft := _saveReturndataAfterEVMCall(retOffset, retSize) + if iszero(success) { + resetEvmFrame() + } + } + default { + frameGasLeft := gasToPass } } } @@ -979,12 +991,7 @@ function $llvm_NoInline_llvm$_genericCreate(offset, size, value, evmGasLeftOld, _eraseReturndataPointer() - let err := 0 - if value { - if gt(value, selfbalance()) { - err := 1 - } - } + let err := insufficientBalance(value) if iszero(err) { offset := add(MEM_OFFSET(), offset) // caller must ensure that it doesn't overflow