From 1a21f86ac743d6b3006f8cf5bcaa90bf77e1a083 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Mon, 19 Aug 2024 04:22:02 +0200 Subject: [PATCH] vm: 7702: correctly handle self-sponsored txs [no ci] --- packages/vm/src/runTx.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 1fce1d8b6a..c9f5f8a3a1 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -7,6 +7,7 @@ import { Account, Address, BIGINT_0, + BIGINT_1, KECCAK256_NULL, bytesToBigInt, bytesToHex, @@ -292,8 +293,21 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { } // EIP-3607: Reject transactions from senders with deployed code if (vm.common.isActivatedEIP(3607) && !equalsBytes(fromAccount.codeHash, KECCAK256_NULL)) { - const msg = _errorMsg('invalid sender address, address is not EOA (EIP-3607)', vm, block, tx) - throw new Error(msg) + if (vm.common.isActivatedEIP(7702)) { + const code = await state.getCode(caller) + if (!equalsBytes(code.slice(0, 3), new Uint8Array([0xef, 0x01, 0x00]))) { + const msg = _errorMsg( + 'invalid sender address, address is not EOA (EIP-3607)', + vm, + block, + tx, + ) + throw new Error(msg) + } + } else { + const msg = _errorMsg('invalid sender address, address is not EOA (EIP-3607)', vm, block, tx) + throw new Error(msg) + } } // Check balance against upfront tx cost @@ -464,14 +478,23 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { continue } } - if (account.nonce !== bytesToBigInt(nonce)) { + + // Nonce check + if (caller.toString() === authority.toString()) { + if (account.nonce + BIGINT_1 !== bytesToBigInt(nonce)) { + // Edge case: caller is the authority, so is self-signing the delegation + // In this case, we "virtually" bump the account nonce by one + // We CANNOT put this updated nonce into the account trie, because then + // the EVM will bump the nonce once again, thus resulting in a wrong nonce + continue + } + } else if (account.nonce !== bytesToBigInt(nonce)) { continue } if (accountExists) { const refund = tx.common.param('perEmptyAccountCost') - tx.common.param('perAuthBaseGas') gasRefund += refund - await vm.evm.journal.putAccount(caller, fromAccount) } account.nonce++