92 lines
3.0 KiB
Nim
92 lines
3.0 KiB
Nim
import
|
|
os, json, tables, options,
|
|
chronicles, json_serialization, eth/common/eth_types_json_serialization,
|
|
spec/[datatypes, digest, crypto],
|
|
eth/trie/db, ssz
|
|
|
|
|
|
type
|
|
BeaconChainDB* = ref object
|
|
backend: TrieDatabaseRef
|
|
|
|
DbKeyKind = enum
|
|
kLastFinalizedState
|
|
kHashToBlock
|
|
kSlotToBlockHash
|
|
kSlotToState
|
|
kHashToValidatorRegistryChangeLog
|
|
|
|
proc lastFinalizedStateKey(): array[1, byte] =
|
|
result[0] = byte ord(kLastFinalizedState)
|
|
|
|
proc hashToBlockKey(h: Eth2Digest): array[32 + 1, byte] =
|
|
result[0] = byte ord(kHashToBlock)
|
|
result[1 .. ^1] = h.data
|
|
|
|
proc slotToBlockHashKey(s: uint64): array[sizeof(uint64) + 1, byte] =
|
|
result[0] = byte ord(kSlotToBlockHash)
|
|
copyMem(addr result[1], unsafeAddr(s), sizeof(s))
|
|
|
|
proc slotToStateKey(s: uint64): array[sizeof(uint64) + 1, byte] =
|
|
result[0] = byte ord(kSlotToState)
|
|
copyMem(addr result[1], unsafeAddr(s), sizeof(s))
|
|
|
|
proc hashToValidatorRegistryChangeLogKey(deltaChainTip: Eth2Digest): array[32 + 1, byte] =
|
|
result[0] = byte ord(kHashToValidatorRegistryChangeLog)
|
|
result[1 .. ^1] = deltaChainTip.data
|
|
|
|
proc init*(T: type BeaconChainDB, backend: TrieDatabaseRef): BeaconChainDB =
|
|
new result
|
|
result.backend = backend
|
|
|
|
proc lastFinalizedState*(db: BeaconChainDB): BeaconState =
|
|
let res = db.backend.get(lastFinalizedStateKey())
|
|
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()).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)
|
|
# TODO: Consider mapping slots and last pointer to state hashes to avoid
|
|
# duplicating in the db
|
|
db.backend.put(lastFinalizedStateKey(), serializedState)
|
|
db.backend.put(slotToStateKey(s.slot), serializedState)
|
|
|
|
proc persistBlock*(db: BeaconChainDB, b: BeaconBlock) =
|
|
let blockHash = b.hash_tree_root_final
|
|
db.backend.put(hashToBlockKey(blockHash), ssz.serialize(b))
|
|
db.backend.put(slotToBlockHashKey(b.slot), blockHash.data)
|
|
|
|
# proc getValidatorChangeLog*(deltaChainTip: Eth2Digest)
|
|
|
|
proc getBlock*(db: BeaconChainDB, hash: Eth2Digest, output: var BeaconBlock): bool =
|
|
let res = db.backend.get(hashToBlockKey(hash))
|
|
if res.len != 0:
|
|
output = ssz.deserialize(res, BeaconBlock).get
|
|
true
|
|
else:
|
|
false
|
|
|
|
proc getBlock*(db: BeaconChainDB, hash: Eth2Digest): BeaconBlock =
|
|
if not db.getBlock(hash, result):
|
|
raise newException(Exception, "Block not found")
|
|
|