diff --git a/nimbus/core/validate.nim b/nimbus/core/validate.nim index b00145a95..ef11b3751 100644 --- a/nimbus/core/validate.nim +++ b/nimbus/core/validate.nim @@ -20,7 +20,7 @@ import stew/[objects, results] # chronicles stuff -when loggingEnabled or enabledLogLevel >= NONE: +when loggingEnabled or enabledLogLevel > NONE: import nimcrypto/utils diff --git a/nimbus/db/accounts_cache.nim b/nimbus/db/accounts_cache.nim index d7cb4a298..0eb8393a7 100644 --- a/nimbus/db/accounts_cache.nim +++ b/nimbus/db/accounts_cache.nim @@ -522,8 +522,8 @@ proc clearEmptyAccounts(ac: AccountsCache) = ac.deleteEmptyAccount(ripemdAddr) ac.ripemdSpecial = false -proc persist*(ac: AccountsCache, - clearEmptyAccount: bool = false, +proc persist*(ac: AccountsCache, + clearEmptyAccount: bool = false, clearCache: bool = true) = # make sure all savepoint already committed doAssert(ac.savePoint.parentSavepoint.isNil) @@ -531,7 +531,7 @@ proc persist*(ac: AccountsCache, if clearEmptyAccount: ac.clearEmptyAccounts() - + for address in ac.savePoint.selfDestruct: ac.deleteAccount(address) @@ -550,7 +550,10 @@ proc persist*(ac: AccountsCache, if not clearCache: cleanAccounts.incl address of DoNothing: - discard + # dead man tell no tales + # remove touched dead account from cache + if not clearCache and Alive notin acc.flags: + cleanAccounts.incl address acc.flags = acc.flags - resetFlags diff --git a/tools/t8n/helpers.nim b/tools/t8n/helpers.nim index 35771f0bb..0e4e4ab4b 100644 --- a/tools/t8n/helpers.nim +++ b/tools/t8n/helpers.nim @@ -85,6 +85,14 @@ proc fromJson(T: type Ommer, n: JsonNode): Ommer = address: fromJson(EthAddress, n, "address") ) +proc fromJson(T: type Withdrawal, n: JsonNode): Withdrawal = + Withdrawal( + index: fromJson(uint64, n, "index"), + validatorIndex: fromJson(uint64, n, "validatorIndex"), + address: fromJson(EthAddress, n, "address"), + amount: fromJson(uint64, n, "amount") + ) + template `gas=`(tx: var Transaction, x: GasInt) = tx.gasLimit = x @@ -165,6 +173,13 @@ proc parseEnv*(ctx: var TransContext, n: JsonNode) = for v in w: ctx.env.ommers.add Ommer.fromJson(v) + if n.hasKey("withdrawals"): + let w = n["withdrawals"] + var withdrawals: seq[Withdrawal] + for v in w: + withdrawals.add Withdrawal.fromJson(v) + ctx.env.withdrawals = some(withdrawals) + proc parseTx(n: JsonNode, chainId: ChainID): Transaction = var tx: Transaction if not n.hasKey("type"): @@ -397,3 +412,5 @@ proc `@@`*(x: ExecutionResult): JsonNode = result["rejected"] = @@(x.rejected) if x.currentBaseFee.isSome: result["currentBaseFee"] = @@(x.currentBaseFee) + if x.withdrawalsRoot.isSome: + result["withdrawalsRoot"] = @@(x.withdrawalsRoot) diff --git a/tools/t8n/t8n_test.nim b/tools/t8n/t8n_test.nim index 8882f9b49..597b3fb03 100644 --- a/tools/t8n/t8n_test.nim +++ b/tools/t8n/t8n_test.nim @@ -411,7 +411,16 @@ const ), output: T8nOutput(alloc: true, result: true), expOut: "exp.json", - ) + ), + TestSpec( + name : "Test withdrawals transition", + base : "testdata/26", + input : t8nInput( + "alloc.json", "txs.json", "env.json", "Shanghai", "" + ), + output: T8nOutput(alloc: true, result: true), + expOut: "exp.json", + ), ] proc main() = diff --git a/tools/t8n/testdata/26/alloc.json b/tools/t8n/testdata/26/alloc.json new file mode 100644 index 000000000..d67655a8a --- /dev/null +++ b/tools/t8n/testdata/26/alloc.json @@ -0,0 +1,8 @@ +{ + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0", + "code": "0x", + "nonce": "0xac", + "storage": {} + } +} diff --git a/tools/t8n/testdata/26/env.json b/tools/t8n/testdata/26/env.json new file mode 100644 index 000000000..03d817b93 --- /dev/null +++ b/tools/t8n/testdata/26/env.json @@ -0,0 +1,17 @@ +{ + "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": null, + "currentRandom": "0xdeadc0de", + "currentGasLimit": "0x750a163df65e8a", + "currentBaseFee": "0x500", + "currentNumber": "1", + "currentTimestamp": "1000", + "withdrawals": [ + { + "index": "0x42", + "validatorIndex": "0x42", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "amount": "0x2a" + } + ] +} diff --git a/tools/t8n/testdata/26/exp.json b/tools/t8n/testdata/26/exp.json new file mode 100644 index 000000000..4815e5cb6 --- /dev/null +++ b/tools/t8n/testdata/26/exp.json @@ -0,0 +1,20 @@ +{ + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x9c7652400", + "nonce": "0xac" + } + }, + "result": { + "stateRoot": "0x6e061c2f6513af27d267a0e3b07cb9a10f1ba3a0f65ab648d3a17c36e15021d2", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "currentDifficulty": null, + "gasUsed": "0x0", + "currentBaseFee": "0x500", + "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" + } +} diff --git a/tools/t8n/testdata/26/txs.json b/tools/t8n/testdata/26/txs.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tools/t8n/testdata/26/txs.json @@ -0,0 +1 @@ +[] diff --git a/tools/t8n/testdata/27/exp.json b/tools/t8n/testdata/27/exp.json new file mode 100644 index 000000000..5975a9c25 --- /dev/null +++ b/tools/t8n/testdata/27/exp.json @@ -0,0 +1,4 @@ +{ + "rlp": "0xf90239f9021aa0d6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082100082c3be83050785808455c5277e80a05865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf88000000000000000080a04921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5c0c0d9d8424394a94f5374fce5edbc8e2a8697c15331677e6ebf0b2a", + "hash": "0xdc42abd3698499675819e0a85cc1266f16da90277509b867446a6b25fa2b9d87" +} diff --git a/tools/t8n/testdata/27/header.json b/tools/t8n/testdata/27/header.json new file mode 100644 index 000000000..4ed7eaca0 --- /dev/null +++ b/tools/t8n/testdata/27/header.json @@ -0,0 +1,12 @@ +{ + "parentHash": "0xd6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34e", + "stateRoot": "0x325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2e", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x1000", + "number": "0xc3be", + "gasLimit": "0x50785", + "gasUsed": "0x0", + "timestamp": "0x55c5277e", + "mixHash": "0x5865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf", + "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" +} diff --git a/tools/t8n/testdata/27/ommers.json b/tools/t8n/testdata/27/ommers.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tools/t8n/testdata/27/ommers.json @@ -0,0 +1 @@ +[] diff --git a/tools/t8n/testdata/27/txs.rlp b/tools/t8n/testdata/27/txs.rlp new file mode 100644 index 000000000..e815397b3 --- /dev/null +++ b/tools/t8n/testdata/27/txs.rlp @@ -0,0 +1 @@ +"c0" diff --git a/tools/t8n/testdata/27/withdrawals.json b/tools/t8n/testdata/27/withdrawals.json new file mode 100644 index 000000000..6634aff08 --- /dev/null +++ b/tools/t8n/testdata/27/withdrawals.json @@ -0,0 +1,8 @@ +[ + { + "index": "0x42", + "validatorIndex": "0x43", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "amount": "0x2a" + } +] diff --git a/tools/t8n/transition.nim b/tools/t8n/transition.nim index 132b36e43..f2d7c1baa 100644 --- a/tools/t8n/transition.nim +++ b/tools/t8n/transition.nim @@ -9,7 +9,7 @@ # according to those terms. import - std/[json, strutils, times, tables, os], + std/[json, strutils, times, tables, os, math], eth/[rlp, trie, eip1559], stint, stew/results, "."/[config, types, helpers], @@ -82,6 +82,11 @@ proc dispatchOutput(ctx: var TransContext, conf: T8NConf, res: ExecOutput) = stderr.write(dis.stderr.pretty) stderr.write("\n") +proc calcWithdrawalsRoot(w: Option[seq[Withdrawal]]): Option[Hash256] = + if w.isNone: + return none(Hash256) + calcWithdrawalsRoot(w.get).some() + proc envToHeader(env: EnvStruct): BlockHeader = BlockHeader( coinbase : env.currentCoinbase, @@ -91,7 +96,8 @@ proc envToHeader(env: EnvStruct): BlockHeader = gasLimit : env.currentGasLimit, timestamp : env.currentTimestamp, stateRoot : emptyRlpHash, - fee : env.currentBaseFee + fee : env.currentBaseFee, + withdrawalsRoot: env.withdrawals.calcWithdrawalsRoot() ) proc postState(db: AccountsCache, alloc: var GenesisAlloc) = @@ -143,6 +149,9 @@ proc dumpTrace(txIndex: int, txHash: Hash256, traceResult: JsonNode) = let fName = "trace-$1-$2.jsonl" % [$txIndex, $txHash] writeFile(fName, traceResult.pretty) +func gwei(n: uint64): UInt256 = + n.u256 * (10 ^ 9).u256 + proc exec(ctx: var TransContext, vmState: BaseVMState, stateReward: Option[UInt256], @@ -221,6 +230,10 @@ proc exec(ctx: var TransContext, vmState.mutateStateDB: db.addBalance(ctx.env.currentCoinbase, mainReward) + if ctx.env.withdrawals.isSome: + for withdrawal in ctx.env.withdrawals.get: + vmState.stateDB.addBalance(withdrawal.address, withdrawal.amount.gwei) + let miner = ctx.env.currentCoinbase let fork = vmState.com.toEVMFork coinbaseStateClearing(vmState, miner, fork, stateReward.isSome()) @@ -239,7 +252,8 @@ proc exec(ctx: var TransContext, # therefore we cannot use vmState.difficulty currentDifficulty: ctx.env.currentDifficulty, gasUsed : vmState.cumulativeGasUsed, - currentBaseFee: ctx.env.currentBaseFee + currentBaseFee: ctx.env.currentBaseFee, + withdrawalsRoot: header.withdrawalsRoot ) template wrapException(body: untyped) = @@ -371,6 +385,9 @@ proc transitionAction*(ctx: var TransContext, conf: T8NConf) = else: raise newError(ErrorConfig, "EIP-1559 config but missing 'currentBaseFee' in env section") + if com.isShanghaiOrLater(ctx.env.currentTimestamp) and ctx.env.withdrawals.isNone: + raise newError(ErrorConfig, "Shanghai config but missing 'withdrawals' in env section") + if com.forkGTE(MergeFork): if ctx.env.currentRandom.isNone: raise newError(ErrorConfig, "post-merge requires currentRandom to be defined in env") diff --git a/tools/t8n/types.nim b/tools/t8n/types.nim index dcdd69901..05418007f 100644 --- a/tools/t8n/types.nim +++ b/tools/t8n/types.nim @@ -43,6 +43,7 @@ type parentBaseFee*: Option[UInt256] parentGasUsed*: Option[GasInt] parentGasLimit*: Option[GasInt] + withdrawals*: Option[seq[Withdrawal]] TxsType* = enum TxsNone @@ -90,6 +91,7 @@ type currentDifficulty*: Option[DifficultyInt] gasUsed*: GasInt currentBaseFee*: Option[UInt256] + withdrawalsRoot*: Option[Hash256] const ErrorEVM* = 2.T8NExitCode