diff --git a/.github/workflows/e2e-evm-cron.yml b/.github/workflows/e2e-evm-cron.yml new file mode 100644 index 000000000..dd632068a --- /dev/null +++ b/.github/workflows/e2e-evm-cron.yml @@ -0,0 +1,54 @@ +name: EVM E2E Cron + +on: + schedule: + - cron: '0 * * * *' # every hour at 00 min + # cron syntax: https://jasonet.co/posts/scheduled-actions/ + +jobs: + # The "evm-e2e-cron" job runs end-to-end tests on a schedule against instances + # of Nibiru to ensure core functionality remains stable. This is intended to + # highlight any outage or catch degredations in public endpoint functionality + # early. Failures trigger immediate Slack notifications to alert the team. + # + # This workflow: + # 1. Executes basic EVM integration tests against the testnet + # 2. Uses a dedicated test wallet (configured via secrets) + # 3. Reports failures to the testnet Slack channel + # + # Environment requirements: + # - WALLET_MNEMONIC_TESTNET: Secret for test wallet access + # - SLACK_WEBHOOK_TESTNET: Webhook URL for failure notifications + evm-e2e-cron: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: "Install just" + # casey/just: https://just.systems/man/en/chapter_6.html + # taiki-e/install-action: https://github.com/taiki-e/install-action + uses: taiki-e/install-action@just + + - name: 'just install' + run: just install + working-directory: 'evm-e2e' + + - name: 'Run tests (just test-basic)' + run: just test-basic + working-directory: 'evm-e2e' + # 2024-11-12: We're using the Testnet 1 validator account because it has + # a lot of funds in NIBI. + env: + JSON_RPC_ENDPOINT: https://evm-rpc.testnet-1.nibiru.fi + MNEMONIC: ${{ secrets.MNEMONIC_TESTNET1_VALIDATOR }} + + - name: Send failure to slack channel + if: always() + uses: ravsamhq/notify-slack-action@v2 + with: + status: ${{ job.status }} + notify_when: 'failure' + notification_title: 'EVM basic tests failed on Testnet' + message_format: '{emoji} *{workflow}* {status_message} Run: {run_url}' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a684bd47..bf07037ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,9 +100,13 @@ tests for race conditions within funtoken precompile - [#2100](https://github.com/NibiruChain/nibiru/pull/2100) - refactor: cleanup statedb and precompile sections - [#2101](https://github.com/NibiruChain/nibiru/pull/2101) - fix(evm): tx receipt proper marshalling - [#2105](https://github.com/NibiruChain/nibiru/pull/2105) - test(evm): precompile call with revert -- [#2107](https://github.com/NibiruChain/nibiru/pull/2107) - -- [#2xxx](https://github.com/NibiruChain/nibiru/pull/2xxx) -feat(evm-funtoken-precompile): Implement methods: balance, bankBalance, whoAmI -fix(precompile-funtoken.go): Fixes a bug where the err != nil check is missing in the bankBalance precompile method +- [#2106](https://github.com/NibiruChain/nibiru/pull/2106) - chore: scheduled basic e2e tests for evm testnet endpoint +- [#2107](https://github.com/NibiruChain/nibiru/pull/2107) - feat(evm-funtoken-precompile): Implement methods: balance, bankBalance, whoAmI +- [#2108](https://github.com/NibiruChain/nibiru/pull/2108) - fix(evm): removed deprecated root key from eth_getTransactionReceipt +- [#2110](https://github.com/NibiruChain/nibiru/pull/2110) - fix(evm): Restore StateDB to its state prior to ApplyEvmMsg call to ensure deterministic gas usage. This fixes an issue where the StateDB pointer field in NibiruBankKeeper was being updated during readonly query endpoints like eth_estimateGas, leading to non-deterministic gas usage in subsequent transactions. +- [#2111](https://github.com/NibiruChain/nibiru/pull/2111) - fix: e2e-evm-cron.yml +- [#2114](https://github.com/NibiruChain/nibiru/pull/2114) - fix(evm): make gas cost zero in conditional bank keeper flow +- [#2116](https://github.com/NibiruChain/nibiru/pull/2116) - fix(precompile-funtoken.go): Fixes a bug where the err != nil check is missing in the bankBalance precompile method #### Nibiru EVM | Before Audit 1 - 2024-10-18 diff --git a/eth/rpc/backend/tx_info.go b/eth/rpc/backend/tx_info.go index f9817448a..ed0d45fee 100644 --- a/eth/rpc/backend/tx_info.go +++ b/eth/rpc/backend/tx_info.go @@ -167,6 +167,9 @@ func (r *TransactionReceipt) MarshalJSON() ([]byte, error) { if r.EffectiveGasPrice != nil { output["effectiveGasPrice"] = r.EffectiveGasPrice } + // delete deprecated (pre Byzantium) key which is always set to 0x and fails parsing within hardhat + delete(output, "root") + return json.Marshal(output) } diff --git a/evm-e2e/justfile b/evm-e2e/justfile index 042d02dc2..396488f58 100644 --- a/evm-e2e/justfile +++ b/evm-e2e/justfile @@ -16,6 +16,10 @@ install: test: npm test +# Runs tx receipt tests. Used for testnet quick check. +test-basic: + npm test -- tx_receipt.test.ts + # Format fmt: npm run format diff --git a/evm-e2e/test/tx_receipt.test.ts b/evm-e2e/test/tx_receipt.test.ts index adc91286a..7a95cd995 100644 --- a/evm-e2e/test/tx_receipt.test.ts +++ b/evm-e2e/test/tx_receipt.test.ts @@ -10,7 +10,7 @@ describe('Transaction Receipt Tests', () => { let recipient = ethers.Wallet.createRandom().address; it('simple transfer receipt', async () => { - const value = ethers.parseEther('1'); + const value = ethers.parseEther('0.0001'); const tx = await account.sendTransaction({ to: recipient, value, diff --git a/x/evm/keeper/bank_extension.go b/x/evm/keeper/bank_extension.go index da5221cbb..cb94ccc59 100644 --- a/x/evm/keeper/bank_extension.go +++ b/x/evm/keeper/bank_extension.go @@ -1,6 +1,7 @@ package keeper import ( + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" auth "github.com/cosmos/cosmos-sdk/x/auth/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -84,6 +85,14 @@ func (bk *NibiruBankKeeper) SyncStateDBWithAccount( if bk.StateDB == nil { return } + + cachedGasConfig := ctx.KVGasConfig() + defer func() { + ctx = ctx.WithKVGasConfig(cachedGasConfig) + }() + + // set gas cost to zero for this conditional operation + ctx = ctx.WithKVGasConfig(storetypes.GasConfig{}) balanceWei := evm.NativeToWei( bk.GetBalance(ctx, acc, evm.EVMBankDenom).Amount.BigInt(), ) diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 4e423e881..31a887bbc 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -454,7 +454,7 @@ func (k Keeper) EstimateGasForEvmCallType( return nil, fmt.Errorf("gas required exceeds allowance (%d)", gasCap) } - return nil, fmt.Errorf("Estimgate gas VMError: %s", result.VmError) + return nil, fmt.Errorf("Estimate gas VMError: %s", result.VmError) } } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 9914426fa..b7a3ec9a8 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -259,6 +259,12 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, vmErr error // vm errors do not effect consensus and are therefore not assigned to err ) + // save a reference to return to the previous stateDB + oldStateDb := k.Bank.StateDB + defer func() { + k.Bank.StateDB = oldStateDb + }() + stateDB := k.NewStateDB(ctx, txConfig) evmObj = k.NewEVM(ctx, msg, evmConfig, tracer, stateDB)