fix block pool init head selection
the head state is not necessarily saved in the database, so we need to make sure we update things to the correct place
This commit is contained in:
parent
b49003988a
commit
860be026e1
|
@ -173,8 +173,9 @@ type
|
||||||
data*: HashedBeaconState
|
data*: HashedBeaconState
|
||||||
|
|
||||||
blck*: BlockRef ##\
|
blck*: BlockRef ##\
|
||||||
## The block associated with the state found in data - in particular,
|
## The block associated with the state found in data - normally
|
||||||
## blck.state_root == rdata.root
|
## `blck.state_root == data.root` but the state might have been advanced
|
||||||
|
## further with empty slots invalidating this condition.
|
||||||
|
|
||||||
BlockSlot* = object
|
BlockSlot* = object
|
||||||
## Unique identifier for a particular fork and time in the block chain -
|
## Unique identifier for a particular fork and time in the block chain -
|
||||||
|
|
|
@ -159,7 +159,7 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
|
|
||||||
var
|
var
|
||||||
blocks = {tailRef.root: tailRef}.toTable()
|
blocks = {tailRef.root: tailRef}.toTable()
|
||||||
latestStateRoot = Option[Eth2Digest]()
|
latestStateRoot = Option[tuple[stateRoot: Eth2Digest, blckRef: BlockRef]]()
|
||||||
headRef: BlockRef
|
headRef: BlockRef
|
||||||
|
|
||||||
if headRoot != tailRoot:
|
if headRoot != tailRoot:
|
||||||
|
@ -183,13 +183,18 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
trace "Populating block pool", key = curRef.root, val = curRef
|
trace "Populating block pool", key = curRef.root, val = curRef
|
||||||
|
|
||||||
if latestStateRoot.isNone() and db.containsState(blck.message.state_root):
|
if latestStateRoot.isNone() and db.containsState(blck.message.state_root):
|
||||||
latestStateRoot = some(blck.message.state_root)
|
latestStateRoot = some((blck.message.state_root, curRef))
|
||||||
|
|
||||||
doAssert curRef == tailRef,
|
doAssert curRef == tailRef,
|
||||||
"head block does not lead to tail, database corrupt?"
|
"head block does not lead to tail, database corrupt?"
|
||||||
else:
|
else:
|
||||||
headRef = tailRef
|
headRef = tailRef
|
||||||
|
|
||||||
|
if latestStateRoot.isNone():
|
||||||
|
doAssert db.containsState(tailBlock.message.state_root),
|
||||||
|
"state data missing for tail block, database corrupt?"
|
||||||
|
latestStateRoot = some((tailBlock.message.state_root, tailRef))
|
||||||
|
|
||||||
var blocksBySlot = initTable[Slot, seq[BlockRef]]()
|
var blocksBySlot = initTable[Slot, seq[BlockRef]]()
|
||||||
for _, b in tables.pairs(blocks):
|
for _, b in tables.pairs(blocks):
|
||||||
let slot = db.getBlock(b.root).get().message.slot
|
let slot = db.getBlock(b.root).get().message.slot
|
||||||
|
@ -199,24 +204,15 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
# many live beaconstates on the stack...
|
# many live beaconstates on the stack...
|
||||||
var tmpState = new Option[BeaconState]
|
var tmpState = new Option[BeaconState]
|
||||||
|
|
||||||
|
# We're only saving epoch boundary states in the database right now, so when
|
||||||
|
# we're loading the head block, the corresponding state does not necessarily
|
||||||
|
# exist in the database - we'll load this latest state we know about and use
|
||||||
|
# that as finalization point.
|
||||||
|
tmpState[] = db.getState(latestStateRoot.get().stateRoot)
|
||||||
let
|
let
|
||||||
# The head state is necessary to find out what we considered to be the
|
finalizedSlot =
|
||||||
# finalized epoch last time we saved something.
|
tmpState[].get().current_justified_checkpoint.epoch.compute_start_slot_at_epoch()
|
||||||
headStateRoot =
|
finalizedHead = headRef.findAncestorBySlot(finalizedSlot)
|
||||||
if latestStateRoot.isSome():
|
|
||||||
latestStateRoot.get()
|
|
||||||
else:
|
|
||||||
db.getBlock(tailRef.root).get().message.state_root
|
|
||||||
|
|
||||||
# TODO right now, because we save a state at every epoch, this *should*
|
|
||||||
# be the latest justified state or newer, meaning it's enough for
|
|
||||||
# establishing what we consider to be the finalized head. This logic
|
|
||||||
# will need revisiting however
|
|
||||||
tmpState[] = db.getState(headStateRoot)
|
|
||||||
let
|
|
||||||
finalizedHead =
|
|
||||||
headRef.findAncestorBySlot(
|
|
||||||
tmpState[].get().finalized_checkpoint.epoch.compute_start_slot_at_epoch())
|
|
||||||
justifiedSlot =
|
justifiedSlot =
|
||||||
tmpState[].get().current_justified_checkpoint.epoch.compute_start_slot_at_epoch()
|
tmpState[].get().current_justified_checkpoint.epoch.compute_start_slot_at_epoch()
|
||||||
justifiedHead = headRef.findAncestorBySlot(justifiedSlot)
|
justifiedHead = headRef.findAncestorBySlot(justifiedSlot)
|
||||||
|
@ -244,8 +240,11 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
)
|
)
|
||||||
|
|
||||||
res.headState = StateData(
|
res.headState = StateData(
|
||||||
data: HashedBeaconState(data: tmpState[].get(), root: headStateRoot),
|
data: HashedBeaconState(
|
||||||
blck: headRef)
|
data: tmpState[].get(), root: latestStateRoot.get().stateRoot),
|
||||||
|
blck: latestStateRoot.get().blckRef)
|
||||||
|
|
||||||
|
res.updateStateData(res.headState, BlockSlot(blck: head.blck, slot: head.blck.slot))
|
||||||
res.tmpState = res.headState
|
res.tmpState = res.headState
|
||||||
|
|
||||||
tmpState[] = db.getState(justifiedStateRoot)
|
tmpState[] = db.getState(justifiedStateRoot)
|
||||||
|
@ -253,7 +252,6 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
data: HashedBeaconState(data: tmpState[].get(), root: justifiedStateRoot),
|
data: HashedBeaconState(data: tmpState[].get(), root: justifiedStateRoot),
|
||||||
blck: justifiedHead.blck)
|
blck: justifiedHead.blck)
|
||||||
|
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
||||||
proc addSlotMapping(pool: BlockPool, br: BlockRef) =
|
proc addSlotMapping(pool: BlockPool, br: BlockRef) =
|
||||||
|
@ -925,6 +923,7 @@ proc preInit*(
|
||||||
let
|
let
|
||||||
blockRoot = hash_tree_root(signedBlock.message)
|
blockRoot = hash_tree_root(signedBlock.message)
|
||||||
|
|
||||||
|
doAssert signedBlock.message.state_root == hash_tree_root(state)
|
||||||
notice "New database from snapshot",
|
notice "New database from snapshot",
|
||||||
blockRoot = shortLog(blockRoot),
|
blockRoot = shortLog(blockRoot),
|
||||||
stateRoot = shortLog(signedBlock.message.state_root),
|
stateRoot = shortLog(signedBlock.message.state_root),
|
||||||
|
|
|
@ -354,7 +354,7 @@ type
|
||||||
# TODO to be replaced with some magic hash caching
|
# TODO to be replaced with some magic hash caching
|
||||||
HashedBeaconState* = object
|
HashedBeaconState* = object
|
||||||
data*: BeaconState
|
data*: BeaconState
|
||||||
root*: Eth2Digest # hash_tree_root (not signing_root!)
|
root*: Eth2Digest # hash_tree_root(data)
|
||||||
|
|
||||||
StateCache* = object
|
StateCache* = object
|
||||||
beacon_committee_cache*:
|
beacon_committee_cache*:
|
||||||
|
|
|
@ -92,7 +92,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
||||||
b1 = addBlock(state, pool.tail.root, BeaconBlockBody())
|
b1 = addBlock(state, pool.tail.root, BeaconBlockBody())
|
||||||
b1Root = hash_tree_root(b1.message)
|
b1Root = hash_tree_root(b1.message)
|
||||||
b2 = addBlock(state, b1Root, BeaconBlockBody())
|
b2 = addBlock(state, b1Root, BeaconBlockBody())
|
||||||
b2Root = hash_tree_root(b2.message)
|
b2Root {.used.} = hash_tree_root(b2.message)
|
||||||
|
|
||||||
timedTest "getRef returns nil for missing blocks":
|
timedTest "getRef returns nil for missing blocks":
|
||||||
check:
|
check:
|
||||||
|
@ -147,7 +147,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
||||||
toSeq(pool.blockRootsForSlot(b1.message.slot)) == @[b1Root]
|
toSeq(pool.blockRootsForSlot(b1.message.slot)) == @[b1Root]
|
||||||
toSeq(pool.blockRootsForSlot(b2.message.slot)) == @[b2Root]
|
toSeq(pool.blockRootsForSlot(b2.message.slot)) == @[b2Root]
|
||||||
|
|
||||||
db.putHeadBlock(b2Root)
|
pool.updateHead(b2Get.get().refs)
|
||||||
|
|
||||||
# The heads structure should have been updated to contain only the new
|
# The heads structure should have been updated to contain only the new
|
||||||
# b2 head
|
# b2 head
|
||||||
|
@ -159,6 +159,9 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
||||||
pool2 = BlockPool.init(db)
|
pool2 = BlockPool.init(db)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
# ensure we loaded the correct head state
|
||||||
|
pool2.head.blck.root == b2Root
|
||||||
|
hash_tree_root(pool2.headState.data.data) == b2.message.state_root
|
||||||
pool2.get(b1Root).isSome()
|
pool2.get(b1Root).isSome()
|
||||||
pool2.get(b2Root).isSome()
|
pool2.get(b2Root).isSome()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue