fix persistHeaderToDb, allow POS block header to be canonical

This commit is contained in:
jangko 2022-12-10 08:32:55 +07:00
parent 1cc6fc5cff
commit 13e5b1a76b
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
9 changed files with 50 additions and 78 deletions

View File

@ -53,11 +53,6 @@ proc main() =
inc stat.skipped
continue
# TODO: fix this after #1337 fixed
if "Merge" in name:
inc stat.skipped
continue
let cd = extractChainData(unit)
let status = processChainData(cd)
stat.inc(name, status)

View File

@ -350,7 +350,8 @@ proc initializeEmptyDb*(com: CommonRef)
trace "Writing genesis to DB"
doAssert(com.genesisHeader.blockNumber.isZero,
"can't commit genesis block with number > 0")
discard com.db.persistHeaderToDb(com.genesisHeader, none(BlockNumber))
discard com.db.persistHeaderToDb(com.genesisHeader,
com.consensusType == ConsensusType.POS)
doAssert(canonicalHeadHashKey().toOpenArray in trieDB)
# ------------------------------------------------------------------------------

View File

@ -118,8 +118,7 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader];
return ValidationResult.Error
if NoPersistHeader notin flags:
let ttd = c.com.ttd
discard c.db.persistHeaderToDb(header, ttd)
discard c.db.persistHeaderToDb(header, c.com.consensus == ConsensusType.POS)
if NoSaveTxs notin flags:
discard c.db.persistTransactions(header.blockNumber, body.transactions)

View File

@ -407,29 +407,8 @@ proc getReceipts*(db: ChainDBRef; receiptRoot: Hash256): seq[Receipt] =
receipts.add(r)
return receipts
proc readTerminalHash*(db: ChainDBRef; h: var Hash256): bool =
let bytes = db.db.get(terminalHashKey().toOpenArray)
if bytes.len == 0:
return false
try:
h = rlp.decode(bytes, Hash256)
except RlpError:
return false
true
proc writeTerminalHash*(db: ChainDBRef; h: Hash256) =
db.db.put(terminalHashKey().toOpenArray, rlp.encode(h))
proc currentTerminalHeader*(db: ChainDBRef; header: var BlockHeader): bool =
var terminalHash: Hash256
if not db.readTerminalHash(terminalHash):
return false
if not db.getBlockHeader(terminalHash, header):
return false
true
proc persistHeaderToDb*(db: ChainDBRef; header: BlockHeader, ttd: Option[DifficultyInt]): seq[BlockHeader] =
proc persistHeaderToDb*(db: ChainDBRef; header: BlockHeader,
forceCanonical: bool): seq[BlockHeader] =
let isGenesis = header.parentHash == GENESIS_PARENT_HASH
let headerHash = header.blockHash
if not isGenesis and not db.headerExists(header.parentHash):
@ -449,14 +428,7 @@ proc persistHeaderToDb*(db: ChainDBRef; header: BlockHeader, ttd: Option[Difficu
except CanonicalHeadNotFound:
return db.setAsCanonicalChainHead(headerHash)
if ttd.isSome:
let ttd = ttd.get()
if headScore < ttd and score >= ttd:
db.writeTerminalHash(headerHash)
if score >= ttd:
return db.setAsCanonicalChainHead(headerHash)
if score > headScore:
if score > headScore or forceCanonical:
return db.setAsCanonicalChainHead(headerHash)
proc persistHeaderToDbWithoutSetHead*(db: ChainDBRef; header: BlockHeader) =

View File

@ -12,7 +12,6 @@ type
contractHash
cliqueSnapshot
transitionStatus
terminalHash
safeHash
finalizedHash
skeletonProgress
@ -74,10 +73,6 @@ proc transitionStatusKey*(): DbKey =
result.data[0] = byte ord(transitionStatus)
result.dataEndPos = uint8 1
proc terminalHashKey*(): DbKey =
result.data[0] = byte ord(terminalHash)
result.dataEndPos = uint8 1
proc safeHashKey*(): DbKey {.inline.} =
result.data[0] = byte ord(safeHash)
result.dataEndPos = uint8 1

View File

@ -160,25 +160,35 @@ proc setupEngineApi*(
blockHash = conf.terminalBlockHash
let db = sealingEngine.chain.db
let ttd = com.ttd.get(high(common.BlockNumber))
let ttd = com.ttd
if conf.terminalTotalDifficulty != ttd:
raise newException(ValueError, "invalid ttd: EL $1 CL $2" % [$ttd, $conf.terminalTotalDifficulty])
if ttd.isNone:
raise newException(ValueError, "invalid ttd: EL (none) CL ($2)" % [$conf.terminalTotalDifficulty])
var header: EthBlockHeader
let terminalBlockNumber = uint64(conf.terminalBlockNumber)
if conf.terminalTotalDifficulty != ttd.get:
raise newException(ValueError, "invalid ttd: EL ($1) CL ($2)" % [$ttd.get, $conf.terminalTotalDifficulty])
let terminalBlockNumber = uint64(conf.terminalBlockNumber).toBlockNumber
let terminalBlockHash = conf.terminalBlockHash.asEthHash
if db.currentTerminalHeader(header):
let headerHash = header.blockHash
if terminalBlockNumber != 0'u64 and terminalBlockNumber != header.blockNumber.truncate(uint64):
raise newException(ValueError, "invalid terminal block number, got $1 want $2" % [$terminalBlockNumber, $header.blockNumber])
if terminalBlockHash != Hash256():
var headerHash: Hash256
if terminalBlockHash != Hash256() and terminalBlockHash != headerHash:
raise newException(ValueError, "invalid terminal block hash, got $1 want $2" % [$terminalBlockHash, $headerHash])
if not db.getBlockHash(terminalBlockNumber, headerHash):
raise newException(ValueError, "cannot get terminal block hash, number $1" %
[$terminalBlockNumber])
if terminalBlockHash != headerHash:
raise newException(ValueError, "invalid terminal block hash, got $1 want $2" %
[$terminalBlockHash, $headerHash])
var header: EthBlockHeader
if not db.getBlockHeader(headerHash, header):
raise newException(ValueError, "cannot get terminal block header, hash $1" %
[$terminalBlockHash])
return TransitionConfigurationV1(
terminalTotalDifficulty: ttd,
terminalTotalDifficulty: ttd.get,
terminalBlockHash : BlockHash headerHash.data,
terminalBlockNumber : Quantity header.blockNumber.truncate(uint64)
)
@ -189,7 +199,7 @@ proc setupEngineApi*(
if terminalBlockHash != Hash256():
raise newException(ValueError, "invalid terminal block hash, no terminal header set")
return TransitionConfigurationV1(terminalTotalDifficulty: ttd)
return TransitionConfigurationV1(terminalTotalDifficulty: ttd.get)
# ForkchoiceUpdatedV1 has several responsibilities:
# If the method is called with an empty head block:

View File

@ -197,7 +197,8 @@ proc importBlock(tester: var Tester, com: CommonRef,
if tester.vmState.generateWitness():
blockWitness(tester.vmState, com.db)
discard com.db.persistHeaderToDb(tb.header, none(DifficultyInt))
discard com.db.persistHeaderToDb(tb.header,
com.consensus == ConsensusType.POS)
proc applyFixtureBlockToChain(tester: var Tester, tb: var TestBlock,
com: CommonRef, checkSeal, validation: bool) =
@ -222,7 +223,8 @@ proc collectDebugData(tester: var Tester) =
}
proc runTester(tester: var Tester, com: CommonRef, testStatusIMPL: var TestStatus) =
discard com.db.persistHeaderToDb(tester.genesisHeader, none(DifficultyInt))
discard com.db.persistHeaderToDb(tester.genesisHeader,
com.consensus == ConsensusType.POS)
check com.db.getCanonicalHead().blockHash == tester.genesisHeader.blockHash
let checkSeal = tester.shouldCheckSeal
@ -371,17 +373,21 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
var success = true
try:
tester.runTester(com, testStatusIMPL)
let latestBlockHash = com.db.getCanonicalHead().blockHash
if latestBlockHash != tester.lastBlockHash:
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)
let header = com.db.getCanonicalHead()
let lastBlockHash = header.blockHash
check lastBlockHash == tester.lastBlockHash
if tester.postStateHash != Hash256():
let rootHash = tester.vmState.stateDB.rootHash
if tester.postStateHash != rootHash:
raise newException(ValidationError, "incorrect postStateHash, expect=" &
$rootHash & ", get=" &
$tester.postStateHash
)
elif lastBlockHash == tester.lastBlockHash:
# multiple chain, we are using the last valid canonical
# state root to test against 'postState'
let stateDB = AccountsCache.init(memDB, header.stateRoot, pruneTrie)
verifyStateDB(fixture["postState"], ReadOnlyStateDB(stateDB))
except ValidationError as E:
echo fixtureName, " ERROR: ", E.msg
success = false

View File

@ -123,7 +123,8 @@ proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv
let uncles = [header]
header.ommersHash = com.db.persistUncles(uncles)
discard com.db.persistHeaderToDb(header, none(DifficultyInt))
discard com.db.persistHeaderToDb(header,
com.consensus == ConsensusType.POS)
com.db.persistFixtureBlock()
result = TestEnv(
txHash: signedTx1.rlpHash,

View File

@ -275,13 +275,6 @@ proc runTxHeadDelta*(noisy = true) =
# Commit to block chain
check chain.persistBlocks([blk.header], [body]).isOk
# If not for other reason, setting head is irrelevant for this test
#
# # PoS block canonical head must be explicitly set using setHead.
# # The function `persistHeaderToDb()` used in `persistBlocks()`
# # does not reliably do so due to scoring.
# chainDB.setHead(blk.header)
# Synchronise TxPool against new chain head, register txs differences.
# In this particular case, these differences will simply flush the
# packer bucket.