Compare commits

..

No commits in common. "73a0f7caeb7d27f8d2bb31dcad7f49e227f71952" and "682d0ff575ce87c13690ce27955634ef16a3027d" have entirely different histories.

1 changed files with 48 additions and 126 deletions

View File

@ -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()