mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-09 13:56:23 +00:00
updates
* comment on last finalized state * use explicitly named proc's instead of type tricks
This commit is contained in:
parent
1d9c91d230
commit
4c2d212781
@ -13,8 +13,6 @@ type
|
||||
kHashToBlock
|
||||
kHeadBlock
|
||||
|
||||
DbTypes = BeaconState | BeaconBlock
|
||||
|
||||
func subkey(kind: DbKeyKind): array[1, byte] =
|
||||
result[0] = byte ord(kind)
|
||||
|
||||
@ -33,17 +31,32 @@ proc init*(T: type BeaconChainDB, backend: TrieDatabaseRef): BeaconChainDB =
|
||||
new result
|
||||
result.backend = backend
|
||||
|
||||
proc put*(db: BeaconChainDB, key: Eth2Digest, value: BeaconBlock) =
|
||||
proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: BeaconBlock) =
|
||||
db.backend.put(subkey(type value, key), ssz.serialize(value))
|
||||
|
||||
proc putHead*(db: BeaconChainDB, key: Eth2Digest) =
|
||||
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?
|
||||
|
||||
proc put*(db: BeaconChainDB, key: Eth2Digest, value: BeaconState) =
|
||||
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: BeaconState) =
|
||||
# TODO: prune old states
|
||||
# TODO: it might be necessary to introduce the concept of a "last finalized
|
||||
# state" to the storage, so that clients with limited storage have
|
||||
# a natural state to start recovering from. One idea is to keep a
|
||||
# special pointer to the state that has ben finalized, and prune all
|
||||
# other states.
|
||||
# One issue is that what will become a finalized is revealed only
|
||||
# long after that state has passed, meaning that we need to keep
|
||||
# a history of "finalized state candidates" or possibly replay from
|
||||
# the previous finalized state, if we have that stored. To consider
|
||||
# here is that the gap between finalized and present state might be
|
||||
# significant (days), meaning replay might be expensive.
|
||||
db.backend.put(subkey(type value, key), ssz.serialize(value))
|
||||
|
||||
proc put*(db: BeaconChainDB, value: DbTypes) =
|
||||
db.put(hash_tree_root_final(value), value)
|
||||
proc putBlock*(db: BeaconChainDB, value: BeaconBlock) =
|
||||
db.putBlock(hash_tree_root_final(value), value)
|
||||
|
||||
proc putState*(db: BeaconChainDB, value: BeaconState) =
|
||||
db.putState(hash_tree_root_final(value), value)
|
||||
|
||||
proc get(db: BeaconChainDB, key: auto, T: typedesc): Option[T] =
|
||||
let res = db.backend.get(key)
|
||||
@ -52,26 +65,29 @@ proc get(db: BeaconChainDB, key: auto, T: typedesc): Option[T] =
|
||||
else:
|
||||
none(T)
|
||||
|
||||
# TODO: T: type DbTypes fails with compiler error.. investigate
|
||||
proc get*(db: BeaconChainDB, key: Eth2Digest, T: type BeaconBlock): Option[T] =
|
||||
db.get(subkey(T, key), T)
|
||||
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Option[BeaconBlock] =
|
||||
db.get(subkey(BeaconBlock, key), BeaconBlock)
|
||||
|
||||
proc get*(db: BeaconChainDB, key: Eth2Digest, T: type BeaconState): Option[T] =
|
||||
db.get(subkey(T, key), T)
|
||||
proc getState*(db: BeaconChainDB, key: Eth2Digest): Option[BeaconState] =
|
||||
db.get(subkey(BeaconState, key), BeaconState)
|
||||
|
||||
proc getHead*(db: BeaconChainDB, T: type BeaconBlock): Option[T] =
|
||||
proc getHead*(db: BeaconChainDB): Option[BeaconBlock] =
|
||||
let key = db.backend.get(subkey(kHeadBlock))
|
||||
if key.len == sizeof(Eth2Digest):
|
||||
var tmp: Eth2Digest
|
||||
copyMem(addr tmp, unsafeAddr key[0], sizeof(tmp))
|
||||
|
||||
db.get(tmp, T)
|
||||
db.getBlock(tmp)
|
||||
else:
|
||||
none(T)
|
||||
none(BeaconBlock)
|
||||
|
||||
proc contains*(
|
||||
db: BeaconChainDB, key: Eth2Digest, T: type DbTypes): bool =
|
||||
db.backend.contains(subkey(T, key))
|
||||
proc containsBlock*(
|
||||
db: BeaconChainDB, key: Eth2Digest): bool =
|
||||
db.backend.contains(subkey(BeaconBlock, key))
|
||||
|
||||
proc containsState*(
|
||||
db: BeaconChainDB, key: Eth2Digest): bool =
|
||||
db.backend.contains(subkey(BeaconBlock, key))
|
||||
|
||||
proc getAncestors*(
|
||||
db: BeaconChainDB, blck: BeaconBlock,
|
||||
@ -87,7 +103,7 @@ proc getAncestors*(
|
||||
result = @[blck]
|
||||
|
||||
while result[^1].slot > 0.Slot:
|
||||
let parent = db.get(result[^1].parent_root, BeaconBlock)
|
||||
let parent = db.getBlock(result[^1].parent_root)
|
||||
|
||||
if parent.isNone(): break
|
||||
|
||||
|
@ -59,7 +59,7 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): T =
|
||||
# TODO does it really make sense to load from DB if a state snapshot has been
|
||||
# specified on command line? potentially, this should be the other way
|
||||
# around...
|
||||
if (let head = result.db.getHead(BeaconBlock) ; head.isSome()):
|
||||
if (let head = result.db.getHead(); head.isSome()):
|
||||
info "Loading head from database",
|
||||
blockSlot = humaneSlotNum(head.get().slot)
|
||||
updateHeadBlock(result, head.get())
|
||||
@ -70,10 +70,10 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): T =
|
||||
|
||||
info "Loaded state from snapshot",
|
||||
stateSlot = humaneSlotNum(result.beaconState.slot)
|
||||
result.db.put(result.beaconState)
|
||||
result.db.putState(result.beaconState)
|
||||
# The genesis block is special in that we have to store it at hash 0 - in
|
||||
# the genesis state, this block has not been applied..
|
||||
result.db.put(result.headBlock)
|
||||
result.db.putBlock(result.headBlock)
|
||||
|
||||
result.keys = ensureNetworkKeys(string conf.dataDir)
|
||||
|
||||
@ -406,7 +406,7 @@ proc onAttestation(node: BeaconNode, attestation: Attestation) =
|
||||
|
||||
node.attestationPool.add(attestation, node.beaconState)
|
||||
|
||||
if not node.db.contains(attestation.data.beacon_block_root, BeaconBlock):
|
||||
if not node.db.containsBlock(attestation.data.beacon_block_root):
|
||||
notice "Attestation block root missing",
|
||||
beaconBlockRoot = shortHash(attestation.data.beacon_block_root)
|
||||
# TODO download...
|
||||
@ -453,12 +453,12 @@ proc updateHeadBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
# in the database.
|
||||
let
|
||||
ancestors = node.db.getAncestors(blck) do (bb: BeaconBlock) -> bool:
|
||||
node.db.contains(bb.state_root, BeaconState)
|
||||
node.db.containsState(bb.state_root)
|
||||
ancestor = ancestors[^1]
|
||||
|
||||
# Several things can happen, but the most common one should be that we found
|
||||
# a beacon state
|
||||
if (let state = node.db.get(ancestor.state_root, BeaconState); state.isSome()):
|
||||
if (let state = node.db.getState(ancestor.state_root); state.isSome()):
|
||||
# Got it!
|
||||
notice "Replaying state transitions",
|
||||
stateSlot = humaneSlotNum(node.beaconState.slot),
|
||||
@ -525,7 +525,7 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
blockRoot = hash_tree_root_final(blck)
|
||||
stateSlot = node.beaconState.slot
|
||||
|
||||
if node.db.contains(blockRoot, BeaconBlock):
|
||||
if node.db.containsBlock(blockRoot):
|
||||
debug "Block already seen",
|
||||
slot = humaneSlotNum(blck.slot),
|
||||
stateRoot = shortHash(blck.state_root),
|
||||
@ -546,7 +546,7 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
|
||||
# The block has been validated and it's not in the database yet - first, let's
|
||||
# store it there, just to be safe
|
||||
node.db.put(blck)
|
||||
node.db.putBlock(blck)
|
||||
|
||||
# Since this is a good block, we should add its attestations in case we missed
|
||||
# any. If everything checks out, this should lead to the fork choice selecting
|
||||
@ -578,7 +578,7 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
|
||||
updateHeadBlock(node, blck)
|
||||
|
||||
if stateNeedsSaving(node.beaconState):
|
||||
node.db.put(node.beaconState)
|
||||
node.db.putState(node.beaconState)
|
||||
|
||||
proc run*(node: BeaconNode) =
|
||||
node.network.subscribe(topicBeaconBlocks) do (blck: BeaconBlock):
|
||||
|
@ -46,7 +46,7 @@ import
|
||||
proc get_ancestor(
|
||||
store: BeaconChainDB, blck: Eth2Digest, slot: Slot): Eth2Digest =
|
||||
## Find the ancestor with a specific slot number
|
||||
let blk = store.get(blck, BeaconBlock).get()
|
||||
let blk = store.getBlock(blck).get()
|
||||
if blk.slot == slot:
|
||||
blck
|
||||
else:
|
||||
@ -110,16 +110,16 @@ proc lmdGhost*(
|
||||
while true: # TODO use a O(log N) implementation instead of O(N^2)
|
||||
let children = blocksChildren[head]
|
||||
if children.len == 0:
|
||||
return store.get(head, BeaconBlock).get()
|
||||
return store.getBlock(head).get()
|
||||
|
||||
# For now we assume that all children are direct descendant of the current head
|
||||
let next_slot = store.get(head, BeaconBlock).get().slot + 1
|
||||
let next_slot = store.getBlock(head).get().slot + 1
|
||||
for child in children:
|
||||
doAssert store.get(child, BeaconBlock).get().slot == next_slot
|
||||
doAssert store.getBlock(child).get().slot == next_slot
|
||||
|
||||
childVotes.clear()
|
||||
for target, votes in rawVoteCount.pairs:
|
||||
if store.get(target, BeaconBlock).get().slot >= next_slot:
|
||||
if store.getBlock(target).get().slot >= next_slot:
|
||||
childVotes.inc(store.get_ancestor(target, next_slot), votes)
|
||||
|
||||
head = childVotes.largest().key
|
||||
|
@ -15,9 +15,8 @@ suite "Beacon chain DB":
|
||||
|
||||
test "empty database":
|
||||
check:
|
||||
db.get(Eth2Digest(), BeaconState).isNone
|
||||
db.get(Eth2Digest(), BeaconBlock).isNone
|
||||
|
||||
db.getState(Eth2Digest()).isNone
|
||||
db.getBlock(Eth2Digest()).isNone
|
||||
|
||||
test "find ancestors":
|
||||
var x: ValidatorSig
|
||||
@ -34,17 +33,17 @@ suite "Beacon chain DB":
|
||||
doAssert db.getAncestors(a0) == [a0]
|
||||
doAssert db.getAncestors(a2) == [a2]
|
||||
|
||||
db.put(a2)
|
||||
db.putBlock(a2)
|
||||
|
||||
doAssert db.getAncestors(a0) == [a0]
|
||||
doAssert db.getAncestors(a2) == [a2]
|
||||
|
||||
db.put(a1)
|
||||
db.putBlock(a1)
|
||||
|
||||
doAssert db.getAncestors(a0) == [a0]
|
||||
doAssert db.getAncestors(a2) == [a2, a1]
|
||||
|
||||
db.put(a0)
|
||||
db.putBlock(a0)
|
||||
|
||||
doAssert db.getAncestors(a0) == [a0]
|
||||
doAssert db.getAncestors(a2) == [a2, a1, a0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user