# Nimbus # Copyright (c) 2018-2024 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) # * MIT license ([LICENSE-MIT](LICENSE-MIT) or # http://opensource.org/licenses/MIT) # at your option. This file may not be copied, modified, or distributed except # according to those terms. import pkg/chronicles, pkg/unittest2, ../nimbus/common, ../nimbus/config, ../nimbus/utils/utils, ../nimbus/core/chain/forked_chain, ../nimbus/db/ledger, ./test_forked_chain/chain_debug const genesisFile = "tests/customgenesis/cancun123.json" senderAddr = address"73cf19657412508833f618a15e8251306b3e6ee5" type TestEnv = object conf: NimbusConf proc setupEnv(): TestEnv = let conf = makeConfig(@[ "--custom-network:" & genesisFile ]) TestEnv(conf: conf) proc newCom(env: TestEnv): CommonRef = CommonRef.new( newCoreDbRef DefaultDbMemory, nil, env.conf.networkId, env.conf.networkParams ) proc makeBlk(com: CommonRef, number: BlockNumber, parentBlk: Block): Block = template parent(): Header = parentBlk.header var wds = newSeqOfCap[Withdrawal](number.int) for i in 0.. head -> error check chain.forkChoice(blk1.blockHash, blk3.blockHash).isErr check chain.validate info & " (3)" # blk4 is not part of chain check chain.forkChoice(blk4.blockHash, blk2.blockHash).isErr # finalized > head -> error check chain.forkChoice(blk1.blockHash, blk2.blockHash).isErr # blk4 is not part of chain check chain.forkChoice(blk2.blockHash, blk4.blockHash).isErr # finalized < head -> ok check chain.forkChoice(blk2.blockHash, blk1.blockHash).isOk check com.headHash == blk2.blockHash check chain.latestHash == blk2.blockHash check chain.validate info & " (7)" # finalized == head -> ok check chain.forkChoice(blk2.blockHash, blk2.blockHash).isOk check com.headHash == blk2.blockHash check chain.latestHash == blk2.blockHash check chain.validate info & " (8)" # no baggage written check com.wdWritten(blk1) == 0 check com.wdWritten(blk2) == 0 check chain.validate info & " (9)" test "newBase == cursor": const info = "newBase == cursor" let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(blk4).isOk check chain.validate info & " (1)" # newbase == cursor check chain.forkChoice(blk7.blockHash, blk6.blockHash).isOk check chain.validate info & " (2)" check com.headHash == blk7.blockHash check chain.latestHash == blk7.blockHash check com.wdWritten(blk7) == 0 # head - baseDistance must been finalized check com.wdWritten(blk4) == 4 # make sure aristo not wiped out baggage check com.wdWritten(blk3) == 3 check chain.validate info & " (9)" test "newBase between oldBase and cursor": const info = "newBase between oldBase and cursor" let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.validate info & " (1)" check chain.forkChoice(blk7.blockHash, blk6.blockHash).isOk check chain.validate info & " (2)" check com.headHash == blk7.blockHash check chain.latestHash == blk7.blockHash check com.wdWritten(blk6) == 0 check com.wdWritten(blk7) == 0 # head - baseDistance must been finalized check com.wdWritten(blk4) == 4 # make sure aristo not wiped out baggage check com.wdWritten(blk3) == 3 check chain.validate info & " (9)" test "newBase == oldBase, fork and stay on that fork": const info = "newBase == oldBase, fork .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(B7.blockHash, B5.blockHash).isOk check com.headHash == B7.blockHash check chain.latestHash == B7.blockHash check chain.validate info & " (9)" test "newBase == cursor, fork and stay on that fork": const info = "newBase == cursor, fork .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.importBlock(B4).isOk check chain.validate info & " (1)" check chain.forkChoice(B7.blockHash, B6.blockHash).isOk check chain.validate info & " (2)" check com.headHash == B7.blockHash check chain.latestHash == B7.blockHash check chain.validate info & " (9)" test "newBase on shorter canonical arc, discard arc with oldBase": const info = "newBase on shorter canonical .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(B7.blockHash, B5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == B7.blockHash check chain.latestHash == B7.blockHash check chain.baseNumber >= B4.header.number check chain.cursorHeads.len == 1 check chain.validate info & " (9)" test "newBase on curbed non-canonical arc": const info = "newBase on curbed non-canonical .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 5) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(B7.blockHash, B5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == B7.blockHash check chain.latestHash == B7.blockHash check chain.baseNumber > 0 check chain.baseNumber < B4.header.number check chain.cursorHeads.len == 2 check chain.validate info & " (9)" test "newBase == oldBase, fork and return to old chain": const info = "newBase == oldBase, fork .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(blk7.blockHash, blk5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == blk7.blockHash check chain.latestHash == blk7.blockHash check chain.validate info & " (9)" test "newBase == cursor, fork and return to old chain": const info = "newBase == cursor, fork .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.importBlock(blk4).isOk check chain.validate info & " (1)" check chain.forkChoice(blk7.blockHash, blk5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == blk7.blockHash check chain.latestHash == blk7.blockHash check chain.validate info & " (9)" test "newBase on shorter canonical arc, discard arc with oldBase" & " (ign dup block)": const info = "newBase on shorter canonical .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.importBlock(blk4).isOk check chain.validate info & " (1)" check chain.forkChoice(B7.blockHash, B5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == B7.blockHash check chain.latestHash == B7.blockHash check chain.baseNumber >= B4.header.number check chain.cursorHeads.len == 1 check chain.validate info & " (9)" test "newBase on longer canonical arc, discard arc with oldBase": const info = "newBase on longer canonical .." let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(blk7.blockHash, blk5.blockHash).isOk check chain.validate info & " (2)" check com.headHash == blk7.blockHash check chain.latestHash == blk7.blockHash check chain.baseNumber > 0 check chain.baseNumber < blk5.header.number check chain.cursorHeads.len == 1 check chain.validate info & " (9)" test "headerByNumber": const info = "headerByNumber" let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.importBlock(B4).isOk check chain.importBlock(B5).isOk check chain.importBlock(B6).isOk check chain.importBlock(B7).isOk check chain.validate info & " (1)" check chain.forkChoice(blk7.blockHash, blk5.blockHash).isOk check chain.validate info & " (2)" # cursor check chain.headerByNumber(8).isErr check chain.headerByNumber(7).expect("OK").number == 7 check chain.headerByNumber(7).expect("OK").blockHash == blk7.blockHash # from db check chain.headerByNumber(3).expect("OK").number == 3 check chain.headerByNumber(3).expect("OK").blockHash == blk3.blockHash # base check chain.headerByNumber(4).expect("OK").number == 4 check chain.headerByNumber(4).expect("OK").blockHash == blk4.blockHash # from cache check chain.headerByNumber(5).expect("OK").number == 5 check chain.headerByNumber(5).expect("OK").blockHash == blk5.blockHash check chain.validate info & " (9)" test "Import after Replay Segment": const info = "Import after Replay Segment" let com = env.newCom() var chain = newForkedChain(com, com.genesisHeader, baseDistance = 3) check chain.importBlock(blk1).isOk check chain.importBlock(blk2).isOk check chain.importBlock(blk3).isOk check chain.importBlock(blk4).isOk check chain.importBlock(blk5).isOk check chain.validate info & " (1)" chain.replaySegment(blk2.header.blockHash) chain.replaySegment(blk5.header.blockHash) check chain.validate info & " (2)" check chain.importBlock(blk6).isOk check chain.importBlock(blk7).isOk check chain.validate info & " (9)" when isMainModule: forkedChainMain()