mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-27 04:26:07 +00:00
remove code duplication from test_blockchain_json
now test_blockchain_json is using block validation code from p2p/executor.nim instead of using it's own block validation code. this will reduce maintenance cost and fixes #592.
This commit is contained in:
parent
db65f92e66
commit
2a9c3982d9
@ -32,6 +32,7 @@ type
|
|||||||
TestBlock = object
|
TestBlock = object
|
||||||
goodBlock: bool
|
goodBlock: bool
|
||||||
blockRLP : Blob
|
blockRLP : Blob
|
||||||
|
hasException: bool
|
||||||
|
|
||||||
Tester = object
|
Tester = object
|
||||||
lastBlockHash: Hash256
|
lastBlockHash: Hash256
|
||||||
@ -115,8 +116,11 @@ proc parseBlocks(blocks: JsonNode): seq[TestBlock] =
|
|||||||
t.goodBlock = true
|
t.goodBlock = true
|
||||||
of "rlp":
|
of "rlp":
|
||||||
fixture.fromJson "rlp", t.blockRLP
|
fixture.fromJson "rlp", t.blockRLP
|
||||||
else:
|
of "transactions", "uncleHeaders",
|
||||||
|
"blocknumber", "chainname", "chainnetwork":
|
||||||
discard
|
discard
|
||||||
|
else:
|
||||||
|
t.hasException = true
|
||||||
|
|
||||||
result.add t
|
result.add t
|
||||||
|
|
||||||
@ -208,9 +212,10 @@ proc parseTester(fixture: JsonNode, testStatusIMPL: var TestStatus): Tester =
|
|||||||
result.sealEngine = some(parseEnum[SealEngine](fixture["sealEngine"].getStr))
|
result.sealEngine = some(parseEnum[SealEngine](fixture["sealEngine"].getStr))
|
||||||
result.network = fixture["network"].getStr
|
result.network = fixture["network"].getStr
|
||||||
|
|
||||||
proc blockWitness(vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) =
|
proc blockWitness(vmState: BaseVMState, chainDB: BaseChainDB) =
|
||||||
let rootHash = vmState.accountDb.rootHash
|
let rootHash = vmState.accountDb.rootHash
|
||||||
let witness = vmState.buildWitness()
|
let witness = vmState.buildWitness()
|
||||||
|
let fork = vmState.fork
|
||||||
let flags = if fork >= FKSpurious: {wfEIP170} else: {}
|
let flags = if fork >= FKSpurious: {wfEIP170} else: {}
|
||||||
|
|
||||||
# build tree from witness
|
# build tree from witness
|
||||||
@ -226,78 +231,6 @@ proc blockWitness(vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) =
|
|||||||
if root != rootHash:
|
if root != rootHash:
|
||||||
raise newException(ValidationError, "Invalid trie generated from block witness")
|
raise newException(ValidationError, "Invalid trie generated from block witness")
|
||||||
|
|
||||||
proc assignBlockRewards(minedBlock: EthBlock, vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) =
|
|
||||||
let blockReward = blockRewards[fork]
|
|
||||||
var mainReward = blockReward
|
|
||||||
if minedBlock.header.ommersHash != EMPTY_UNCLE_HASH:
|
|
||||||
let h = vmState.chainDB.persistUncles(minedBlock.uncles)
|
|
||||||
if h != minedBlock.header.ommersHash:
|
|
||||||
raise newException(ValidationError, "Uncle hash mismatch")
|
|
||||||
for uncle in minedBlock.uncles:
|
|
||||||
var uncleReward = uncle.blockNumber.u256 + 8.u256
|
|
||||||
uncleReward -= minedBlock.header.blockNumber.u256
|
|
||||||
uncleReward = uncleReward * blockReward
|
|
||||||
uncleReward = uncleReward div 8.u256
|
|
||||||
vmState.mutateStateDB:
|
|
||||||
db.addBalance(uncle.coinbase, uncleReward)
|
|
||||||
mainReward += blockReward div 32.u256
|
|
||||||
|
|
||||||
# Reward beneficiary
|
|
||||||
vmState.mutateStateDB:
|
|
||||||
db.addBalance(minedBlock.header.coinbase, mainReward)
|
|
||||||
if vmState.generateWitness:
|
|
||||||
db.collectWitnessData()
|
|
||||||
db.persist()
|
|
||||||
|
|
||||||
let stateDb = vmState.accountDb
|
|
||||||
if minedBlock.header.stateRoot != stateDb.rootHash:
|
|
||||||
raise newException(ValidationError, "wrong state root in block")
|
|
||||||
|
|
||||||
let bloom = createBloom(vmState.receipts)
|
|
||||||
if minedBlock.header.bloom != bloom:
|
|
||||||
raise newException(ValidationError, "wrong bloom")
|
|
||||||
|
|
||||||
let receiptRoot = calcReceiptRoot(vmState.receipts)
|
|
||||||
if minedBlock.header.receiptRoot != receiptRoot:
|
|
||||||
raise newException(ValidationError, "wrong receiptRoot")
|
|
||||||
|
|
||||||
let txRoot = calcTxRoot(minedBlock.transactions)
|
|
||||||
if minedBlock.header.txRoot != txRoot:
|
|
||||||
raise newException(ValidationError, "wrong txRoot")
|
|
||||||
|
|
||||||
if vmState.generateWitness:
|
|
||||||
blockWitness(vmState, fork, chainDB)
|
|
||||||
|
|
||||||
proc processBlock(chainDB: BaseChainDB, vmState: BaseVMState, minedBlock: EthBlock, fork: Fork) =
|
|
||||||
var dbTx = chainDB.db.beginTransaction()
|
|
||||||
defer: dbTx.dispose()
|
|
||||||
|
|
||||||
if chainDB.config.daoForkSupport and minedBlock.header.blockNumber == chainDB.config.daoForkBlock:
|
|
||||||
vmState.mutateStateDB:
|
|
||||||
db.applyDAOHardFork()
|
|
||||||
|
|
||||||
vmState.receipts = newSeq[Receipt](minedBlock.transactions.len)
|
|
||||||
vmState.cumulativeGasUsed = 0
|
|
||||||
|
|
||||||
for txIndex, tx in minedBlock.transactions:
|
|
||||||
var sender: EthAddress
|
|
||||||
if tx.getSender(sender):
|
|
||||||
discard processTransaction(tx, sender, vmState, fork)
|
|
||||||
else:
|
|
||||||
raise newException(ValidationError, "could not get sender")
|
|
||||||
vmState.receipts[txIndex] = makeReceipt(vmState, fork)
|
|
||||||
|
|
||||||
if vmState.cumulativeGasUsed != minedBlock.header.gasUsed:
|
|
||||||
let diff = vmState.cumulativeGasUsed - minedBlock.header.gasUsed
|
|
||||||
raise newException(ValidationError, &"wrong gas used in header expected={minedBlock.header.gasUsed}, actual={vmState.cumulativeGasUsed}, diff={diff}")
|
|
||||||
|
|
||||||
assignBlockRewards(minedBlock, vmState, fork, vmState.chainDB)
|
|
||||||
|
|
||||||
# `applyDeletes = false`
|
|
||||||
# preserve previous block stateRoot
|
|
||||||
# while still benefits from trie pruning
|
|
||||||
dbTx.commit(applyDeletes = false)
|
|
||||||
|
|
||||||
func validateBlockUnchanged(a, b: EthBlock): bool =
|
func validateBlockUnchanged(a, b: EthBlock): bool =
|
||||||
result = rlp.encode(a) == rlp.encode(b)
|
result = rlp.encode(a) == rlp.encode(b)
|
||||||
|
|
||||||
@ -508,7 +441,7 @@ proc validateBlock(chainDB: BaseChainDB, currBlock: EthBlock, checkSeal: bool):
|
|||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc importBlock(tester: var Tester, chainDB: BaseChainDB,
|
proc importBlock(tester: var Tester, chainDB: BaseChainDB,
|
||||||
preminedBlock: EthBlock, fork: Fork, checkSeal, validation = true): EthBlock =
|
preminedBlock: EthBlock, tb: TestBlock, checkSeal, validation: bool, testStatusIMPL: var TestStatus): EthBlock =
|
||||||
|
|
||||||
let parentHeader = chainDB.getBlockHeader(preminedBlock.header.parentHash)
|
let parentHeader = chainDB.getBlockHeader(preminedBlock.header.parentHash)
|
||||||
let baseHeaderForImport = generateHeaderFromParentHeader(chainDB.config,
|
let baseHeaderForImport = generateHeaderFromParentHeader(chainDB.config,
|
||||||
@ -523,7 +456,16 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB,
|
|||||||
let tracerFlags: set[TracerFlags] = if tester.trace: {TracerFlags.EnableTracing} else : {}
|
let tracerFlags: set[TracerFlags] = if tester.trace: {TracerFlags.EnableTracing} else : {}
|
||||||
tester.vmState = newBaseVMState(parentHeader.stateRoot, baseHeaderForImport, chainDB, tracerFlags)
|
tester.vmState = newBaseVMState(parentHeader.stateRoot, baseHeaderForImport, chainDB, tracerFlags)
|
||||||
|
|
||||||
processBlock(chainDB, tester.vmState, result, fork)
|
let body = BlockBody(
|
||||||
|
transactions: result.transactions,
|
||||||
|
uncles: result.uncles
|
||||||
|
)
|
||||||
|
let res = processBlock(chainDB, result.header, body, tester.vmState)
|
||||||
|
if res == ValidationResult.Error:
|
||||||
|
check (tb.hasException or (not tb.goodBlock))
|
||||||
|
else:
|
||||||
|
if tester.vmState.generateWitness():
|
||||||
|
blockWitness(tester.vmState, chainDB)
|
||||||
|
|
||||||
result.header.stateRoot = tester.vmState.blockHeader.stateRoot
|
result.header.stateRoot = tester.vmState.blockHeader.stateRoot
|
||||||
result.header.parentHash = parentHeader.hash
|
result.header.parentHash = parentHeader.hash
|
||||||
@ -538,15 +480,14 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB,
|
|||||||
discard chainDB.persistHeaderToDb(preminedBlock.header)
|
discard chainDB.persistHeaderToDb(preminedBlock.header)
|
||||||
|
|
||||||
proc applyFixtureBlockToChain(tester: var Tester, tb: TestBlock,
|
proc applyFixtureBlockToChain(tester: var Tester, tb: TestBlock,
|
||||||
chainDB: BaseChainDB, checkSeal, validation = true): (EthBlock, EthBlock, Blob) =
|
chainDB: BaseChainDB, checkSeal, validation: bool, testStatusIMPL: var TestStatus): (EthBlock, EthBlock, Blob) =
|
||||||
|
|
||||||
# we hack the ChainConfig here and let it works with calcDifficulty
|
# we hack the ChainConfig here and let it works with calcDifficulty
|
||||||
vmConfiguration(tester.network, chainDB.config)
|
vmConfiguration(tester.network, chainDB.config)
|
||||||
|
|
||||||
var
|
var
|
||||||
preminedBlock = rlp.decode(tb.blockRLP, EthBlock)
|
preminedBlock = rlp.decode(tb.blockRLP, EthBlock)
|
||||||
fork = toFork(chainDB.config, preminedBlock.header.blockNumber)
|
minedBlock = tester.importBlock(chainDB, preminedBlock, tb, checkSeal, validation, testStatusIMPL)
|
||||||
minedBlock = tester.importBlock(chainDB, preminedBlock, fork, checkSeal, validation)
|
|
||||||
rlpEncodedMinedBlock = rlp.encode(minedBlock)
|
rlpEncodedMinedBlock = rlp.encode(minedBlock)
|
||||||
result = (preminedBlock, minedBlock, rlpEncodedMinedBlock)
|
result = (preminedBlock, minedBlock, rlpEncodedMinedBlock)
|
||||||
|
|
||||||
@ -570,11 +511,11 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes
|
|||||||
if tester.debugMode:
|
if tester.debugMode:
|
||||||
tester.debugData = newJArray()
|
tester.debugData = newJArray()
|
||||||
|
|
||||||
for idx, TestBlock in tester.blocks:
|
for idx, testBlock in tester.blocks:
|
||||||
if TestBlock.goodBlock:
|
if testBlock.goodBlock:
|
||||||
try:
|
try:
|
||||||
let (preminedBlock, _, _) = tester.applyFixtureBlockToChain(
|
let (preminedBlock, _, _) = tester.applyFixtureBlockToChain(
|
||||||
TestBlock, chainDB, checkSeal, validation = false) # we manually validate below
|
testBlock, chainDB, checkSeal, validation = false, testStatusIMPL) # we manually validate below
|
||||||
check validateBlock(chainDB, preminedBlock, checkSeal) == true
|
check validateBlock(chainDB, preminedBlock, checkSeal) == true
|
||||||
except:
|
except:
|
||||||
debugEcho "FATAL ERROR(WE HAVE BUG): ", getCurrentExceptionMsg()
|
debugEcho "FATAL ERROR(WE HAVE BUG): ", getCurrentExceptionMsg()
|
||||||
@ -582,10 +523,11 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes
|
|||||||
else:
|
else:
|
||||||
var noError = true
|
var noError = true
|
||||||
try:
|
try:
|
||||||
let (_, _, _) = tester.applyFixtureBlockToChain(TestBlock,
|
let (_, _, _) = tester.applyFixtureBlockToChain(testBlock,
|
||||||
chainDB, checkSeal, validation = true)
|
chainDB, checkSeal, validation = true, testStatusIMPL)
|
||||||
except ValueError, ValidationError, BlockNotFound, MalformedRlpError, RlpTypeMismatch:
|
except ValueError, ValidationError, BlockNotFound, MalformedRlpError, RlpTypeMismatch:
|
||||||
# failure is expected on this bad block
|
# failure is expected on this bad block
|
||||||
|
check (testBlock.hasException or (not testBlock.goodBlock))
|
||||||
noError = false
|
noError = false
|
||||||
|
|
||||||
# Block should have caused a validation error
|
# Block should have caused a validation error
|
||||||
@ -702,7 +644,7 @@ proc blockchainJsonMain*(debugMode = false) =
|
|||||||
let path = "tests" / "fixtures" / folder
|
let path = "tests" / "fixtures" / folder
|
||||||
let n = json.parseFile(path / config.testSubject)
|
let n = json.parseFile(path / config.testSubject)
|
||||||
var testStatusIMPL: TestStatus
|
var testStatusIMPL: TestStatus
|
||||||
testFixture(n, testStatusIMPL, debugMode = false, config.trace)
|
testFixture(n, testStatusIMPL, debugMode = true, config.trace)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
var message: string
|
var message: string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user