diff --git a/src/compiler/evm_frontend/evm_imported.cpp b/src/compiler/evm_frontend/evm_imported.cpp index cbe4dbde..d3f7b05b 100644 --- a/src/compiler/evm_frontend/evm_imported.cpp +++ b/src/compiler/evm_frontend/evm_imported.cpp @@ -872,6 +872,8 @@ static uint64_t evmHandleCallInternal(zen::runtime::EVMInstance *Instance, } uint64_t CallGas = Gas; + bool HasEnoughBalance = true; + if (HasValueArgs) { std::optional AccountState; uint64_t GasCost = HasValue ? zen::evm::CALL_VALUE_COST : 0; @@ -896,22 +898,16 @@ static uint64_t evmHandleCallInternal(zen::runtime::EVMInstance *Instance, Instance, zen::common::ErrorCode::GasLimitExceeded); } - if (HasValueArgs) { - bool HasEnoughBalance = true; - if (HasValue) { - Instance->addGas(zen::evm::CALL_GAS_STIPEND); - CallGas += zen::evm::CALL_GAS_STIPEND; - - const auto CallerBalance = - Module->Host->get_balance(CurrentMsg->recipient); - const intx::uint256 CallerValue = - intx::be::load(CallerBalance); - HasEnoughBalance = CallerValue >= intx::uint256(Value); - - if (!HasEnoughBalance) { - Instance->setReturnData({}); - return 0; - } + if (HasValueArgs && HasValue) { + CallGas += zen::evm::CALL_GAS_STIPEND; + Instance->addGas(zen::evm::CALL_GAS_STIPEND); + const auto CallerBalance = Module->Host->get_balance(CurrentMsg->recipient); + const intx::uint256 CallerValue = + intx::be::load(CallerBalance); + HasEnoughBalance = CallerValue >= intx::uint256(Value); + if (!HasEnoughBalance) { + Instance->setReturnData({}); + return 0; } } diff --git a/src/tests/evm_precompiles.hpp b/src/tests/evm_precompiles.hpp index b7064910..d2eb891c 100644 --- a/src/tests/evm_precompiles.hpp +++ b/src/tests/evm_precompiles.hpp @@ -99,22 +99,33 @@ inline uint64_t adjustedExponentLength(uint64_t ExpLen, inline boost::multiprecision::cpp_int multComplexityEIP198(uint64_t MaxLen) noexcept { using boost::multiprecision::cpp_int; - const cpp_int X(MaxLen); + using cpp_int_et_off = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend<>, boost::multiprecision::et_off>; + const cpp_int_et_off X(MaxLen); + cpp_int_et_off Result = X * X; if (MaxLen <= 64) { - return X * X; + return cpp_int(Result); } if (MaxLen <= 1024) { - return X * X / 4 + cpp_int(96) * MaxLen - 3072; - } - return X * X / 16 + cpp_int(480) * MaxLen - 199680; + Result /= 4; + Result += cpp_int_et_off(96) * MaxLen; + Result -= 3072; + return cpp_int(Result); + } + Result /= 16; + Result += cpp_int_et_off(480) * MaxLen; + Result -= 199680; + return cpp_int(Result); } inline boost::multiprecision::cpp_int multComplexityEIP2565(uint64_t MaxLen) noexcept { using boost::multiprecision::cpp_int; + using cpp_int_et_off = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend<>, boost::multiprecision::et_off>; const uint64_t Words = (MaxLen + 7) / 8; - const cpp_int W(Words); - return W * W; + const cpp_int_et_off W(Words); + return cpp_int(W * W); } inline bool toUint64(const boost::multiprecision::cpp_int &Value, @@ -309,21 +320,25 @@ inline evmc::Result executeModExp(const evmc_message &Msg, const uint64_t IterationCount = std::max(AdjustedExpLen, 1); using boost::multiprecision::cpp_int; - cpp_int GasCost = 0; + using cpp_int_et_off = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend<>, boost::multiprecision::et_off>; + cpp_int_et_off GasCost = 0; if (Revision >= EVMC_BERLIN) { - GasCost = - multComplexityEIP2565(MaxLen) * cpp_int(IterationCount) / cpp_int(3); + GasCost = cpp_int_et_off(multComplexityEIP2565(MaxLen)); + GasCost *= cpp_int_et_off(IterationCount); + GasCost /= cpp_int_et_off(3); if (GasCost < 200) { GasCost = 200; } } else { - GasCost = - multComplexityEIP198(MaxLen) * cpp_int(IterationCount) / cpp_int(20); - GasCost += cpp_int(LegacyModExpBaseGas); + GasCost = cpp_int_et_off(multComplexityEIP198(MaxLen)); + GasCost *= cpp_int_et_off(IterationCount); + GasCost /= cpp_int_et_off(20); + GasCost += cpp_int_et_off(LegacyModExpBaseGas); } uint64_t GasCost64 = 0; - if (!toUint64(GasCost, GasCost64)) { + if (!toUint64(cpp_int(GasCost), GasCost64)) { return evmc::Result(EVMC_OUT_OF_GAS, 0, 0, nullptr, 0); } diff --git a/src/tests/evm_test_host.hpp b/src/tests/evm_test_host.hpp index 15570bbb..520f2cb4 100644 --- a/src/tests/evm_test_host.hpp +++ b/src/tests/evm_test_host.hpp @@ -45,6 +45,7 @@ class ZenMockedEVMHost : public evmc::MockedHost { PrewarmStorageKeys; std::unordered_set CreatedInTx; std::unordered_set PendingSelfdestructs; + uint64_t CallStipendRefund = 0; // track CALL stipend refunds for prepaid fees bool FeesPrepaidInTx = false; public: @@ -477,6 +478,12 @@ class ZenMockedEVMHost : public evmc::MockedHost { ParentResult.gas_left == 0) { ParentResult.gas_left = Msg.gas; } + if (FeesPrepaidInTx && Msg.kind == EVMC_CALL && + toUint256Bytes(Msg.value) != intx::uint256{0} && + ParentResult.status_code == EVMC_SUCCESS && + ParentResult.gas_left < Msg.gas) { + this->CallStipendRefund += CALL_GAS_STIPEND; + } return ParentResult; } diff --git a/src/tests/solidity_contract_tests.cpp b/src/tests/solidity_contract_tests.cpp index 56e5f5db..1b329f4f 100644 --- a/src/tests/solidity_contract_tests.cpp +++ b/src/tests/solidity_contract_tests.cpp @@ -203,6 +203,8 @@ GTEST_API_ int main(int argc, char **argv) { uint64_t GasLimit = 0xFFFF'FFFF'FFFF; LoggerLevel LogLevel = LoggerLevel::Info; RuntimeConfig Config; + Config.Format = InputFormat::EVM; + Config.Mode = RunMode::InterpMode; const std::unordered_map FormatMap = { {"wasm", InputFormat::WASM}, diff --git a/tests/evm_asm/sar.expected b/tests/evm_asm/sar.expected new file mode 100644 index 00000000..b1be29b3 --- /dev/null +++ b/tests/evm_asm/sar.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +storage: {} +transient_storage: {} +return: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +events: [] diff --git a/tests/evm_asm/sar_edge.expected b/tests/evm_asm/sar_edge.expected new file mode 100644 index 00000000..f0e8a4e3 --- /dev/null +++ b/tests/evm_asm/sar_edge.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +storage: {} +transient_storage: {} +return: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +events: [] diff --git a/tests/evm_asm/shl.expected b/tests/evm_asm/shl.expected new file mode 100644 index 00000000..a6fa96ea --- /dev/null +++ b/tests/evm_asm/shl.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: 0000000000000000000000000000000000000000000000000000000000000008 +storage: {} +transient_storage: {} +return: 0000000000000000000000000000000000000000000000000000000000000008 +events: [] diff --git a/tests/evm_asm/shl_edge.expected b/tests/evm_asm/shl_edge.expected new file mode 100644 index 00000000..3e413478 --- /dev/null +++ b/tests/evm_asm/shl_edge.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: 8000000000000000000000000000000000000000000000000000000000000000 +storage: {} +transient_storage: {} +return: 8000000000000000000000000000000000000000000000000000000000000000 +events: [] diff --git a/tests/evm_asm/shl_truncate_overflow.expected b/tests/evm_asm/shl_truncate_overflow.expected new file mode 100644 index 00000000..e17295d5 --- /dev/null +++ b/tests/evm_asm/shl_truncate_overflow.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: 0000000000000000000000000000000000000000000000000000000000000000 +storage: {} +transient_storage: {} +return: 0000000000000000000000000000000000000000000000000000000000000000 +events: [] diff --git a/tests/evm_asm/shr.expected b/tests/evm_asm/shr.expected new file mode 100644 index 00000000..8597ccca --- /dev/null +++ b/tests/evm_asm/shr.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: 0000000000000000000000000000000000000000000000000000000000000002 +storage: {} +transient_storage: {} +return: 0000000000000000000000000000000000000000000000000000000000000002 +events: [] diff --git a/tests/evm_asm/shr_edge.expected b/tests/evm_asm/shr_edge.expected new file mode 100644 index 00000000..2dfe8d55 --- /dev/null +++ b/tests/evm_asm/shr_edge.expected @@ -0,0 +1,8 @@ +status: success +error_code: 0 +stack: [] +memory: 0000000000000000000000000000000000000000000000000000000000000001 +storage: {} +transient_storage: {} +return: 0000000000000000000000000000000000000000000000000000000000000001 +events: []