Compare commits
No commits in common. "73a0f7caeb7d27f8d2bb31dcad7f49e227f71952" and "682d0ff575ce87c13690ce27955634ef16a3027d" have entirely different histories.
73a0f7caeb
...
682d0ff575
|
@ -18,37 +18,31 @@ import
|
|||
../executor/process_block
|
||||
|
||||
type
|
||||
HeadDesc = object
|
||||
number: BlockNumber
|
||||
hash: Hash256
|
||||
|
||||
BlockDesc = object
|
||||
blk: EthBlock
|
||||
receipts: seq[Receipt]
|
||||
|
||||
ForkedChain* = object
|
||||
stagingTx: CoreDbTxRef
|
||||
db: CoreDbRef
|
||||
com: CommonRef
|
||||
blocks: Table[Hash256, BlockDesc]
|
||||
headHash: Hash256
|
||||
baseHash: Hash256
|
||||
baseHeader: BlockHeader
|
||||
headHeader: BlockHeader
|
||||
heads: seq[HeadDesc]
|
||||
blocks: Table[Hash256, EthBlock]
|
||||
head: Hash256
|
||||
base: Hash256
|
||||
headBlockNumber: BlockNumber
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc processBlock(c: ForkedChain,
|
||||
parent: BlockHeader,
|
||||
blk: EthBlock): Result[seq[Receipt], string] =
|
||||
proc getVmState(c: ForkedChain,
|
||||
header: BlockHeader): Result[BaseVMState, string] =
|
||||
let vmState = BaseVMState()
|
||||
if not vmState.init(header, c.com):
|
||||
return err("Could not initialise VMState")
|
||||
ok(vmState)
|
||||
|
||||
proc processBlock(c: ForkedChain, blk: EthBlock): Result[void, string] =
|
||||
template header(): BlockHeader =
|
||||
blk.header
|
||||
|
||||
let vmState = BaseVMState()
|
||||
vmState.init(parent, header, c.com)
|
||||
let vmState = ?c.getVmState(header)
|
||||
c.com.hardForkTransition(header)
|
||||
|
||||
?c.com.validateHeaderAndKinship(blk, vmState.parent, checkSealOK = false)
|
||||
|
@ -60,8 +54,6 @@ proc processBlock(c: ForkedChain,
|
|||
skipUncles = true,
|
||||
)
|
||||
|
||||
# We still need to write header to database
|
||||
# because validateUncles still need it
|
||||
let blockHash = header.blockHash()
|
||||
if not c.db.persistHeader(
|
||||
blockHash,
|
||||
|
@ -69,102 +61,55 @@ proc processBlock(c: ForkedChain,
|
|||
c.com.startOfHistory):
|
||||
return err("Could not persist header")
|
||||
|
||||
ok(move(vmState.receipts))
|
||||
ok()
|
||||
|
||||
proc updateHeads(c: var ForkedChain,
|
||||
hash: Hash256,
|
||||
header: BlockHeader) =
|
||||
for i in 0..<c.heads.len:
|
||||
if c.heads[i].hash == header.parentHash:
|
||||
c.heads[i] = HeadDesc(
|
||||
hash: hash,
|
||||
number: header.number,
|
||||
)
|
||||
return
|
||||
|
||||
c.heads.add HeadDesc(
|
||||
hash: hash,
|
||||
number: header.number,
|
||||
)
|
||||
|
||||
proc updateHead(c: var ForkedChain,
|
||||
blk: EthBlock,
|
||||
receipts: sink seq[Receipt]) =
|
||||
proc updateHead(c: var ForkedChain, blk: EthBlock) =
|
||||
template header(): BlockHeader =
|
||||
blk.header
|
||||
|
||||
c.headHeader = header
|
||||
c.headHash = header.blockHash
|
||||
c.blocks[c.headHash] = BlockDesc(
|
||||
blk: blk,
|
||||
receipts: move(receipts)
|
||||
)
|
||||
c.updateHeads(c.headHash, header)
|
||||
c.head = header.blockHash
|
||||
c.headBlockNumber = header.number
|
||||
c.blocks[c.head] = blk
|
||||
|
||||
proc validatePotentialHead(c: var ForkedChain,
|
||||
parent: BlockHeader,
|
||||
blk: EthBlock,
|
||||
updateHead: bool = true) =
|
||||
let dbTx = c.db.newTransaction()
|
||||
defer:
|
||||
dbTx.dispose()
|
||||
|
||||
var res = c.processBlock(parent, blk)
|
||||
let res = c.processBlock(blk)
|
||||
if res.isErr:
|
||||
dbTx.rollback()
|
||||
return
|
||||
|
||||
dbTx.commit()
|
||||
if updateHead:
|
||||
c.updateHead(blk, move(res.value))
|
||||
c.updateHead(blk)
|
||||
|
||||
proc replaySegment(c: var ForkedChain,
|
||||
head: Hash256) =
|
||||
head: Hash256): BlockNumber =
|
||||
var
|
||||
prevHash = head
|
||||
chain = newSeq[EthBlock]()
|
||||
|
||||
while prevHash != c.baseHash:
|
||||
chain.add c.blocks[prevHash].blk
|
||||
while prevHash != c.base:
|
||||
chain.add c.blocks[prevHash]
|
||||
prevHash = chain[^1].header.parentHash
|
||||
|
||||
c.stagingTx.rollback()
|
||||
c.stagingTx = c.db.newTransaction()
|
||||
c.headHeader = c.baseHeader
|
||||
for i in countdown(chain.high, chain.low):
|
||||
c.validatePotentialHead(c.headHeader, chain[i], updateHead = false)
|
||||
c.headHeader = chain[i].header
|
||||
c.validatePotentialHead(chain[i], updateHead = false)
|
||||
|
||||
proc writeBaggage(c: var ForkedChain, blockHash: Hash256) =
|
||||
var prevHash = blockHash
|
||||
while prevHash != c.baseHash:
|
||||
let blk = c.blocks[prevHash]
|
||||
c.db.persistTransactions(blk.blk.header.number, blk.blk.transactions)
|
||||
c.db.persistReceipts(blk.receipts)
|
||||
discard c.db.persistUncles(blk.blk.uncles)
|
||||
if blk.blk.withdrawals.isSome:
|
||||
c.db.persistWithdrawals(blk.blk.withdrawals.get)
|
||||
prevHash = blk.blk.header.parentHash
|
||||
chain[^1].header.number
|
||||
|
||||
proc updateBase(c: var ForkedChain,
|
||||
newBaseHash: Hash256, newBaseHeader: BlockHeader) =
|
||||
# remove obsolete chains
|
||||
for i in 0..<c.heads.len:
|
||||
if c.heads[i].number <= c.baseHeader.number:
|
||||
var prevHash = c.heads[i].hash
|
||||
while prevHash != c.baseHash:
|
||||
c.blocks.withValue(prevHash, val) do:
|
||||
let rmHash = prevHash
|
||||
prevHash = val.blk.header.parentHash
|
||||
c.blocks.del(rmHash)
|
||||
do:
|
||||
# older chain segment have been deleted
|
||||
# by previous head
|
||||
break
|
||||
c.heads.del(i)
|
||||
|
||||
c.baseHeader = newBaseHeader
|
||||
c.baseHash = newBaseHash
|
||||
head: Hash256, headBlockNumber: BlockNumber) =
|
||||
c.base = head
|
||||
c.head = head
|
||||
c.headBlockNumber = headBlockNumber
|
||||
c.blocks.clear()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
|
@ -174,24 +119,23 @@ proc initForkedChain*(com: CommonRef): ForkedChain =
|
|||
result.com = com
|
||||
result.db = com.db
|
||||
result.stagingTx = com.db.newTransaction()
|
||||
result.baseHeader = com.db.getCanonicalHead()
|
||||
let headHash = result.baseHeader.blockHash
|
||||
result.headHash = headHash
|
||||
result.baseHash = headHash
|
||||
result.headHeader = result.baseHeader
|
||||
let head = com.db.getCanonicalHead()
|
||||
let headHash = head.blockHash
|
||||
result.head = headHash
|
||||
result.base = headHash
|
||||
|
||||
proc addBlock*(c: var ForkedChain, blk: EthBlock) =
|
||||
template header(): BlockHeader =
|
||||
blk.header
|
||||
|
||||
if header.parentHash == c.headHash:
|
||||
c.validatePotentialHead(c.headHeader, blk)
|
||||
if header.parentHash == c.head:
|
||||
c.validatePotentialHead(blk)
|
||||
return
|
||||
|
||||
if header.parentHash == c.baseHash:
|
||||
if header.parentHash == c.base:
|
||||
c.stagingTx.rollback()
|
||||
c.stagingTx = c.db.newTransaction()
|
||||
c.validatePotentialHead(c.baseHeader, blk)
|
||||
c.validatePotentialHead(blk)
|
||||
return
|
||||
|
||||
if header.parentHash notin c.blocks:
|
||||
|
@ -199,57 +143,35 @@ proc addBlock*(c: var ForkedChain, blk: EthBlock) =
|
|||
# there is no hope the descendant is valid
|
||||
return
|
||||
|
||||
c.replaySegment(header.parentHash)
|
||||
c.validatePotentialHead(c.headHeader, blk)
|
||||
discard c.replaySegment(header.parentHash)
|
||||
c.validatePotentialHead(blk)
|
||||
|
||||
proc finalizeSegment*(c: var ForkedChain,
|
||||
finalizedHash: Hash256): Result[void, string] =
|
||||
if finalizedHash == c.headHash:
|
||||
c.writeBaggage(finalizedHash)
|
||||
|
||||
finalized: Hash256): Result[void, string] =
|
||||
if finalized == c.head:
|
||||
# the current segment is canonical chain
|
||||
c.stagingTx.commit()
|
||||
|
||||
# Save and record the block number before the last saved block state.
|
||||
c.db.persistent(c.headHeader.number).isOkOr:
|
||||
c.db.persistent(c.headBlockNumber).isOkOr:
|
||||
return err("Failed to save state: " & $$error)
|
||||
|
||||
c.updateBase(finalized, c.headBlockNumber)
|
||||
c.stagingTx = c.db.newTransaction()
|
||||
|
||||
c.updateBase(finalizedHash, c.headHeader)
|
||||
return ok()
|
||||
|
||||
var
|
||||
newBaseHash: Hash256
|
||||
newBaseHeader: BlockHeader
|
||||
|
||||
c.blocks.withValue(finalizedHash, val) do:
|
||||
if c.headHeader.number <= 128:
|
||||
if val.blk.header.number < c.headHeader.number:
|
||||
newBaseHash = finalizedHash
|
||||
newBaseHeader = val.blk.header
|
||||
else:
|
||||
newBaseHash = c.headHash
|
||||
newBaseHeader = c.headHeader
|
||||
elif val.blk.header.number < c.headHeader.number - 128:
|
||||
newBaseHash = finalizedHash
|
||||
newBaseHeader = val.blk.header
|
||||
else:
|
||||
newBaseHash = c.headHash
|
||||
newBaseHeader = c.headHeader
|
||||
do:
|
||||
if finalized notin c.blocks:
|
||||
return err("Finalized head not in segments list")
|
||||
|
||||
c.stagingTx.rollback()
|
||||
c.stagingTx = c.db.newTransaction()
|
||||
c.replaySegment(newBaseHash)
|
||||
c.writeBaggage(newBaseHash)
|
||||
let headBlockNumber = c.replaySegment(finalized)
|
||||
|
||||
c.stagingTx.commit()
|
||||
c.db.persistent(newBaseHeader.number).isOkOr:
|
||||
c.db.persistent(headBlockNumber).isOkOr:
|
||||
return err("Failed to save state: " & $$error)
|
||||
|
||||
c.updateBase(finalized, headBlockNumber)
|
||||
c.stagingTx = c.db.newTransaction()
|
||||
c.updateBase(newBaseHash, newBaseHeader)
|
||||
|
||||
ok()
|
||||
|
|
Loading…
Reference in New Issue