More persistance
This commit is contained in:
parent
dda24619e8
commit
917c48d9a5
|
@ -4,12 +4,12 @@ import
|
|||
spec/[datatypes, digest, crypto],
|
||||
eth_trie/db, ssz
|
||||
|
||||
const STATE_STORAGE_PERIOD = 1000 # Save states once per this number of slots. TODO: Find a good number.
|
||||
|
||||
type
|
||||
BeaconChainDB* = ref object
|
||||
backend: TrieDatabaseRef
|
||||
|
||||
BeaconStateRef* = ref BeaconState
|
||||
|
||||
DbKey = object
|
||||
data: array[33, byte]
|
||||
dataEndPos: uint8
|
||||
|
@ -17,6 +17,9 @@ type
|
|||
DbKeyKind = enum
|
||||
kLastFinalizedState
|
||||
kHashToBlock
|
||||
kSlotToBlockHash
|
||||
kSlotToState
|
||||
kHashToValidatorRegistryChangeLog
|
||||
|
||||
|
||||
template toOpenArray*(k: DbKey): openarray[byte] =
|
||||
|
@ -31,23 +34,67 @@ proc hashToBlockKey(h: Eth2Digest): DbKey =
|
|||
result.data[1 .. ^1] = h.data
|
||||
result.dataEndPos = 32
|
||||
|
||||
proc slotToBlockHashKey(s: uint64): DbKey =
|
||||
result.data[0] = byte ord(kSlotToBlockHash)
|
||||
copyMem(addr result.data[1], unsafeAddr(s), sizeof(s))
|
||||
result.dataEndPos = uint8 sizeof(s)
|
||||
|
||||
proc slotToStateKey(s: uint64): DbKey =
|
||||
result.data[0] = byte ord(kSlotToState)
|
||||
copyMem(addr result.data[1], unsafeAddr(s), sizeof(s))
|
||||
result.dataEndPos = uint8 sizeof(s)
|
||||
|
||||
proc hashToValidatorRegistryChangeLogKey(deltaChainTip: Eth2Digest): DbKey =
|
||||
result.data[0] = byte ord(kHashToValidatorRegistryChangeLog)
|
||||
result.data[1 .. ^1] = deltaChainTip.data
|
||||
result.dataEndPos = 32
|
||||
|
||||
proc init*(T: type BeaconChainDB, backend: TrieDatabaseRef): BeaconChainDB =
|
||||
new result
|
||||
result.backend = backend
|
||||
|
||||
proc lastFinalizedState*(db: BeaconChainDB): BeaconStateRef =
|
||||
try:
|
||||
let res = db.backend.get(lastFinalizedStateKey().toOpenArray)
|
||||
if res.len != 0:
|
||||
result.new
|
||||
result[] = ssz.deserialize(res, BeaconState).get
|
||||
except:
|
||||
error "Failed to load the latest finalized state",
|
||||
err = getCurrentExceptionMsg()
|
||||
return nil
|
||||
proc lastFinalizedState*(db: BeaconChainDB): BeaconState =
|
||||
let res = db.backend.get(lastFinalizedStateKey().toOpenArray)
|
||||
if res.len == 0:
|
||||
raise newException(Exception, "Internal error: Database has no finalized state")
|
||||
ssz.deserialize(res, BeaconState).get
|
||||
|
||||
proc isInitialized*(db: BeaconChainDB): bool =
|
||||
db.backend.get(lastFinalizedStateKey().toOpenArray).len != 0
|
||||
|
||||
proc persistState*(db: BeaconChainDB, s: BeaconState) =
|
||||
if s.slot != GENESIS_SLOT:
|
||||
# TODO: Verify incoming state slot is higher than lastFinalizedState one
|
||||
discard
|
||||
else:
|
||||
# Make sure we have no states
|
||||
assert(not db.isInitialized)
|
||||
|
||||
var prevState: BeaconState
|
||||
if s.slot != GENESIS_SLOT:
|
||||
prevState = db.lastFinalizedState()
|
||||
if prevState.validator_registry_delta_chain_tip != s.validator_registry_delta_chain_tip:
|
||||
# Validator registry has changed in the incoming state.
|
||||
# TODO: Save the changelog.
|
||||
discard
|
||||
|
||||
let serializedState = ssz.serialize(s)
|
||||
db.backend.put(lastFinalizedStateKey().toOpenArray, serializedState)
|
||||
|
||||
if s.slot mod STATE_STORAGE_PERIOD == 0:
|
||||
# Save slot to state mapping
|
||||
db.backend.put(slotToStateKey(s.slot).toOpenArray, serializedState)
|
||||
|
||||
proc persistBlock*(db: BeaconChainDB, s: BeaconState, b: BeaconBlock) =
|
||||
db.backend.put(lastFinalizedStateKey().toOpenArray, ssz.serialize(s))
|
||||
var prevState = db.lastFinalizedState()
|
||||
|
||||
db.persistState(s)
|
||||
|
||||
let blockHash = b.hash_tree_root_final
|
||||
db.backend.put(hashToBlockKey(blockHash).toOpenArray, ssz.serialize(b))
|
||||
db.backend.put(slotToBlockHashKey(b.slot).toOpenArray, blockHash.data)
|
||||
|
||||
# proc getValidatorChangeLog*(deltaChainTip: Eth2Digest)
|
||||
|
||||
proc getBlock*(db: BeaconChainDB, hash: Eth2Digest, output: var BeaconBlock): bool =
|
||||
let res = db.backend.get(hashToBlockKey(hash).toOpenArray)
|
||||
|
|
|
@ -49,6 +49,12 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): T =
|
|||
|
||||
let trieDB = trieDB newChainDb(string conf.dataDir)
|
||||
result.db = BeaconChainDB.init(trieDB)
|
||||
|
||||
if not result.db.isInitialized:
|
||||
# Use stateSnapshot as genesis
|
||||
info "Initializing DB"
|
||||
result.db.persistState(result.config.stateSnapshot.get)
|
||||
|
||||
result.keys = ensureNetworkKeys(string conf.dataDir)
|
||||
|
||||
var address: Address
|
||||
|
@ -81,14 +87,10 @@ proc connectToNetwork(node: BeaconNode) {.async.} =
|
|||
|
||||
proc sync*(node: BeaconNode): Future[bool] {.async.} =
|
||||
let persistedState = node.db.lastFinalizedState()
|
||||
if persistedState.isNil or
|
||||
persistedState[].slotDistanceFromNow() > WEAK_SUBJECTVITY_PERIOD.int64:
|
||||
if node.config.stateSnapshot.isSome:
|
||||
node.beaconState = node.config.stateSnapshot.get
|
||||
else:
|
||||
node.beaconState = await obtainTrustedStateSnapshot(node.db)
|
||||
if persistedState.slotDistanceFromNow() > WEAK_SUBJECTVITY_PERIOD.int64:
|
||||
node.beaconState = await obtainTrustedStateSnapshot(node.db)
|
||||
else:
|
||||
node.beaconState = persistedState[]
|
||||
node.beaconState = persistedState
|
||||
var targetSlot = toSlot timeSinceGenesis(node.beaconState)
|
||||
|
||||
let t = now()
|
||||
|
@ -354,6 +356,7 @@ proc processBlocks*(node: BeaconNode) =
|
|||
node.headBlock = newBlock
|
||||
node.headBlockRoot = newBlockRoot
|
||||
node.beaconState = state
|
||||
node.db.persistBlock(node.beaconState, newBlock)
|
||||
|
||||
# TODO:
|
||||
#
|
||||
|
|
|
@ -13,7 +13,7 @@ proc initRandao*(bytes: openarray[byte]): Randao =
|
|||
raise newException(Exception, "Wrong randao size")
|
||||
var s: Eth2Digest
|
||||
s.data[0 .. ^1] = bytes
|
||||
initRandao(bytes)
|
||||
initRandao(s)
|
||||
|
||||
proc initialCommitment*(r: Randao): Eth2Digest =
|
||||
repeatHash(r.seed, MaxRandaoLevels)
|
||||
|
|
|
@ -16,7 +16,11 @@ type
|
|||
p2pProtocol BeaconSync(version = 1,
|
||||
shortName = "bcs"):
|
||||
requestResponse:
|
||||
proc getValidatorChangeLog(peer: Peer, changeLogHead: Eth2Digest)
|
||||
proc getValidatorChangeLog(peer: Peer, changeLogHead: Eth2Digest) =
|
||||
var bb: BeaconBlock
|
||||
var bs: BeaconState
|
||||
# TODO: get the changelog from the DB.
|
||||
await peer.validatorChangeLog(reqId, bb, bs, [], [], @[])
|
||||
|
||||
proc validatorChangeLog(peer: Peer,
|
||||
signedBlock: BeaconBlock,
|
||||
|
@ -25,11 +29,6 @@ p2pProtocol BeaconSync(version = 1,
|
|||
removed: openarray[uint32],
|
||||
order: seq[byte])
|
||||
|
||||
template `++`(x: var int): int =
|
||||
let y = x
|
||||
inc x
|
||||
y
|
||||
|
||||
type
|
||||
# A bit shorter names for convenience
|
||||
ChangeLog = BeaconSync.validatorChangeLog
|
||||
|
|
|
@ -27,7 +27,7 @@ proc obtainTrustedStateSnapshot*(db: BeaconChainDB): Future[BeaconState] {.async
|
|||
#
|
||||
# 5. Check that the state snapshot hash is correct and save it in the DB.
|
||||
|
||||
discard
|
||||
assert(false, "Not implemented")
|
||||
|
||||
proc createStateSnapshot*(startup: ChainStartupData, outFile: string) =
|
||||
let initialState = get_initial_beacon_state(startup.validatorDeposits,
|
||||
|
|
Loading…
Reference in New Issue