From 283271a6e35e588ed0f381787c0ab8e9d3b52b10 Mon Sep 17 00:00:00 2001 From: jangko Date: Mon, 4 Dec 2023 09:55:31 +0700 Subject: [PATCH] Fix unhandled overflow exception in gasCall --- .github/workflows/ci.yml | 10 ++-- nimbus/evm/interpreter/gas_costs.nim | 6 ++- tests/all_tests.nim | 3 +- tests/all_tests_macro.nim | 2 +- tests/test_overflow.nim | 76 ++++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 tests/test_overflow.nim diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 715e7f1660..b7a1824238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,11 +15,11 @@ on: - 'doc/**' - 'docs/**' - '**/*.md' - 'hive_integration/**' - 'fluffy/**' - '.github/workflows/fluffy*.yml' - 'nimbus_verified_proxy/**' - '.github/workflows/nimbus_verified_proxy.yml' + - 'hive_integration/**' + - 'fluffy/**' + - '.github/workflows/fluffy*.yml' + - 'nimbus_verified_proxy/**' + - '.github/workflows/nimbus_verified_proxy.yml' # Disable `pull_request`. Experimenting with using only `push` for PRs. #pull_request: diff --git a/nimbus/evm/interpreter/gas_costs.nim b/nimbus/evm/interpreter/gas_costs.nim index 332784e8cb..a9670278ad 100644 --- a/nimbus/evm/interpreter/gas_costs.nim +++ b/nimbus/evm/interpreter/gas_costs.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018 Status Research & Development GmbH +# Copyright (c) 2018-2023 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) # * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) @@ -508,6 +508,10 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = raise newException(TypeError, "GasInt Overflow (" & $gasParams.kind & ") " & $gasParams.c_contractGas) result.gasRefund = gasParams.c_contractGas.truncate(GasInt) + if result.gasCost.u256 + result.gasRefund.u256 > high(GasInt).u256: + raise newException(TypeError, "GasInt overflow, gasCost=" & + $result.gasCost & ", gasRefund=" & $result.gasRefund) + result.gasCost += result.gasRefund # Ccallgas - Gas sent to the child message diff --git a/tests/all_tests.nim b/tests/all_tests.nim index b90cd9d4fb..8f81ba4551 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -51,4 +51,5 @@ cliBuilder: ./test_txpool, ./test_merge, ./test_eip4844, - ./test_beacon/test_skeleton + ./test_beacon/test_skeleton, + ./test_overflow diff --git a/tests/all_tests_macro.nim b/tests/all_tests_macro.nim index 538dcf9353..1b657a05b9 100644 --- a/tests/all_tests_macro.nim +++ b/tests/all_tests_macro.nim @@ -88,7 +88,7 @@ macro cliBuilder*(stmtList: typed): untyped = `caseStmt` # if you want to add new test module(s) -# make sure you define an entry poin +# make sure you define an entry point # e.g. # proc mytestMain*() = # # put anything you want here diff --git a/tests/test_overflow.nim b/tests/test_overflow.nim new file mode 100644 index 0000000000..3c0490a230 --- /dev/null +++ b/tests/test_overflow.nim @@ -0,0 +1,76 @@ +# Nimbus +# Copyright (c) 2023 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or +# http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or +# http://opensource.org/licenses/MIT) +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. + +import eth/keys +import stew/byteutils +import unittest2 +import ../nimbus/common +import ../nimbus/vm_state +import ../nimbus/vm_types +import ../nimbus/transaction +import ../nimbus/transaction/call_evm +import ../nimbus/db/core_db +import ../nimbus/db/accounts_cache + +const + data = [0x5b.uint8, 0x5a, 0x5a, 0x30, 0x30, 0x30, 0x30, 0x72, 0x00, 0x00, 0x00, 0x58, + 0x58, 0x24, 0x58, 0x58, 0x3a, 0x19, 0x75, 0x75, 0x2e, 0x2e, 0x2e, 0x2e, + 0xec, 0x9f, 0x69, 0x67, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x6c, 0x5a, 0x32, + 0x07, 0xf4, 0x75, 0x75, 0xf5, 0x75, 0x75, 0x75, 0x7f, 0x5b, 0xd9, 0x32, + 0x5a, 0x07, 0x19, 0x34, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xec, + 0x9f, 0x69, 0x67, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x6c, 0xfc, 0xf7, 0xfc, + 0xfc, 0xfc, 0xfc, 0xf4, 0x03, 0x03, 0x81, 0x81, 0x81, 0xfb, 0x7a, 0x30, + 0x80, 0x3d, 0x59, 0x59, 0x59, 0x59, 0x81, 0x00, 0x59, 0x2f, 0x45, 0x30, + 0x32, 0xf4, 0x5d, 0x5b, 0x37, 0x19] + + codeAddress = hexToByteArray[20]("000000000000000000000000636f6e7472616374") + coinbase = hexToByteArray[20]("4444588443C3a91288c5002483449Aba1054192b") + +proc overflowMain*() = + test "GasCall unhandled overflow": + let header = BlockHeader( + blockNumber: u256(1150000), + coinBase: coinbase, + gasLimit: 30000000, + timeStamp: EthTime(123456), + ) + + let com = CommonRef.new(newCoreDbRef(LegacyDbMemory), config = chainConfigForNetwork(MainNet)) + + let s = BaseVMState.new( + header, + header, + com, + ) + + s.stateDB.setCode(codeAddress, @data) + let unsignedTx = Transaction( + txType: TxLegacy, + nonce: 0, + chainId: MainNet.ChainId, + gasPrice: 0.GasInt, + gasLimit: 30000000, + to: codeAddress.some, + value: 0.u256, + payload: @data + ) + + let privateKey = PrivateKey.fromHex("0000000000000000000000000000000000000000000000000000001000000000")[] + let tx = signTransaction(unsignedTx, privateKey, ChainId(1), false) + let res = testCallEvm(tx, tx.getSender, s, FkHomestead) + when defined(evmc_enabled): + check res.error == "EVMC_FAILURE" + else: + check res.error == "Opcode Dispatch Error: GasInt overflow, gasCost=2199123918888, gasRefund=9223372036845099570, depth=1" + +when isMainModule: + overflowMain()