From 265d794583cd31b1d4993cceefe071685344b15d Mon Sep 17 00:00:00 2001 From: andri lim Date: Wed, 15 Jan 2025 09:18:25 +0700 Subject: [PATCH] devnet-5: Move EIP-7702 Authorization validation to authority func (#2999) * Move EIP-7702 Authorization validation to authority func If the authorization is invalid the transaction itself is still valid, the invalid authorization will be skipped. * Fix copyright year --- .../nodocker/engine/tx_sender.nim | 40 +++++++++++++++++- nimbus/core/eip7702.nim | 13 +++++- nimbus/core/validate.nim | 11 +---- tests/test_txpool.nim | 42 +++++++++++++++++++ 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/hive_integration/nodocker/engine/tx_sender.nim b/hive_integration/nodocker/engine/tx_sender.nim index 6553f8c19a..41128049fd 100644 --- a/hive_integration/nodocker/engine/tx_sender.nim +++ b/hive_integration/nodocker/engine/tx_sender.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2023-2024 Status Research & Development GmbH +# Copyright (c) 2023-2025 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) @@ -34,6 +34,7 @@ type blobGasFee*: UInt256 blobCount* : int blobID* : BlobID + authorizationList*: seq[Authorization] BigInitcodeTx* = object of BaseTx initcodeLength*: int @@ -75,6 +76,7 @@ type data* : Opt[seq[byte]] chainId* : Opt[ChainId] signature* : Opt[CustSig] + auth* : Opt[Authorization] const TestAccountCount = 1000 @@ -203,6 +205,21 @@ proc makeTxOfType(params: MakeTxParams, tc: BaseTx): PooledTransaction = proofs: blobData.proofs.mapIt(KzgProof it.bytes), ) ) + of TxEip7702: + PooledTransaction( + tx: Transaction( + txType : TxEip7702, + nonce : params.nonce, + gasLimit: tc.gasLimit, + maxFeePerGas: gasFeeCap, + maxPriorityFeePerGas: gasTipCap, + to : tc.recipient, + value : tc.amount, + payload : tc.payload, + chainId : params.chainId, + authorizationList: tc.authorizationList, + ) + ) else: raiseAssert "unsupported tx type" @@ -433,7 +450,7 @@ proc customizeTransaction*(sender: TxSender, if custTx.chainId.isSome: modTx.chainId = custTx.chainId.get - if baseTx.txType in {TxEip1559, TxEip4844}: + if baseTx.txType in {TxEip1559, TxEip4844, TxEip7702}: if custTx.gasPriceOrGasFeeCap.isSome: modTx.maxFeePerGas = custTx.gasPriceOrGasFeeCap.get.GasInt @@ -449,6 +466,11 @@ proc customizeTransaction*(sender: TxSender, doAssert(baseTx.txType == TxEip4844) modTx.maxFeePerBlobGas = custTx.blobGas.get + if custTx.auth.isSome: + doAssert(baseTx.txType == TxEip7702) + doAssert(baseTx.authorizationList.len > 0) + modTx.authorizationList[0] = custTx.auth.get + if custTx.signature.isSome: let signature = custTx.signature.get modTx.V = signature.V @@ -458,3 +480,17 @@ proc customizeTransaction*(sender: TxSender, modTx.signature = modTx.sign(acc.key, eip155 = true) modTx + +proc makeAuth*(sender: TxSender, acc: TestAccount, nonce: AccountNonce): Authorization = + var auth = Authorization( + chainId: sender.chainId, + address: acc.address, + nonce: nonce, + ) + let hash = auth.rlpHashForSigning() + let sig = sign(acc.key, SkMessage(hash.data)) + let raw = sig.toRaw() + + auth.r = UInt256.fromBytesBE(raw.toOpenArray(0, 31)) + auth.s = UInt256.fromBytesBE(raw.toOpenArray(32, 63)) + auth.v = raw[64].uint64 diff --git a/nimbus/core/eip7702.nim b/nimbus/core/eip7702.nim index 9cc5ab56c8..b232008f51 100644 --- a/nimbus/core/eip7702.nim +++ b/nimbus/core/eip7702.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2024 Status Research & Development GmbH +# Copyright (c) 2024-2025 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) @@ -12,6 +12,7 @@ import ../evm/code_bytes, + ../constants, results, stew/assign2, eth/common/eth_types, @@ -26,6 +27,16 @@ const PER_EMPTY_ACCOUNT_COST* = 25000 func authority*(auth: Authorization): Opt[Address] = + const SECP256K1halfN = SECPK1_N div 2 + + if auth.v > 1'u64: + # auth.v must be 0 or 1 + return Opt.none(Address) + + if auth.s > SECP256K1halfN: + # auth.s must be <= SECP256K1N/2 + return Opt.none(Address) + let sigHash = rlpHashForSigning(auth) var bytes: array[65, byte] diff --git a/nimbus/core/validate.nim b/nimbus/core/validate.nim index acf715e5a7..8448525618 100644 --- a/nimbus/core/validate.nim +++ b/nimbus/core/validate.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018-2024 Status Research & Development GmbH +# Copyright (c) 2018-2025 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) @@ -273,15 +273,6 @@ proc validateTxBasic*( if tx.authorizationList.len == 0: return err("invalid tx: authorization list must not empty") - const SECP256K1halfN = SECPK1_N div 2 - - for auth in tx.authorizationList: - if auth.v > 1'u64: - return err("invalid tx: auth.v must be 0 or 1") - - if auth.s > SECP256K1halfN: - return err("invalid tx: auth.s must be <= SECP256K1N/2") - ok() proc validateTransaction*( diff --git a/tests/test_txpool.nim b/tests/test_txpool.nim index 4f663a5a8d..ddae00a637 100644 --- a/tests/test_txpool.nim +++ b/tests/test_txpool.nim @@ -572,5 +572,47 @@ proc txPoolMain*() = inc count check count == hs.len + test "EIP-7702 transaction before Prague": + let + acc = mx.getAccount(24) + auth = mx.makeAuth(acc, 0) + tc = BaseTx( + txType: Opt.some(TxEip7702), + gasLimit: 75000, + recipient: Opt.some(recipient214), + amount: amount, + authorizationList: @[auth], + ) + tx = mx.makeTx(tc, 0) + + xp.checkAddTx(tx, txErrorBasicValidation) + + test "EIP-7702 transaction invalid auth signature": + let + env = initEnv(Prague) + xp = env.xp + mx = env.sender + acc = mx.getAccount(25) + auth = mx.makeAuth(acc, 0) + tc = BaseTx( + txType: Opt.some(TxEip7702), + gasLimit: 75000, + recipient: Opt.some(recipient214), + amount: amount, + authorizationList: @[auth], + ) + ptx = mx.makeTx(tc, 0) + + # invalid auth + var invauth = auth + invauth.v = 3.uint64 + let + ctx = CustomTx(auth: Opt.some(invauth)) + tx = mx.customizeTransaction(acc, ptx.tx, ctx) + + xp.checkAddTx(tx) + # invalid auth, but the tx itself still valid + xp.checkImportBlock(1, 0) + when isMainModule: txPoolMain()