diff --git a/nimbus/core/eip7702.nim b/nimbus/core/eip7702.nim index bf874b418..9cc5ab56c 100644 --- a/nimbus/core/eip7702.nim +++ b/nimbus/core/eip7702.nim @@ -22,7 +22,7 @@ const DelegationPrefix = [0xef.byte, 0x01, 0x00] const - PER_AUTH_BASE_COST* = 2500 + PER_AUTH_BASE_COST* = 12500 PER_EMPTY_ACCOUNT_COST* = 25000 func authority*(auth: Authorization): Opt[Address] = diff --git a/nimbus/core/executor/process_transaction.nim b/nimbus/core/executor/process_transaction.nim index 041158729..6938054f0 100644 --- a/nimbus/core/executor/process_transaction.nim +++ b/nimbus/core/executor/process_transaction.nim @@ -42,6 +42,7 @@ proc commitOrRollbackDependingOnGasUsed( tx: Transaction; gasBurned: GasInt; priorityFee: GasInt; + blobGasUsed: GasInt; ): Result[GasInt, string] = # Make sure that the tx does not exceed the maximum cumulative limit as # set in the block header. Again, the eip-1559 reference does not mention @@ -59,6 +60,7 @@ proc commitOrRollbackDependingOnGasUsed( # Return remaining gas to the block gas counter so it is # available for the next transaction. vmState.gasPool += tx.gasLimit - gasBurned + vmState.blobGasUsed += blobGasUsed ok(gasBurned) proc processTransactionImpl( @@ -85,11 +87,11 @@ proc processTransactionImpl( vmState.gasPool -= tx.gasLimit + # blobGasUsed will be added to vmState.blobGasUsed if the tx is ok. let blobGasUsed = tx.getTotalBlobGas if vmState.blobGasUsed + blobGasUsed > MAX_BLOB_GAS_PER_BLOCK: return err("blobGasUsed " & $blobGasUsed & " exceeds maximum allowance " & $MAX_BLOB_GAS_PER_BLOCK) - vmState.blobGasUsed += blobGasUsed # Actually, the eip-1559 reference does not mention an early exit. # @@ -110,7 +112,7 @@ proc processTransactionImpl( gasBurned = tx.txCallEvm(sender, vmState, baseFee) vmState.captureTxEnd(tx.gasLimit - gasBurned) - commitOrRollbackDependingOnGasUsed(vmState, accTx, header, tx, gasBurned, priorityFee) + commitOrRollbackDependingOnGasUsed(vmState, accTx, header, tx, gasBurned, priorityFee, blobGasUsed) else: err(txRes.error) diff --git a/nimbus/core/validate.nim b/nimbus/core/validate.nim index 79e9ae948..66f41d850 100644 --- a/nimbus/core/validate.nim +++ b/nimbus/core/validate.nim @@ -17,9 +17,8 @@ import ../transaction/call_types, ../transaction, ../utils/utils, - "."/[dao, eip4844, gaslimit, withdrawals], + "."/[dao, eip4844, eip7702, gaslimit, withdrawals], ./pow/[difficulty, header], - nimcrypto/utils as cryptoutils, stew/objects, results @@ -342,9 +341,11 @@ proc validateTransaction*( # Clients might choose to disable this rule for RPC calls like # `eth_call` and `eth_estimateGas` # EOA = Externally Owned Account - let codeHash = roDB.getCodeHash(sender) - if codeHash != EMPTY_CODE_HASH: - return err(&"invalid tx: sender is not an EOA. sender={sender.toHex}, codeHash={codeHash.data.toHex}") + let + code = roDB.getCode(sender) + delegated = code.parseDelegation() + if code.len > 0 and not delegated: + return err(&"invalid tx: sender is not an EOA. sender={sender.toHex}, codeLen={code.len}") if tx.txType == TxEip4844: # ensure that the user was willing to at least pay the current data gasprice diff --git a/nimbus/evm/computation.nim b/nimbus/evm/computation.nim index 14c1115be..c1c2ddfe0 100644 --- a/nimbus/evm/computation.nim +++ b/nimbus/evm/computation.nim @@ -22,8 +22,7 @@ import ../common/common, eth/common/eth_types_rlp, chronicles, chronos, - sets, - stew/assign2 + sets export common @@ -249,8 +248,7 @@ template resolveCode*(c: Computation, address: Address): CodeBytesRef = c.vmState.readOnlyStateDB.resolveCode(address) proc newComputation*(vmState: BaseVMState, sysCall: bool, message: Message, - salt: ContractSalt = ZERO_CONTRACTSALT, - authorizationList: openArray[Authorization] = []): Computation = + salt: ContractSalt = ZERO_CONTRACTSALT): Computation = new result result.vmState = vmState result.msg = message @@ -271,11 +269,9 @@ proc newComputation*(vmState: BaseVMState, sysCall: bool, message: Message, else: result.code = CodeStream.init( vmState.readOnlyStateDB.getCode(message.codeAddress)) - assign(result.authorizationList, authorizationList) func newComputation*(vmState: BaseVMState, sysCall: bool, - message: Message, code: CodeBytesRef, - authorizationList: openArray[Authorization] = []): Computation = + message: Message, code: CodeBytesRef): Computation = new result result.vmState = vmState result.msg = message @@ -285,7 +281,6 @@ func newComputation*(vmState: BaseVMState, sysCall: bool, result.gasMeter.init(message.gas) result.code = CodeStream.init(code) result.sysCall = sysCall - assign(result.authorizationList, authorizationList) template gasCosts*(c: Computation): untyped = c.vmState.gasCosts diff --git a/nimbus/evm/interpreter/op_handlers/oph_call.nim b/nimbus/evm/interpreter/op_handlers/oph_call.nim index cc49d86c5..3f2b226be 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_call.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_call.nim @@ -75,6 +75,20 @@ proc gasCallEIP2929(c: Computation, address: Address): GasInt = # the form of a constant `gasCall` return ColdAccountAccessCost - WarmStorageReadCost +proc delegateResolutionCost(c: Computation, address: Address): GasInt = + when evmc_enabled: + if c.host.accessAccount(address) == EVMC_ACCESS_COLD: + ColdAccountAccessCost + else: + WarmStorageReadCost + else: + c.vmState.mutateStateDB: + if not db.inAccessList(address): + db.accessList(address) + return ColdAccountAccessCost + else: + return WarmStorageReadCost + proc updateStackAndParams(q: var LocalParams; c: Computation) = c.stack.lsTop(0) @@ -99,7 +113,7 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) = if FkPrague <= c.fork: let delegateTo = parseDelegationAddress(c.getCode(q.codeAddress)) if delegateTo.isSome: - q.gasCallEIPs += gasCallEIP2929(c, delegateTo[]) + q.gasCallEIPs += delegateResolutionCost(c, delegateTo[]) proc callParams(c: Computation): EvmResult[LocalParams] = ## Helper for callOp() diff --git a/nimbus/evm/state_transactions.nim b/nimbus/evm/state_transactions.nim index def643081..135d3e25a 100644 --- a/nimbus/evm/state_transactions.nim +++ b/nimbus/evm/state_transactions.nim @@ -9,58 +9,14 @@ # according to those terms. import - ../core/eip7702, ../constants, - ../db/ledger, ./computation, ./interpreter_dispatch, - ./message, ./state, - ./types, - ./interpreter/gas_meter + ./types {.push raises: [].} -# Using `proc` as `incNonce()` might be `proc` in logging mode -proc preExecComputation(c: Computation) = - if not c.msg.isCreate: - c.vmState.mutateStateDB: - db.incNonce(c.msg.sender) - - # EIP-7702 - for auth in c.authorizationList: - # 1. Verify the chain id is either 0 or the chain's current ID. - if not(auth.chainId == 0.ChainId or auth.chainId == c.vmState.com.chainId): - continue - - # 2. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] - let authority = authority(auth).valueOr: - continue - - # 3. Add authority to accessed_addresses (as defined in EIP-2929.) - let ledger = c.vmState.stateDB - ledger.accessList(authority) - - # 4. Verify the code of authority is either empty or already delegated. - let code = ledger.getCode(authority) - if code.len > 0: - if not parseDelegation(code): - continue - - # 5. Verify the nonce of authority is equal to nonce. - if ledger.getNonce(authority) != auth.nonce: - continue - - # 6. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. - if ledger.accountExists(authority): - c.gasMeter.refundGas(PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) - - # 7. Set the code of authority to be 0xef0100 || address. This is a delegation designation. - ledger.setCode(authority, @(addressToDelegation(authority))) - - # 8. Increase the nonce of authority by one. - ledger.setNonce(authority, auth.nonce + 1) - proc postExecComputation(c: Computation) = if c.isSuccess: if c.fork < FkLondon: @@ -69,7 +25,6 @@ proc postExecComputation(c: Computation) = c.vmState.status = c.isSuccess proc execComputation*(c: Computation) = - c.preExecComputation() c.execCallOrCreate() c.postExecComputation() diff --git a/nimbus/evm/types.nim b/nimbus/evm/types.nim index 464840aef..7201d5975 100644 --- a/nimbus/evm/types.nim +++ b/nimbus/evm/types.nim @@ -93,7 +93,6 @@ type parent*, child*: Computation continuation*: proc(): EvmResultVoid {.gcsafe, raises: [].} sysCall*: bool - authorizationList*: seq[Authorization] Error* = ref object evmcStatus*: evmc_status_code diff --git a/nimbus/transaction/call_common.nim b/nimbus/transaction/call_common.nim index 507ecc569..37558ff74 100644 --- a/nimbus/transaction/call_common.nim +++ b/nimbus/transaction/call_common.nim @@ -18,6 +18,7 @@ import ../db/ledger, ../common/evmforks, ../core/eip4844, + ../core/eip7702, ./host_types, ./call_types @@ -61,6 +62,10 @@ proc initialAccessListEIP2929(call: CallParams) = # access list itself, after calculating the new contract address. if not call.isCreate: db.accessList(call.to) + # If the `call.to` has a delegation, also warm its target. + let target = parseDelegationAddress(db.getCode(call.to)) + if target.isSome: + db.accessList(target[]) # EIP3651 adds coinbase to the list of addresses that should start warm. if vmState.fork >= FkShanghai: @@ -76,6 +81,57 @@ proc initialAccessListEIP2929(call: CallParams) = for key in account.storageKeys: db.accessList(account.address, key.to(UInt256)) +proc preExecComputation(vmState: BaseVMState, call: CallParams): int64 = + var gasRefund = 0 + let ledger = vmState.stateDB + + if not call.isCreate: + ledger.incNonce(call.sender) + + # EIP-7702 + for auth in call.authorizationList: + # 1. Verify the chain id is either 0 or the chain's current ID. + if not(auth.chainId == 0.ChainId or auth.chainId == vmState.com.chainId): + continue + + # 2. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] + let authority = authority(auth).valueOr: + continue + + # 3. Add authority to accessed_addresses (as defined in EIP-2929.) + ledger.accessList(authority) + + # 4. Verify the code of authority is either empty or already delegated. + let code = ledger.getCode(authority) + if code.len > 0: + if not parseDelegation(code): + continue + + # 5. Verify the nonce of authority is equal to nonce. + if ledger.getNonce(authority) != auth.nonce: + continue + + # 6. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. + if ledger.accountExists(authority): + gasRefund += PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST + + # 7. Set the code of authority to be 0xef0100 || address. This is a delegation designation. + if auth.address == default(eth_types.Address): + ledger.setCode(authority, @[]) + else: + ledger.setCode(authority, @(addressToDelegation(auth.address))) + + # 8. Increase the nonce of authority by one. + ledger.setNonce(authority, auth.nonce + 1) + + # Usually the transaction destination and delegation target are added to + # the access list in initialAccessListEIP2929, however if the delegation is in + # the same transaction we need add here as to reduce calling slow ecrecover. + if call.to == authority: + ledger.accessList(auth.address) + + gasRefund + proc setupHost(call: CallParams): TransactionHost = let vmState = call.vmState vmState.txCtx = TxContext( @@ -104,6 +160,9 @@ proc setupHost(call: CallParams): TransactionHost = # All other defaults in `TransactionHost` are fine. ) + let gasRefund = if call.sysCall: 0 + else: preExecComputation(vmState, call) + # Generate new contract address, prepare code, and update message `recipient` # with the contract address. This differs from the previous Nimbus EVM API. # Guarded under `evmc_enabled` for now so it doesn't break vm2. @@ -132,9 +191,7 @@ proc setupHost(call: CallParams): TransactionHost = host.msg.input_data = host.input[0].addr let cMsg = hostToComputationMessage(host.msg) - host.computation = newComputation(vmState, call.sysCall, cMsg, code, - authorizationList = call.authorizationList) - + host.computation = newComputation(vmState, call.sysCall, cMsg, code) host.code = code else: @@ -146,9 +203,9 @@ proc setupHost(call: CallParams): TransactionHost = host.msg.input_data = host.input[0].addr let cMsg = hostToComputationMessage(host.msg) - host.computation = newComputation(vmState, call.sysCall, cMsg, - authorizationList = call.authorizationList) + host.computation = newComputation(vmState, call.sysCall, cMsg) + host.computation.gasMeter.refundGas(gasRefund) vmState.captureStart(host.computation, call.sender, call.to, call.isCreate, call.input, call.gasLimit, call.value) diff --git a/nimbus/transaction/call_types.nim b/nimbus/transaction/call_types.nim index ba9a3791b..59e31da53 100644 --- a/nimbus/transaction/call_types.nim +++ b/nimbus/transaction/call_types.nim @@ -14,6 +14,7 @@ import ../common/evmforks, ../evm/types, ../evm/internals, + ../core/eip7702, ./host_types type @@ -80,4 +81,7 @@ func intrinsicGas*(call: CallParams | Transaction, fork: EVMFork): GasInt = gas += ACCESS_LIST_ADDRESS_COST gas += GasInt(account.storageKeys.len) * ACCESS_LIST_STORAGE_KEY_COST + if fork >= FkPrague: + gas += call.authorizationList.len * PER_EMPTY_ACCOUNT_COST + return gas.GasInt diff --git a/tools/evmstate/helpers.nim b/tools/evmstate/helpers.nim index 756b30622..c5ea32741 100644 --- a/tools/evmstate/helpers.nim +++ b/tools/evmstate/helpers.nim @@ -50,6 +50,9 @@ template fromJson(T: type uint64, n: JsonNode): uint64 = template fromJson(T: type EthTime, n: JsonNode): EthTime = EthTime(fromHex[uint64](n.getStr)) +template fromJson(T: type ChainId, n: JsonNode): ChainId = + ChainId(fromHex[uint64](n.getStr)) + proc fromJson(T: type PrivateKey, n: JsonNode): PrivateKey = var secretKey = n.getStr removePrefix(secretKey, "0x") @@ -78,13 +81,13 @@ template required(T: type, nField: string): auto = template required(T: type, nField: string, index: int): auto = fromJson(T, n[nField][index]) -template omitZero(T: type, nField: string): auto = +template defaultZero(T: type, nField: string): auto = if n.hasKey(nField): fromJson(T, n[nField]) else: default(T) -template omitZero(T: type, nField: string, index: int): auto = +template defaultZero(T: type, nField: string, index: int): auto = if n.hasKey(nField): fromJson(T, n[nField][index]) else: @@ -96,7 +99,23 @@ template optional(T: type, nField: string): auto = else: Opt.none(T) +proc fromJson(T: type Authorization, n: JsonNode): Authorization = + Authorization( + chainId: required(ChainId, "chainId"), + address: required(Address, "address"), + nonce: required(AccountNonce, "nonce"), + v: required(uint64, "v"), + r: required(UInt256, "r"), + s: required(UInt256, "s"), + ) + +proc fromJson(T: type seq[Authorization], list: JsonNode): T = + for x in list: + result.add Authorization.fromJson(x) + proc txType(n: JsonNode): TxType = + if "authorizationList" in n: + return TxEip7702 if "blobVersionedHashes" in n: return TxEip4844 if "gasPrice" notin n: @@ -113,7 +132,7 @@ proc parseHeader*(n: JsonNode): Header = gasLimit : required(GasInt, "currentGasLimit"), timestamp : required(EthTime, "currentTimestamp"), stateRoot : emptyRoot, - mixHash : omitZero(Bytes32, "currentRandom"), + mixHash : defaultZero(Bytes32, "currentRandom"), baseFeePerGas : optional(UInt256, "currentBaseFee"), withdrawalsRoot: optional(Hash32, "currentWithdrawalsRoot"), excessBlobGas : optional(uint64, "currentExcessBlobGas"), @@ -135,12 +154,13 @@ proc parseTx*(n: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction = value : required(UInt256, "value", valueIndex), payload : required(seq[byte], "data", dataIndex), chainId : ChainId(1), - gasPrice: omitZero(GasInt, "gasPrice"), - maxFeePerGas : omitZero(GasInt, "maxFeePerGas"), - accessList : omitZero(AccessList, "accessLists", dataIndex), - maxPriorityFeePerGas: omitZero(GasInt, "maxPriorityFeePerGas"), - maxFeePerBlobGas : omitZero(UInt256, "maxFeePerBlobGas"), - versionedHashes : omitZero(seq[Hash32], "blobVersionedHashes") + gasPrice: defaultZero(GasInt, "gasPrice"), + maxFeePerGas : defaultZero(GasInt, "maxFeePerGas"), + accessList : defaultZero(AccessList, "accessLists", dataIndex), + maxPriorityFeePerGas: defaultZero(GasInt, "maxPriorityFeePerGas"), + maxFeePerBlobGas : defaultZero(UInt256, "maxFeePerBlobGas"), + versionedHashes : defaultZero(seq[Hash32], "blobVersionedHashes"), + authorizationList : defaultZero(seq[Authorization], "authorizationList"), ) let rawTo = n["to"].getStr diff --git a/tools/t8n/t8n_test.nim b/tools/t8n/t8n_test.nim index 7840402cd..6f22819fe 100644 --- a/tools/t8n/t8n_test.nim +++ b/tools/t8n/t8n_test.nim @@ -646,6 +646,24 @@ const output: T8nOutput(result: true), expOut: "exp3.json", ), + TestSpec( + name: "More cancun test, plus example of rlp-transaction that cannot be decoded properly", + base: "testdata/30", + input: t8nInput( + "alloc.json", "txs_more.rlp", "env.json", "Cancun", "", + ), + output: T8nOutput(alloc: true, result: true), + expOut: "exp.json", + ), + TestSpec( + name: "Prague test, EIP-7702 transaction", + base: "testdata/33", + input: t8nInput( + "alloc.json", "txs.json", "env.json", "Prague", "", + ), + output: T8nOutput(alloc: true, result: true), + expOut: "exp.json", + ), ] proc main() = diff --git a/tools/t8n/testdata/30/alloc.json b/tools/t8n/testdata/30/alloc.json new file mode 100644 index 000000000..6bc93d255 --- /dev/null +++ b/tools/t8n/testdata/30/alloc.json @@ -0,0 +1,23 @@ +{ + "0x095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x0de0b6b3a7640000", + "code" : "0x60004960005500", + "nonce" : "0x00", + "storage" : { + } + }, + "0xd02d72e067e77158444ef2020ff2d325f929b363" : { + "balance": "0x01000000000000", + "code": "0x", + "nonce": "0x01", + "storage": { + } + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x0de0b6b3a7640000", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } +} \ No newline at end of file diff --git a/tools/t8n/testdata/30/env.json b/tools/t8n/testdata/30/env.json new file mode 100644 index 000000000..4acd9794b --- /dev/null +++ b/tools/t8n/testdata/30/env.json @@ -0,0 +1,23 @@ +{ + "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentNumber" : "0x01", + "currentTimestamp" : "0x03e8", + "currentGasLimit" : "0x1000000000", + "previousHash" : "0xe4e2a30b340bec696242b67584264f878600dce98354ae0b6328740fd4ff18da", + "currentDataGasUsed" : "0x2000", + "parentTimestamp" : "0x00", + "parentDifficulty" : "0x00", + "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "parentBeaconBlockRoot" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentRandom" : "0x0000000000000000000000000000000000000000000000000000000000020000", + "withdrawals" : [ + ], + "parentBaseFee" : "0x08", + "parentGasUsed" : "0x00", + "parentGasLimit" : "0x1000000000", + "parentExcessBlobGas" : "0x1000", + "parentBlobGasUsed" : "0x2000", + "blockHashes" : { + "0" : "0xe4e2a30b340bec696242b67584264f878600dce98354ae0b6328740fd4ff18da" + } +} \ No newline at end of file diff --git a/tools/t8n/testdata/30/exp.json b/tools/t8n/testdata/30/exp.json new file mode 100644 index 000000000..9e7e0cf9a --- /dev/null +++ b/tools/t8n/testdata/30/exp.json @@ -0,0 +1,64 @@ +{ + "alloc": { + "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "code": "0x60004960005500", + "balance": "0xde0b6b3a7640000" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xde0b6b3a7640000" + }, + "0xd02d72e067e77158444ef2020ff2d325f929b363": { + "balance": "0xfffffffb8390", + "nonce": "0x3" + } + }, + "result": { + "stateRoot": "0x3483124b6710486c9fb3e07975669c66924697c88cccdcc166af5e1218915c93", + "txRoot": "0x013509c8563d41c0ae4bf38f2d6d19fc6512a1d0d6be045079c8c9f68bf45f9d", + "receiptsRoot": "0x75308898d571eafb5cd8cde8278bf5b3d13c5f6ec074926de3bb895b519264e1", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "type": "0x2", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + }, + { + "type": "0x2", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0xa410", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x2" + } + ], + "rejected": [ + { + "index": 1, + "error": "rlp: input string too short for common.Address, decoding into (types.Transaction)(types.BlobTx).To" + } + ], + "currentDifficulty": null, + "gasUsed": "0xa410", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "currentExcessBlobGas": "0x0", + "blobGasUsed": "0x0" + } +} \ No newline at end of file diff --git a/tools/t8n/testdata/30/txs_more.rlp b/tools/t8n/testdata/30/txs_more.rlp new file mode 100644 index 000000000..35af8d1f2 --- /dev/null +++ b/tools/t8n/testdata/30/txs_more.rlp @@ -0,0 +1 @@ +"0xf901adb86702f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904b8d903f8d601800285012a05f200833d090080830186a000f85bf85994095e7baea6a6c7c4c2dfeb977efac326af552d87f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d880a0fc12b67159a3567f8bdbc49e0be369a2e20e09d57a51c41310543a4128409464a02de0cfe5495c4f58ff60645ceda0afd67a4c90a70bc89fe207269435b35e5b67b86702f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9" \ No newline at end of file diff --git a/tools/t8n/testdata/33/alloc.json b/tools/t8n/testdata/33/alloc.json new file mode 100644 index 000000000..6874a6b33 --- /dev/null +++ b/tools/t8n/testdata/33/alloc.json @@ -0,0 +1,30 @@ +{ + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "nonce": "0x00", + "balance": "0x0de0b6b3a7640000", + "code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355", + "storage": { + "0x01": "0x0100", + "0x02": "0x0100", + "0x03": "0x0100" + } + }, + "0x000000000000000000000000000000000000aaaa": { + "nonce": "0x00", + "balance": "0x4563918244f40000", + "code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100", + "storage": {} + }, + "0x000000000000000000000000000000000000bbbb": { + "nonce": "0x00", + "balance": "0x29a2241af62c0000", + "code": "0x6042805500", + "storage": {} + }, + "0x71562b71999873DB5b286dF957af199Ec94617F7": { + "nonce": "0x00", + "balance": "0x6124fee993bc0000", + "code": "0x", + "storage": {} + } +} diff --git a/tools/t8n/testdata/33/env.json b/tools/t8n/testdata/33/env.json new file mode 100644 index 000000000..70bb7f981 --- /dev/null +++ b/tools/t8n/testdata/33/env.json @@ -0,0 +1,14 @@ +{ + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "71794957647893862", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "blockHashes": {}, + "ommers": [], + "currentBaseFee": "7", + "parentUncleHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "withdrawals": [], + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/tools/t8n/testdata/33/exp.json b/tools/t8n/testdata/33/exp.json new file mode 100644 index 000000000..af2c4dee7 --- /dev/null +++ b/tools/t8n/testdata/33/exp.json @@ -0,0 +1,70 @@ +{ + "alloc": { + "0x000000000000000000000000000000000000aaaa": { + "code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100", + "balance": "0x4563918244f40000" + }, + "0x000000000000000000000000000000000000bbbb": { + "code": "0x6042805500", + "balance": "0x29a2241af62c0000" + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x2bf52" + }, + "0x703c4b2bd70c169f5717101caee543299fc946c7": { + "code": "0xef0100000000000000000000000000000000000000bbbb", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000042": "0x0000000000000000000000000000000000000000000000000000000000000042" + }, + "balance": "0x1", + "nonce": "0x1" + }, + "0x71562b71999873db5b286df957af199ec94617f7": { + "code": "0xef0100000000000000000000000000000000000000aaaa", + "balance": "0x6124fee993afa30e", + "nonce": "0x2" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000100" + }, + "balance": "0xde0b6b3a7640000" + } + }, + "result": { + "stateRoot": "0x9fdcacd4510e93c4488e537dc51578b5c6d505771db64a2610036eeb4be7b26f", + "txRoot": "0x5d13a0b074e80388dc754da92b22922313a63417b3e25a10f324935e09697a53", + "receiptsRoot": "0x504c5d86c34391f70d210e6c482615b391db4bdb9f43479366399d9c5599850a", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "type": "0x4", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x15fa9", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x0417aab7c1d8a3989190c3167c132876ce9b8afd99262c5a0f9d06802de3d7ef", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15fa9", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x15fa9", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "requestsHash": "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f", + "requests": [ + "0x", + "0x", + "0x" + ] + } +} diff --git a/tools/t8n/testdata/33/txs.json b/tools/t8n/testdata/33/txs.json new file mode 100644 index 000000000..9c4db138c --- /dev/null +++ b/tools/t8n/testdata/33/txs.json @@ -0,0 +1,37 @@ +[ + { + "type": "0x4", + "chainId": "0x1", + "nonce": "0x0", + "to": "0x71562b71999873db5b286df957af199ec94617f7", + "gas": "0x7a120", + "gasPrice": null, + "maxPriorityFeePerGas": "0x2", + "maxFeePerGas": "0x12a05f200", + "value": "0x0", + "input": "0x", + "accessList": [], + "authorizationList": [ + { + "chainId": "0x1", + "address": "0x000000000000000000000000000000000000aaaa", + "nonce": "0x1", + "v": "0x1", + "r": "0xf7e3e597fc097e71ed6c26b14b25e5395bc8510d58b9136af439e12715f2d721", + "s": "0x6cf7c3d7939bfdb784373effc0ebb0bd7549691a513f395e3cdabf8602724987" + }, + { + "chainId": "0x0", + "address": "0x000000000000000000000000000000000000bbbb", + "nonce": "0x0", + "v": "0x1", + "r": "0x5011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98", + "s": "0x56c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf61" + } + ], + "secretKey": "0xb71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291", + "v": "0x0", + "r": "0x0", + "s": "0x0" + } +] diff --git a/tools/t8n/transition.nim b/tools/t8n/transition.nim index 58ab9bcc8..978b7801f 100644 --- a/tools/t8n/transition.nim +++ b/tools/t8n/transition.nim @@ -344,13 +344,16 @@ proc exec(ctx: TransContext, withdrawalsRoot : header.withdrawalsRoot ) - if vmState.com.isCancunOrLater(ctx.env.currentTimestamp): + var excessBlobGas = Opt.none(GasInt) + if ctx.env.currentExcessBlobGas.isSome: + excessBlobGas = ctx.env.currentExcessBlobGas + elif ctx.env.parentExcessBlobGas.isSome and ctx.env.parentBlobGasUsed.isSome: + excessBlobGas = Opt.some calcExcessBlobGas(vmState.parent) + + if excessBlobGas.isSome: result.result.blobGasUsed = Opt.some vmState.blobGasUsed - if ctx.env.currentExcessBlobGas.isSome: - result.result.currentExcessBlobGas = ctx.env.currentExcessBlobGas - elif ctx.env.parentExcessBlobGas.isSome and ctx.env.parentBlobGasUsed.isSome: - result.result.currentExcessBlobGas = Opt.some calcExcessBlobGas(vmState.parent) - + result.result.currentExcessBlobGas = excessBlobGas + if vmState.com.isPragueOrLater(ctx.env.currentTimestamp): var allLogs: seq[Log] for rec in result.result.receipts: