remove unnecessary codes from test_blockchain_json

except for genesis block, we are not parsing block header from json
node anymore.

we parse block headers from block RLP, it is the same thing.
This commit is contained in:
jangko 2021-05-14 10:47:58 +07:00
parent d1348824f8
commit beb274d98c
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
1 changed files with 54 additions and 127 deletions

View File

@ -26,58 +26,46 @@ type
VMConfig = array[2, tuple[blockNumber: int, fork: Fork]] VMConfig = array[2, tuple[blockNumber: int, fork: Fork]]
PlainBlock = object EthBlock = object
header: BlockHeader header: BlockHeader
transactions: seq[Transaction] transactions: seq[Transaction]
uncles: seq[BlockHeader] uncles: seq[BlockHeader]
TesterBlock = object TestBlock = object
blockHeader: Option[BlockHeader] goodBlock: bool
transactions: seq[Transaction] blockRLP: Blob
uncles: seq[BlockHeader]
blockNumber: Option[int]
chainName: Option[string]
chainNetwork: Option[Fork]
exceptions: seq[(string, string)]
headerRLP: Blob
Tester = object Tester = object
lastBlockHash: Hash256 lastBlockHash: Hash256
genesisBlockHeader: BlockHeader genesisHeader: BlockHeader
blocks: seq[TesterBlock] blocks: seq[TestBlock]
sealEngine: Option[SealEngine] sealEngine: Option[SealEngine]
vmConfig: VMConfig vmConfig: VMConfig
good: bool
debugMode: bool debugMode: bool
trace: bool trace: bool
vmState: BaseVMState vmState: BaseVMState
debugData: JsonNode debugData: JsonNode
network: string network: string
MiningHeader* = object MiningHeader = object
parentHash*: Hash256 parentHash: Hash256
ommersHash*: Hash256 ommersHash: Hash256
coinbase*: EthAddress coinbase: EthAddress
stateRoot*: Hash256 stateRoot: Hash256
txRoot*: Hash256 txRoot: Hash256
receiptRoot*: Hash256 receiptRoot: Hash256
bloom*: common.BloomFilter bloom: common.BloomFilter
difficulty*: DifficultyInt difficulty: DifficultyInt
blockNumber*: BlockNumber blockNumber: BlockNumber
gasLimit*: GasInt gasLimit: GasInt
gasUsed*: GasInt gasUsed: GasInt
timestamp*: EthTime timestamp: EthTime
extraData*: Blob extraData: Blob
proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false) proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false)
func normalizeNumber(n: JsonNode): JsonNode = func normalizeNumber(n: JsonNode): JsonNode =
let str = n.getStr let str = n.getStr
# paranoid checks
doAssert n.kind == Jstring
doAssert str[0] == '0' and str[1] == 'x'
# real normalization
# strip leading 0
if str == "0x": if str == "0x":
result = newJString("0x0") result = newJString("0x0")
elif str == "0x0": elif str == "0x0":
@ -120,72 +108,18 @@ proc parseHeader(blockHeader: JsonNode, testStatusIMPL: var TestStatus): BlockHe
blockHeader.fromJson "hash", blockHash blockHeader.fromJson "hash", blockHash
check blockHash == hash(result) check blockHash == hash(result)
proc parseTx*(n: JsonNode): Transaction = proc parseBlocks(blocks: JsonNode): seq[TestBlock] =
for k, v in n:
case k
of "nonce", "gasPrice", "gasLimit", "value":
n[k] = normalizeNumber(v)
of "to":
let str = v.getStr
if str.len > 2 and str[1] != 'x':
n[k] = newJString("0x" & str)
of "v", "r", "s":
n[k] = normalizeNumber(v)
else:
discard
n.fromJson "nonce", result.accountNonce
n.fromJson "gasPrice", result.gasPrice
n.fromJson "gasLimit", result.gasLimit
result.isContractCreation = n["to"].getStr == ""
if not result.isContractCreation:
n.fromJson "to", result.to
n.fromJson "value", result.value
n.fromJson "data", result.payload
n.fromJson "v", result.V
n.fromJson "r", result.R
n.fromJson "s", result.S
proc parseBlocks(blocks: JsonNode, testStatusIMPL: var TestStatus): seq[TesterBlock] =
result = @[]
for fixture in blocks: for fixture in blocks:
var t: TesterBlock var t: TestBlock
for key, value in fixture: for key, value in fixture:
case key case key
of "blockHeader": of "blockHeader":
t.blockHeader = some(parseHeader(fixture["blockHeader"], testStatusIMPL)) # header is absent in bad block
of "blocknumber": t.goodBlock = true
let numberStr = value.getStr
if numberStr.len >= 2 and numberStr[1] == 'x':
fixture[key] = normalizeNumber(value)
var number: int
fixture.fromJson "blocknumber", number
t.blockNumber = some(number)
else:
t.blockNumber = some(parseInt(numberStr))
of "chainname":
t.chainName = some(value.getStr)
of "chainnetwork":
t.chainNetWork = some(parseEnum[Fork](value.getStr))
of "rlp": of "rlp":
fixture.fromJson "rlp", t.headerRLP fixture.fromJson "rlp", t.blockRLP
of "transactions":
for tx in value:
t.transactions.add parseTx(tx)
of "uncleHeaders":
t.uncles = @[]
for uncle in value:
t.uncles.add parseHeader(uncle, testStatusIMPL)
else: else:
t.exceptions.add( (key, value.getStr) ) discard
if t.blockHeader.isSome:
let h = t.blockHeader.get()
check calcTxRoot(t.transactions) == h.txRoot
let enc = rlp.encode(t.uncles)
check keccakHash(enc) == h.ommersHash
result.add t result.add t
@ -260,29 +194,26 @@ func vmConfigToFork(vmConfig: VMConfig, blockNumber: Uint256): Fork =
raise newException(ValueError, "unreachable code") raise newException(ValueError, "unreachable code")
proc parseTester(fixture: JsonNode, testStatusIMPL: var TestStatus): Tester = proc parseTester(fixture: JsonNode, testStatusIMPL: var TestStatus): Tester =
result.good = true result.blocks = parseBlocks(fixture["blocks"])
fixture.fromJson "lastblockhash", result.lastBlockHash fixture.fromJson "lastblockhash", result.lastBlockHash
result.genesisBlockHeader = parseHeader(fixture["genesisBlockHeader"], testStatusIMPL) result.genesisHeader = parseHeader(fixture["genesisBlockHeader"], testStatusIMPL)
if "genesisRLP" in fixture: if "genesisRLP" in fixture:
var genesisRLP: Blob var genesisRLP: Blob
fixture.fromJson "genesisRLP", genesisRLP fixture.fromJson "genesisRLP", genesisRLP
let genesisBlock = PlainBlock(header: result.genesisBlockHeader) let genesisBlock = EthBlock(header: result.genesisHeader)
check genesisRLP == rlp.encode(genesisBlock) check genesisRLP == rlp.encode(genesisBlock)
else:
var goodBlock = true
for h in result.blocks:
goodBlock = goodBlock and h.goodBlock
check goodBlock == false
if "sealEngine" in fixture: if "sealEngine" in fixture:
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
try:
result.blocks = parseBlocks(fixture["blocks"], testStatusIMPL)
except ValueError:
result.good = false
# TODO: implement missing VM
#if result.network in ["HomesteadToDaoAt5"]:
#result.good = false
proc blockWitness(vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) = proc blockWitness(vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) =
let rootHash = vmState.accountDb.rootHash let rootHash = vmState.accountDb.rootHash
let witness = vmState.buildWitness() let witness = vmState.buildWitness()
@ -301,7 +232,7 @@ 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: PlainBlock, vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) = proc assignBlockRewards(minedBlock: EthBlock, vmState: BaseVMState, fork: Fork, chainDB: BaseChainDB) =
let blockReward = blockRewards[fork] let blockReward = blockRewards[fork]
var mainReward = blockReward var mainReward = blockReward
if minedBlock.header.ommersHash != EMPTY_UNCLE_HASH: if minedBlock.header.ommersHash != EMPTY_UNCLE_HASH:
@ -343,7 +274,7 @@ proc assignBlockRewards(minedBlock: PlainBlock, vmState: BaseVMState, fork: Fork
if vmState.generateWitness: if vmState.generateWitness:
blockWitness(vmState, fork, chainDB) blockWitness(vmState, fork, chainDB)
proc processBlock(chainDB: BaseChainDB, vmState: BaseVMState, minedBlock: PlainBlock, fork: Fork) = proc processBlock(chainDB: BaseChainDB, vmState: BaseVMState, minedBlock: EthBlock, fork: Fork) =
var dbTx = chainDB.db.beginTransaction() var dbTx = chainDB.db.beginTransaction()
defer: dbTx.dispose() defer: dbTx.dispose()
@ -373,7 +304,7 @@ proc processBlock(chainDB: BaseChainDB, vmState: BaseVMState, minedBlock: PlainB
# while still benefits from trie pruning # while still benefits from trie pruning
dbTx.commit(applyDeletes = false) dbTx.commit(applyDeletes = false)
func validateBlockUnchanged(a, b: PlainBlock): bool = func validateBlockUnchanged(a, b: EthBlock): bool =
result = rlp.encode(a) == rlp.encode(b) result = rlp.encode(a) == rlp.encode(b)
type Hash512 = MDigest[512] type Hash512 = MDigest[512]
@ -507,7 +438,7 @@ proc validateGasLimit(chainDB: BaseChainDB, header: BlockHeader) =
elif header.gasLimit > highBound: elif header.gasLimit > highBound:
raise newException(ValidationError, "The gas limit is too high") raise newException(ValidationError, "The gas limit is too high")
proc validateUncles(chainDB: BaseChainDB, currBlock: PlainBlock, checkSeal: bool) = proc validateUncles(chainDB: BaseChainDB, currBlock: EthBlock, checkSeal: bool) =
let hasUncles = currBlock.uncles.len > 0 let hasUncles = currBlock.uncles.len > 0
let shouldHaveUncles = currBlock.header.ommersHash != EMPTY_UNCLE_HASH let shouldHaveUncles = currBlock.header.ommersHash != EMPTY_UNCLE_HASH
@ -559,10 +490,10 @@ proc validateUncles(chainDB: BaseChainDB, currBlock: PlainBlock, checkSeal: bool
let uncleParent = chainDB.getBlockHeader(uncle.parentHash) let uncleParent = chainDB.getBlockHeader(uncle.parentHash)
validateUncle(currBlock.header, uncle, uncleParent) validateUncle(currBlock.header, uncle, uncleParent)
func isGenesis(currBlock: PlainBlock): bool = func isGenesis(currBlock: EthBlock): bool =
result = currBlock.header.blockNumber == 0.u256 and currBlock.header.parentHash == GENESIS_PARENT_HASH result = currBlock.header.blockNumber == 0.u256 and currBlock.header.parentHash == GENESIS_PARENT_HASH
proc validateBlock(chainDB: BaseChainDB, currBlock: PlainBlock, checkSeal: bool): bool = proc validateBlock(chainDB: BaseChainDB, currBlock: EthBlock, checkSeal: bool): bool =
if currBlock.isGenesis: if currBlock.isGenesis:
if currBlock.header.extraData.len > 32: if currBlock.header.extraData.len > 32:
raise newException(ValidationError, "BlockHeader.extraData larger than 32 bytes") raise newException(ValidationError, "BlockHeader.extraData larger than 32 bytes")
@ -583,7 +514,7 @@ proc validateBlock(chainDB: BaseChainDB, currBlock: PlainBlock, checkSeal: bool)
result = true result = true
proc importBlock(tester: var Tester, chainDB: BaseChainDB, proc importBlock(tester: var Tester, chainDB: BaseChainDB,
preminedBlock: PlainBlock, fork: Fork, checkSeal, validation = true): PlainBlock = preminedBlock: EthBlock, fork: Fork, checkSeal, validation = true): 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,
@ -612,14 +543,14 @@ proc importBlock(tester: var Tester, chainDB: BaseChainDB,
discard chainDB.persistHeaderToDb(preminedBlock.header) discard chainDB.persistHeaderToDb(preminedBlock.header)
proc applyFixtureBlockToChain(tester: var Tester, tb: TesterBlock, proc applyFixtureBlockToChain(tester: var Tester, tb: TestBlock,
chainDB: BaseChainDB, checkSeal, validation = true): (PlainBlock, PlainBlock, Blob) = chainDB: BaseChainDB, checkSeal, validation = true): (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
tester.vmConfig = vmConfiguration(tester.network, chainDB.config) tester.vmConfig = vmConfiguration(tester.network, chainDB.config)
var var
preminedBlock = rlp.decode(tb.headerRLP, PlainBlock) preminedBlock = rlp.decode(tb.blockRLP, EthBlock)
fork = vmConfigToFork(tester.vmConfig, preminedBlock.header.blockNumber) fork = vmConfigToFork(tester.vmConfig, preminedBlock.header.blockNumber)
minedBlock = tester.importBlock(chainDB, preminedBlock, fork, checkSeal, validation) minedBlock = tester.importBlock(chainDB, preminedBlock, fork, checkSeal, validation)
rlpEncodedMinedBlock = rlp.encode(minedBlock) rlpEncodedMinedBlock = rlp.encode(minedBlock)
@ -638,20 +569,18 @@ proc collectDebugData(tester: var Tester) =
} }
proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var TestStatus) = proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var TestStatus) =
discard chainDB.persistHeaderToDb(tester.genesisBlockHeader) discard chainDB.persistHeaderToDb(tester.genesisHeader)
check chainDB.getCanonicalHead().blockHash == tester.genesisBlockHeader.blockHash check chainDB.getCanonicalHead().blockHash == tester.genesisHeader.blockHash
let checkSeal = tester.shouldCheckSeal let checkSeal = tester.shouldCheckSeal
if tester.debugMode: if tester.debugMode:
tester.debugData = newJArray() tester.debugData = newJArray()
for idx, testerBlock in tester.blocks: for idx, TestBlock in tester.blocks:
let shouldBeGoodBlock = testerBlock.blockHeader.isSome if TestBlock.goodBlock:
if shouldBeGoodBlock:
try: try:
let (preminedBlock, _, _) = tester.applyFixtureBlockToChain( let (preminedBlock, _, _) = tester.applyFixtureBlockToChain(
testerBlock, chainDB, checkSeal, validation = false) # we manually validate below TestBlock, chainDB, checkSeal, validation = false) # 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()
@ -659,7 +588,7 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes
else: else:
var noError = true var noError = true
try: try:
let (_, _, _) = tester.applyFixtureBlockToChain(testerBlock, let (_, _, _) = tester.applyFixtureBlockToChain(TestBlock,
chainDB, checkSeal, validation = true) chainDB, checkSeal, validation = true)
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
@ -718,10 +647,8 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
var tester = parseTester(fixture, testStatusIMPL) var tester = parseTester(fixture, testStatusIMPL)
var chainDB = newBaseChainDB(newMemoryDb(), pruneTrie = test_config.getConfiguration().pruning) var chainDB = newBaseChainDB(newMemoryDb(), pruneTrie = test_config.getConfiguration().pruning)
if not tester.good: continue
var vmState = newBaseVMState(emptyRlpHash, var vmState = newBaseVMState(emptyRlpHash,
tester.genesisBlockHeader, chainDB) tester.genesisHeader, chainDB)
vmState.generateWitness = true vmState.generateWitness = true
@ -730,7 +657,7 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
db.persist() db.persist()
let obtainedHash = $(vmState.readOnlyStateDB.rootHash) let obtainedHash = $(vmState.readOnlyStateDB.rootHash)
check obtainedHash == $(tester.genesisBlockHeader.stateRoot) check obtainedHash == $(tester.genesisHeader.stateRoot)
tester.debugMode = debugMode tester.debugMode = debugMode
tester.trace = trace tester.trace = trace
@ -802,7 +729,7 @@ when isMainModule:
# genesisRLP -> NOT every fixture has it, rlp bytes of genesis block header # genesisRLP -> NOT every fixture has it, rlp bytes of genesis block header
# _info -> every fixture has it, can be omitted # _info -> every fixture has it, can be omitted
# pre, postState -> every fixture has it, prestate and post state # pre, postState -> every fixture has it, prestate and post state
# genesisBlockHeader -> every fixture has it # genesisHeader -> every fixture has it
# network -> every fixture has it # network -> every fixture has it
# # EIP150 247 # # EIP150 247
# # ConstantinopleFix 286 # # ConstantinopleFix 286