From 16bc2de1cffd509c823d33ccc7582a8bdfe54bdd Mon Sep 17 00:00:00 2001 From: jangko Date: Mon, 26 Sep 2022 23:14:12 +0700 Subject: [PATCH] update EF test fixtures and fixes to pass all tests --- .../consensus/extract_consensus_data.nim | 35 +++++- newBlockchainTests.md | 54 +++++++-- newGeneralStateTests.md | 27 +++-- nimbus/chain_config.nim | 3 + nimbus/db/accounts_cache.nim | 18 +++ nimbus/db/db_chain.nim | 15 ++- nimbus/genesis.nim | 7 +- nimbus/p2p/chain/chain_desc.nim | 12 +- nimbus/p2p/validate.nim | 4 + nimbus/vm2/interpreter/op_handlers.nim | 1 + tests/test_blockchain_json.nim | 106 +++++++++++++++--- tests/test_generalstate_json.nim | 27 +++-- tests/test_helpers.nim | 6 +- 13 files changed, 252 insertions(+), 63 deletions(-) diff --git a/hive_integration/nodocker/consensus/extract_consensus_data.nim b/hive_integration/nodocker/consensus/extract_consensus_data.nim index 6d96c8f63..d3c31d637 100644 --- a/hive_integration/nodocker/consensus/extract_consensus_data.nim +++ b/hive_integration/nodocker/consensus/extract_consensus_data.nim @@ -8,7 +8,7 @@ # those terms. import - std/[json, strutils], + std/[json, strutils, options], stew/byteutils type @@ -42,6 +42,8 @@ proc processNetwork(network: string): JsonNode = berlinBlock = 2000 londonBlock = 2000 arrowGlacierBlock = 2000 + mergeForkBlock = none(int) + ttd = none(int) case network @@ -116,6 +118,20 @@ proc processNetwork(network: string): JsonNode = berlinBlock = 0 londonBlock = 0 arrowGlacierBlock = 0 + of "Merge": + homesteadBlock = 0 + eip150Block = 0 + eip158Block = 0 + byzantiumBlock = 0 + constantinopleBlock = 0 + petersburgBlock = 0 + istanbulBlock = 0 + muirGlacierBlock = 0 + berlinBlock = 0 + londonBlock = 0 + arrowGlacierBlock = 0 + mergeForkBlock = some(0) + ttd = some(0) # Just the subset of "At5" networks mentioned in the test suite. of "FrontierToHomesteadAt5": @@ -150,6 +166,19 @@ proc processNetwork(network: string): JsonNode = muirGlacierBlock = 0 berlinBlock = 0 londonBlock = 5 + of "ArrowGlacierToMergeAtDiffC0000": + homesteadBlock = 0 + eip150Block = 0 + eip158Block = 0 + byzantiumBlock = 0 + constantinopleBlock = 0 + petersburgBlock = 0 + istanbulBlock = 0 + muirGlacierBlock = 0 + berlinBlock = 0 + londonBlock = 0 + arrowGlacierBlock = 0 + ttd = some(0xC0000) else: doAssert(false, "unsupported network: " & network) @@ -169,7 +198,11 @@ proc processNetwork(network: string): JsonNode = n["berlinBlock"] = newJInt(berlinBlock) n["londonBlock"] = newJInt(londonBlock) n["arrowGlacierBlock"] = newJInt(arrowGlacierBlock) + if mergeForkBlock.isSome: + n["mergeForkBlock"] = newJInt(mergeForkBlock.get()) n["chainId"] = newJInt(1) + if ttd.isSome: + n["terminalTotalDifficulty"] = newJString("0x" & ttd.get().toHex(8)) result = n proc optionalField(n: string, genesis, gen: JsonNode) = diff --git a/newBlockchainTests.md b/newBlockchainTests.md index da49b9e91..4214f5e56 100644 --- a/newBlockchainTests.md +++ b/newBlockchainTests.md @@ -1,5 +1,12 @@ newBlockchainTests === +## bcArrowGlacierToMerge +```diff ++ difficultyFormula.json OK ++ powToPosBlockRejection.json OK ++ powToPosTest.json OK +``` +OK: 3/3 Fail: 0/3 Skip: 0/3 ## bcBerlinToLondon ```diff + BerlinToLondonTransition.json OK @@ -29,6 +36,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + baseFee.json OK + besuBaseFeeBug.json OK + burnVerify.json OK ++ burnVerifyLondon.json OK + checkGasLimit.json OK + feeCap.json OK + gasLimit20m.json OK @@ -40,21 +48,29 @@ OK: 1/1 Fail: 0/1 Skip: 0/1 + lowDemand.json OK + medDemand.json OK + tips.json OK ++ tipsLondon.json OK + transFail.json OK + transType.json OK + valCausesOOF.json OK ``` -OK: 19/19 Fail: 0/19 Skip: 0/19 +OK: 21/21 Fail: 0/21 Skip: 0/21 ## bcEIP158ToByzantium ```diff + ByzantiumTransition.json OK ``` OK: 1/1 Fail: 0/1 Skip: 0/1 +## bcEIP3675 +```diff ++ timestampPerBlock.json OK ++ tipInsideBlock.json OK +``` +OK: 2/2 Fail: 0/2 Skip: 0/2 ## bcExample ```diff + basefeeExample.json OK ++ mergeExample.json OK ``` -OK: 1/1 Fail: 0/1 Skip: 0/1 +OK: 2/2 Fail: 0/2 Skip: 0/2 ## bcExploitTest ```diff DelegateCallSpam.json Skip @@ -266,6 +282,7 @@ OK: 96/96 Fail: 0/96 Skip: 0/96 + RefundOverflow.json OK + RefundOverflow2.json OK + SuicidesMixingCoinbase.json OK ++ SuicidesMixingCoinbase2.json OK + TransactionFromCoinbaseHittingBlockGasLimit1.json OK + TransactionFromCoinbaseNotEnoughFounds.json OK + TransactionNonceCheck.json OK @@ -299,6 +316,7 @@ OK: 96/96 Fail: 0/96 Skip: 0/96 + extcodehashEmptySuicide.json OK + logRevert.json OK + multimpleBalanceInstruction.json OK ++ random.json OK + randomStatetest123.json OK + randomStatetest136.json OK + randomStatetest160.json OK @@ -344,7 +362,7 @@ OK: 96/96 Fail: 0/96 Skip: 0/96 + transactionFromSelfDestructedContract.json OK + txCost-sec73.json OK ``` -OK: 87/88 Fail: 0/88 Skip: 1/88 +OK: 89/90 Fail: 0/90 Skip: 1/90 ## bcTotalDifficultyTest ```diff + lotsOfBranchesOverrideAtTheEnd.json OK @@ -405,6 +423,7 @@ OK: 9/9 Fail: 0/9 Skip: 0/9 ## bcUncleTest ```diff + EqualUncleInTwoDifferentBlocks.json OK ++ EqualUncleInTwoDifferentBlocks2.json OK + InChainUncle.json OK + InChainUncleFather.json OK + InChainUncleGrandPa.json OK @@ -427,7 +446,7 @@ OK: 9/9 Fail: 0/9 Skip: 0/9 + uncleHeaderWithGeneration0.json OK + uncleWithSameBlockNumber.json OK ``` -OK: 22/22 Fail: 0/22 Skip: 0/22 +OK: 23/23 Fail: 0/23 Skip: 0/23 ## bcValidBlockTest ```diff + ExtraData32.json OK @@ -730,8 +749,9 @@ OK: 5/5 Fail: 0/5 Skip: 0/5 + callcodecallcodecallcode_111_SuicideEnd.json OK + callcodecallcodecallcode_111_SuicideMiddle.json OK callcodecallcodecallcode_ABCB_RECURSIVE.json Skip ++ touchAndGo.json OK ``` -OK: 72/79 Fail: 0/79 Skip: 7/79 +OK: 73/80 Fail: 0/80 Skip: 7/80 ## stCallCreateCallCodeTest ```diff Call1024BalanceTooLow.json Skip @@ -1006,6 +1026,7 @@ OK: 51/52 Fail: 0/52 Skip: 1/52 + CREATE_HighNonceMinus1.json OK + CREATE_empty000CreateinInitCode_Transaction.json OK + CodeInConstructor.json OK ++ CreateAddressWarmAfterFail.json OK + CreateCollisionResults.json OK + CreateCollisionToEmpty.json OK + CreateOOGFromCallRefunds.json OK @@ -1019,12 +1040,14 @@ OK: 51/52 Fail: 0/52 Skip: 1/52 + CreateOOGafterInitCodeRevert2.json OK + CreateOOGafterMaxCodesize.json OK + CreateResults.json OK ++ CreateTransactionHighNonce.json OK + TransactionCollisionToEmpty.json OK + TransactionCollisionToEmptyButCode.json OK + TransactionCollisionToEmptyButNonce.json OK + createFailResult.json OK ++ createLargeResult.json OK ``` -OK: 41/41 Fail: 0/41 Skip: 0/41 +OK: 44/44 Fail: 0/44 Skip: 0/44 ## stDelegatecallTestHomestead ```diff Call1024BalanceTooLow.json Skip @@ -1128,12 +1151,13 @@ OK: 40/40 Fail: 0/40 Skip: 0/40 + lowGasPriceOldTypes.json OK + outOfFunds.json OK + outOfFundsOldTypes.json OK ++ senderBalance.json OK + tipTooHigh.json OK + transactionIntinsicBug.json OK + typeTwoBerlin.json OK + valCausesOOF.json OK ``` -OK: 12/12 Fail: 0/12 Skip: 0/12 +OK: 13/13 Fail: 0/13 Skip: 0/13 ## stEIP158Specific ```diff + CALL_OneVCallSuicide.json OK @@ -1175,11 +1199,12 @@ OK: 5/5 Fail: 0/5 Skip: 0/5 + indexesOmitExample.json OK + invalidTr.json OK + labelsExample.json OK ++ mergeTest.json OK + rangesExample.json OK + solidityExample.json OK + yulExample.json OK ``` -OK: 11/11 Fail: 0/11 Skip: 0/11 +OK: 12/12 Fail: 0/12 Skip: 0/12 ## stExtCodeHash ```diff + callToNonExistent.json OK @@ -1457,6 +1482,7 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 ## stPreCompiledContracts ```diff + blake2B.json OK ++ delegatecall09Undefined.json OK + idPrecomps.json OK + identity_to_bigger.json OK + identity_to_smaller.json OK @@ -1465,7 +1491,7 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 + precompsEIP2929.json OK + sec80.json OK ``` -OK: 8/8 Fail: 0/8 Skip: 0/8 +OK: 9/9 Fail: 0/9 Skip: 0/9 ## stPreCompiledContracts2 ```diff + CALLBlake2f.json OK @@ -1533,6 +1559,7 @@ OK: 8/8 Fail: 0/8 Skip: 0/8 + CallEcrecoverS_prefixed0.json OK + CallEcrecoverUnrecoverableKey.json OK + CallEcrecoverV_prefixed0.json OK ++ CallEcrecover_Overflow.json OK + CallIdentitiy_0.json OK + CallIdentitiy_1.json OK + CallIdentity_1_nonzeroValue.json OK @@ -1562,13 +1589,15 @@ OK: 8/8 Fail: 0/8 Skip: 0/8 + CallSha256_4.json OK + CallSha256_4_gas99.json OK + CallSha256_5.json OK ++ ecrecoverShortBuff.json OK ++ ecrecoverWeirdV.json OK + modexpRandomInput.json OK + modexp_0_0_0_20500.json OK + modexp_0_0_0_22000.json OK + modexp_0_0_0_25000.json OK + modexp_0_0_0_35000.json OK ``` -OK: 99/99 Fail: 0/99 Skip: 0/99 +OK: 102/102 Fail: 0/102 Skip: 0/102 ## stQuadraticComplexityTest ```diff Call1MB1024Calldepth.json Skip @@ -2772,6 +2801,7 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + currentAccountBalance.json OK + doubleSelfdestructTest.json OK + doubleSelfdestructTest2.json OK ++ doubleSelfdestructTouch.json OK + extcodecopy.json OK + return0.json OK + return1.json OK @@ -2786,7 +2816,7 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + suicideSendEtherToMe.json OK + testRandomTest.json OK ``` -OK: 56/66 Fail: 0/66 Skip: 10/66 +OK: 57/67 Fail: 0/67 Skip: 10/67 ## stTimeConsuming ```diff CALLBlake2f_MaxRounds.json Skip @@ -3306,4 +3336,4 @@ OK: 0/3 Fail: 0/3 Skip: 3/3 OK: 11/11 Fail: 0/11 Skip: 0/11 ---TOTAL--- -OK: 2859/2964 Fail: 0/2964 Skip: 105/2964 +OK: 2881/2986 Fail: 0/2986 Skip: 105/2986 diff --git a/newGeneralStateTests.md b/newGeneralStateTests.md index 8be5311b7..ed4e7bec6 100644 --- a/newGeneralStateTests.md +++ b/newGeneralStateTests.md @@ -271,8 +271,9 @@ OK: 5/5 Fail: 0/5 Skip: 0/5 + callcodecallcodecallcode_111_SuicideEnd.json OK + callcodecallcodecallcode_111_SuicideMiddle.json OK callcodecallcodecallcode_ABCB_RECURSIVE.json Skip ++ touchAndGo.json OK ``` -OK: 72/79 Fail: 0/79 Skip: 7/79 +OK: 73/80 Fail: 0/80 Skip: 7/80 ## stCallCreateCallCodeTest ```diff Call1024BalanceTooLow.json Skip @@ -547,6 +548,7 @@ OK: 51/52 Fail: 0/52 Skip: 1/52 + CREATE_HighNonceMinus1.json OK + CREATE_empty000CreateinInitCode_Transaction.json OK + CodeInConstructor.json OK ++ CreateAddressWarmAfterFail.json OK + CreateCollisionResults.json OK + CreateCollisionToEmpty.json OK + CreateOOGFromCallRefunds.json OK @@ -560,12 +562,14 @@ OK: 51/52 Fail: 0/52 Skip: 1/52 + CreateOOGafterInitCodeRevert2.json OK + CreateOOGafterMaxCodesize.json OK + CreateResults.json OK ++ CreateTransactionHighNonce.json OK + TransactionCollisionToEmpty.json OK + TransactionCollisionToEmptyButCode.json OK + TransactionCollisionToEmptyButNonce.json OK + createFailResult.json OK ++ createLargeResult.json OK ``` -OK: 41/41 Fail: 0/41 Skip: 0/41 +OK: 44/44 Fail: 0/44 Skip: 0/44 ## stDelegatecallTestHomestead ```diff Call1024BalanceTooLow.json Skip @@ -669,12 +673,13 @@ OK: 40/40 Fail: 0/40 Skip: 0/40 + lowGasPriceOldTypes.json OK + outOfFunds.json OK + outOfFundsOldTypes.json OK ++ senderBalance.json OK + tipTooHigh.json OK + transactionIntinsicBug.json OK + typeTwoBerlin.json OK + valCausesOOF.json OK ``` -OK: 12/12 Fail: 0/12 Skip: 0/12 +OK: 13/13 Fail: 0/13 Skip: 0/13 ## stEIP158Specific ```diff + CALL_OneVCallSuicide.json OK @@ -716,11 +721,12 @@ OK: 5/5 Fail: 0/5 Skip: 0/5 + indexesOmitExample.json OK + invalidTr.json OK + labelsExample.json OK ++ mergeTest.json OK + rangesExample.json OK + solidityExample.json OK + yulExample.json OK ``` -OK: 11/11 Fail: 0/11 Skip: 0/11 +OK: 12/12 Fail: 0/12 Skip: 0/12 ## stExtCodeHash ```diff + callToNonExistent.json OK @@ -998,6 +1004,7 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 ## stPreCompiledContracts ```diff + blake2B.json OK ++ delegatecall09Undefined.json OK + idPrecomps.json OK + identity_to_bigger.json OK + identity_to_smaller.json OK @@ -1006,7 +1013,7 @@ OK: 24/24 Fail: 0/24 Skip: 0/24 + precompsEIP2929.json OK + sec80.json OK ``` -OK: 8/8 Fail: 0/8 Skip: 0/8 +OK: 9/9 Fail: 0/9 Skip: 0/9 ## stPreCompiledContracts2 ```diff + CALLBlake2f.json OK @@ -1074,6 +1081,7 @@ OK: 8/8 Fail: 0/8 Skip: 0/8 + CallEcrecoverS_prefixed0.json OK + CallEcrecoverUnrecoverableKey.json OK + CallEcrecoverV_prefixed0.json OK ++ CallEcrecover_Overflow.json OK + CallIdentitiy_0.json OK + CallIdentitiy_1.json OK + CallIdentity_1_nonzeroValue.json OK @@ -1103,13 +1111,15 @@ OK: 8/8 Fail: 0/8 Skip: 0/8 + CallSha256_4.json OK + CallSha256_4_gas99.json OK + CallSha256_5.json OK ++ ecrecoverShortBuff.json OK ++ ecrecoverWeirdV.json OK + modexpRandomInput.json OK + modexp_0_0_0_20500.json OK + modexp_0_0_0_22000.json OK + modexp_0_0_0_25000.json OK + modexp_0_0_0_35000.json OK ``` -OK: 99/99 Fail: 0/99 Skip: 0/99 +OK: 102/102 Fail: 0/102 Skip: 0/102 ## stQuadraticComplexityTest ```diff Call1MB1024Calldepth.json Skip @@ -2313,6 +2323,7 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + currentAccountBalance.json OK + doubleSelfdestructTest.json OK + doubleSelfdestructTest2.json OK ++ doubleSelfdestructTouch.json OK + extcodecopy.json OK + return0.json OK + return1.json OK @@ -2327,7 +2338,7 @@ OK: 13/13 Fail: 0/13 Skip: 0/13 + suicideSendEtherToMe.json OK + testRandomTest.json OK ``` -OK: 56/66 Fail: 0/66 Skip: 10/66 +OK: 57/67 Fail: 0/67 Skip: 10/67 ## stTimeConsuming ```diff CALLBlake2f_MaxRounds.json Skip @@ -2847,4 +2858,4 @@ OK: 1/3 Fail: 0/3 Skip: 2/3 OK: 11/11 Fail: 0/11 Skip: 0/11 ---TOTAL--- -OK: 2495/2597 Fail: 0/2597 Skip: 102/2597 +OK: 2506/2608 Fail: 0/2608 Skip: 102/2608 diff --git a/nimbus/chain_config.nim b/nimbus/chain_config.nim index 58eb6841b..1f414c801 100644 --- a/nimbus/chain_config.nim +++ b/nimbus/chain_config.nim @@ -357,6 +357,9 @@ proc parseGenesisAlloc*(data: string, ga: var GenesisAlloc): bool proc toFork*(c: ChainConfig, number: BlockNumber): Fork = ## Map to EVM fork, which doesn't include the DAO or Glacier forks. + if c.mergeForkBlock.isSome and number >= c.mergeForkBlock.get: + return FkParis + if number >= c.londonBlock: FkLondon elif number >= c.berlinBlock: FkBerlin elif number >= c.istanbulBlock: FkIstanbul diff --git a/nimbus/db/accounts_cache.nim b/nimbus/db/accounts_cache.nim index 2ea332efa..5611e7389 100644 --- a/nimbus/db/accounts_cache.nim +++ b/nimbus/db/accounts_cache.nim @@ -463,6 +463,24 @@ proc persist*(ac: AccountsCache, clearCache: bool = true) = ac.isDirty = false +iterator addresses*(ac: AccountsCache): EthAddress = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for address, _ in ac.savePoint.cache: + yield address + +iterator accounts*(ac: AccountsCache): Account = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for _, account in ac.savePoint.cache: + yield account.account + +iterator pairs*(ac: AccountsCache): (EthAddress, Account) = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for address, account in ac.savePoint.cache: + yield (address, account.account) + iterator storage*(ac: AccountsCache, address: EthAddress): (UInt256, UInt256) = # beware that if the account not persisted, # the storage root will not be updated diff --git a/nimbus/db/db_chain.nim b/nimbus/db/db_chain.nim index a93cca01f..c9692ac2a 100644 --- a/nimbus/db/db_chain.nim +++ b/nimbus/db/db_chain.nim @@ -144,6 +144,10 @@ proc getBlockHeader*(self: BaseChainDB; n: BlockNumber): BlockHeader = proc getScore*(self: BaseChainDB; blockHash: Hash256): UInt256 = rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray), UInt256) +proc setScore*(self: BaseChainDB; blockHash: Hash256, score: UInt256) = + ## for testing purpose + self.db.put(blockHashToScoreKey(blockHash).toOpenArray, rlp.encode(score)) + proc getTd*(self: BaseChainDB; blockHash: Hash256, td: var UInt256): bool = let bytes = self.db.get(blockHashToScoreKey(blockHash).toOpenArray) if bytes.len == 0: return false @@ -162,7 +166,14 @@ proc headTotalDifficulty*(self: BaseChainDB): UInt256 = let blockHash = rlp.decode(data, Hash256) rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray), UInt256) - + +proc isBlockAfterTtd*(self: BaseChainDB, header: BlockHeader): bool = + let + ttd = self.ttd + ptd = self.getScore(header.parentHash) + td = ptd + header.difficulty + ptd >= ttd and td >= ttd + proc getAncestorsHashes*(self: BaseChainDB, limit: UInt256, header: BlockHeader): seq[Hash256] = var ancestorCount = min(header.blockNumber, limit).truncate(int) var h = header @@ -465,7 +476,7 @@ proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader if headScore < ttd and score >= ttd: self.writeTerminalHash(headerHash) - if score > headScore: + if score > headScore or score >= ttd: result = self.setAsCanonicalChainHead(headerHash) proc persistHeaderToDbWithoutSetHead*(self: BaseChainDB; header: BlockHeader) = diff --git a/nimbus/genesis.nim b/nimbus/genesis.nim index 4753332e2..0fc6e50f2 100644 --- a/nimbus/genesis.nim +++ b/nimbus/genesis.nim @@ -13,6 +13,8 @@ import proc newStateDB*(db: TrieDatabaseRef, pruneTrie: bool): AccountStateDB = newAccountStateDB(db, emptyRlpHash, pruneTrie) +import debug + proc toGenesisHeader*(db: BaseChainDB, sdb: AccountStateDB): BlockHeader {.raises: [Defect, RlpError].} = ## Initialise block chain DB accounts derived from the `genesis.alloc` table @@ -76,15 +78,16 @@ proc toGenesisHeader*(db: BaseChainDB, sdb: AccountStateDB): BlockHeader ommersHash: EMPTY_UNCLE_HASH ) + let fork = db.config.toFork(0.toBlockNumber) if g.baseFeePerGas.isSome: result.baseFee = g.baseFeePerGas.get() - elif db.config.toFork(0.toBlockNumber) >= FkLondon: + elif fork >= FkLondon: result.baseFee = EIP1559_INITIAL_BASE_FEE.u256 if g.gasLimit.isZero: result.gasLimit = GENESIS_GAS_LIMIT - if g.difficulty.isZero: + if g.difficulty.isZero and fork <= FkLondon: result.difficulty = GENESIS_DIFFICULTY proc toGenesisHeader*(params: NetworkParams): BlockHeader diff --git a/nimbus/p2p/chain/chain_desc.nim b/nimbus/p2p/chain/chain_desc.nim index 7251af13b..0fccdfd58 100644 --- a/nimbus/p2p/chain/chain_desc.nim +++ b/nimbus/p2p/chain/chain_desc.nim @@ -91,17 +91,7 @@ func toNextFork(n: Option[BlockNumber]): uint64 = proc isBlockAfterTtd*(c: Chain, header: BlockHeader): bool {.gcsafe, raises: [Defect,CatchableError].} = - let - ttd = c.db.ttd - ptd = c.db.getScore(header.parentHash) - td = ptd + header.difficulty - - # c.db.totalDifficulty is parent.totalDifficulty - # TerminalBlock is defined as header.totalDifficulty >= TTD - # and parent.totalDifficulty < TTD - # So blockAfterTTD must be both header.totalDifficulty >= TTD - # and parent.totalDifficulty >= TTD - ptd >= ttd and td >= ttd + isBlockAfterTtd(c.db, header) func getNextFork(c: ChainConfig, fork: ChainFork): uint64 = let next: array[ChainFork, uint64] = [ diff --git a/nimbus/p2p/validate.nim b/nimbus/p2p/validate.nim index 32c8b3447..4ffa7eab6 100644 --- a/nimbus/p2p/validate.nim +++ b/nimbus/p2p/validate.nim @@ -321,6 +321,10 @@ proc validateTransaction*( accountNonce=nonce return false + if tx.nonce == high(uint64): + debug "invalid tx: nonce at maximum" + return false + # EIP-3607 Reject transactions from senders with deployed code # The EIP spec claims this attack never happened before # Clients might choose to disable this rule for RPC calls like diff --git a/nimbus/vm2/interpreter/op_handlers.nim b/nimbus/vm2/interpreter/op_handlers.nim index 72eb2b47e..3f7f274f0 100644 --- a/nimbus/vm2/interpreter/op_handlers.nim +++ b/nimbus/vm2/interpreter/op_handlers.nim @@ -142,6 +142,7 @@ when isMainModule and isChatty: echo ">>> frontier[sstore]: ", FkFrontier.opHandlersInfo(Sstore) echo ">>> constantinople[sstore]: ", FkConstantinople.opHandlersInfo(Sstore) echo ">>> berlin[sstore]: ", FkBerlin.opHandlersInfo(Sstore) + echo ">>> paris[sstore]: ", FkParis.opHandlersInfo(Sstore) # ------------------------------------------------------------------------------ # End diff --git a/tests/test_blockchain_json.nim b/tests/test_blockchain_json.nim index b9a2553f4..e5f95f00b 100644 --- a/tests/test_blockchain_json.nim +++ b/tests/test_blockchain_json.nim @@ -9,7 +9,7 @@ import unittest2, json, os, tables, strutils, sets, options, eth/[common, rlp], eth/trie/[db, trie_defs], - stew/endians2, + stew/[endians2, byteutils], ./test_helpers, ./test_allowed_to_fail, ../premix/parser, test_config, ../nimbus/[vm_state, utils, vm_types, errors, constants, forks], @@ -39,6 +39,7 @@ type vmState : BaseVMState debugData : JsonNode network : string + postStateHash: Hash256 var pow = PowRef.new @@ -146,7 +147,9 @@ func vmConfiguration(network: string, c: var ChainConfig) = c.berlinBlock = number[FkBerlin] c.londonBlock = number[FkLondon] c.arrowGlacierBlock = number[FkLondon] + c.mergeForkBlock = some(number[FkParis]) + c.terminalTotalDifficulty = none(UInt256) case network of "EIP150": c.assignNumber(FkTangerine, Zero) @@ -183,6 +186,12 @@ func vmConfiguration(network: string, c: var ChainConfig) = c.assignNumber(FkLondon, Zero) of "BerlinToLondonAt5": c.assignNumber(FkLondon, Five) + of "Merge": + c.assignNumber(FkParis, Zero) + c.terminalTotalDifficulty = some(0.u256) + of "ArrowGlacierToMergeAtDiffC0000": + c.assignNumber(FkParis, H) + c.terminalTotalDifficulty = some(0xC0000.u256) else: raise newException(ValueError, "unsupported network " & network) @@ -205,6 +214,10 @@ proc parseTester(fixture: JsonNode, testStatusIMPL: var TestStatus): Tester = if "sealEngine" in fixture: result.sealEngine = some(parseEnum[SealEngine](fixture["sealEngine"].getStr)) + + if "postStateHash" in fixture: + result.postStateHash.data = hexToByteArray[32](fixture["postStateHash"].getStr) + result.network = fixture["network"].getStr proc blockWitness(vmState: BaseVMState, chainDB: BaseChainDB) = @@ -230,7 +243,7 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB, preminedBlock: EthBlock, tb: TestBlock, checkSeal, validation: bool): EthBlock = let parentHeader = chainDB.getBlockHeader(preminedBlock.header.parentHash) - let baseHeaderForImport = generateHeaderFromParentHeader(chainDB.config, + var baseHeaderForImport = generateHeaderFromParentHeader(chainDB.config, parentHeader, preminedBlock.header.coinbase, some(preminedBlock.header.timestamp), @@ -240,6 +253,12 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB, ) deepCopy(result, preminedBlock) + let ttdReached = chainDB.isBlockAfterTtd(preminedBlock.header) + if ttdReached and chainDB.config.mergeForkBlock.isNone: + chainDB.config.mergeForkBlock = some(preminedBlock.header.blockNumber) + + if ttdReached: + baseHeaderForImport.prevRandao = preminedBlock.header.prevRandao tester.vmState = BaseVMState.new( parentHeader, @@ -252,6 +271,14 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB, transactions: result.txs, uncles: result.uncles ) + + if validation: + let rc = chainDB.validateHeaderAndKinship( + result.header, body, checkSeal, ttdReached, pow) + if rc.isErr: + raise newException( + ValidationError, "validateHeaderAndKinship: " & rc.error) + let res = tester.vmState.processBlockNotPoA(result.header, body) if res == ValidationResult.Error: if not (tb.hasException or (not tb.goodBlock)): @@ -260,13 +287,6 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB, if tester.vmState.generateWitness(): blockWitness(tester.vmState, chainDB) - if validation: - let rc = chainDB.validateHeaderAndKinship( - result.header, body, checkSeal, false, pow) - if rc.isErr: - raise newException( - ValidationError, "validateHeaderAndKinship: " & rc.error) - discard chainDB.persistHeaderToDb(preminedBlock.header) proc applyFixtureBlockToChain(tester: var Tester, tb: TestBlock, @@ -279,6 +299,7 @@ proc applyFixtureBlockToChain(tester: var Tester, tb: TestBlock, preminedBlock = rlp.decode(tb.blockRLP, EthBlock) minedBlock = tester.importBlock(chainDB, preminedBlock, tb, checkSeal, validation) rlpEncodedMinedBlock = rlp.encode(minedBlock) + result = (preminedBlock, minedBlock, rlpEncodedMinedBlock) func shouldCheckSeal(tester: Tester): bool = @@ -310,9 +331,20 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes let (preminedBlock, _, _) = tester.applyFixtureBlockToChain( testBlock, chainDB, checkSeal, validation = false) + let ttdReached = chainDB.isBlockAfterTtd(preminedBlock.header) + if ttdReached and chainDB.config.mergeForkBlock.isNone: + chainDB.config.mergeForkBlock = some(preminedBlock.header.blockNumber) + # manually validating - check chainDB.validateHeaderAndKinship( - preminedBlock, checkSeal, false, pow).isOk + let res = chainDB.validateHeaderAndKinship( + preminedBlock, checkSeal, ttdReached, pow) + check res.isOk + when defined(noisy): + if res.isErr: + debugEcho "blockNumber: ", preminedBlock.header.blockNumber + debugEcho "fork: ", chainDB.config.toFork(preminedBlock.header.blockNumber) + debugEcho "error message: ", res.error + debugEcho "ttdReached: ", ttdReached except: debugEcho "FATAL ERROR(WE HAVE BUG): ", getCurrentExceptionMsg() @@ -361,13 +393,45 @@ proc dumpDebugData(tester: Tester, vmState: BaseVMState, accountList: JsonNode): "accounts": accounts } -proc dumpDebugData(tester: Tester, fixture: JsonNode, fixtureName: string, fixtureIndex: int, success: bool) = - let accountList = if fixture["postState"].kind == JObject: fixture["postState"] else: fixture["pre"] +proc accountList(fixture: JsonNode): JsonNode = + if fixture["postState"].kind == JObject: + fixture["postState"] + else: + fixture["pre"] + +proc debugDataFromAccountList(tester: Tester, fixture: JsonNode): JsonNode = + let accountList = fixture.accountList let vmState = tester.vmState - let debugData = if vmState.isNil: - %{"debugData": tester.debugData} + if vmState.isNil: + %{"debugData": tester.debugData} + else: + dumpDebugData(tester, vmState, accountList) + +proc debugDataFromPostStateHash(tester: Tester): JsonNode = + var + accounts = newJObject() + accountList = newSeq[EthAddress]() + vmState = tester.vmState + + for address in vmState.stateDB.addresses: + accountList.add address + + for i, ac in accountList: + accounts[ac.toHex] = dumpAccount(vmState.readOnlyStateDB, ac, "acc" & $i) + + %{ + "debugData": tester.debugData, + "postStateHash": %($vmState.readOnlyStateDB.rootHash), + "expectedStateHash": %($tester.postStateHash), + "accounts": accounts + } + +proc dumpDebugData(tester: Tester, fixture: JsonNode, fixtureName: string, fixtureIndex: int, success: bool) = + let debugData = if tester.postStateHash != Hash256(): + debugDataFromPostStateHash(tester) else: - dumpDebugData(tester, vmState, accountList) + debugDataFromAccountList(tester, fixture) + let status = if success: "_success" else: "_failed" writeFile("debug_" & fixtureName & "_" & $fixtureIndex & status & ".json", debugData.pretty()) @@ -411,7 +475,15 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal tester.runTester(chainDB, testStatusIMPL) let latestBlockHash = chainDB.getCanonicalHead().blockHash if latestBlockHash != tester.lastBlockHash: - verifyStateDB(fixture["postState"], tester.vmState.readOnlyStateDB) + if tester.postStateHash != Hash256(): + let rootHash = tester.vmState.stateDB.rootHash + if tester.postStateHash != rootHash: + raise newException(ValidationError, "incorrect postStateHash, expect=" & + $rootHash & ", get=" & + $tester.postStateHash + ) + else: + verifyStateDB(fixture["postState"], tester.vmState.readOnlyStateDB) except ValidationError as E: echo fixtureName, " ERROR: ", E.msg success = false diff --git a/tests/test_generalstate_json.nim b/tests/test_generalstate_json.nim index f814cedae..e3049db3f 100644 --- a/tests/test_generalstate_json.nim +++ b/tests/test_generalstate_json.nim @@ -17,7 +17,7 @@ import eth/[rlp, common], eth/trie/[db, trie_defs], unittest2, - stew/results + stew/[results, byteutils] type Tester = object @@ -89,8 +89,16 @@ let chainParams = networkParams(MainNet) proc testFixtureIndexes(tester: Tester, testStatusIMPL: var TestStatus) = let chainDB = newBaseChainDB(newMemoryDB(), getConfiguration().pruning, params = chainParams) - vmState = BaseVMState.new( - parent = BlockHeader(stateRoot: emptyRlpHash), + parent = BlockHeader(stateRoot: emptyRlpHash) + + # can't be assigned to + # tester.header.parentHash = parent.blockHash + chainDB.setScore(parent.blockHash, 0.u256) + if tester.fork >= FkParis: + chainDB.config.terminalTotalDifficulty = some(0.u256) + + let vmState = BaseVMState.new( + parent = parent, header = tester.header, chainDB = chainDB, tracerFlags = (if tester.trace: {TracerFlags.EnableTracing} else: {}), @@ -157,17 +165,20 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus, let fenv = fixture["env"] tester.header = BlockHeader( - coinbase: fenv["currentCoinbase"].getStr.ethAddressFromHex, - difficulty: fromHex(UInt256, fenv{"currentDifficulty"}.getStr), + coinbase : fenv["currentCoinbase"].getStr.ethAddressFromHex, + difficulty : fromHex(UInt256, fenv{"currentDifficulty"}.getStr), blockNumber: fenv{"currentNumber"}.getHexadecimalInt.u256, - gasLimit: fenv{"currentGasLimit"}.getHexadecimalInt.GasInt, - timestamp: fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix, - stateRoot: emptyRlpHash + gasLimit : fenv{"currentGasLimit"}.getHexadecimalInt.GasInt, + timestamp : fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix, + stateRoot : emptyRlpHash ) if "currentBaseFee" in fenv: tester.header.baseFee = fromHex(UInt256, fenv{"currentBaseFee"}.getStr) + if "currentRandom" in fenv: + tester.header.prevRandao.data = hexToByteArray[32](fenv{"currentRandom"}.getStr) + let specifyIndex = getConfiguration().index tester.trace = trace tester.debugMode = debugMode diff --git a/tests/test_helpers.nim b/tests/test_helpers.nim index 8297f0b54..504b4ceef 100644 --- a/tests/test_helpers.nim +++ b/tests/test_helpers.nim @@ -30,7 +30,8 @@ const FkPetersburg: "ConstantinopleFix", FkIstanbul: "Istanbul", FkBerlin: "Berlin", - FkLondon: "London" + FkLondon: "London", + FkParis: "Merge" }.toTable supportedForks* = { @@ -43,7 +44,8 @@ const FkPetersburg, FkIstanbul, FkBerlin, - FkLondon} + FkLondon, + FkParis} nameToFork* = revmap(forkNames)