nimbus-eth2/beacon_chain/beacon_chain_db.nim

98 lines
3.1 KiB
Nim
Raw Normal View History

import
2019-01-14 12:19:44 +00:00
os, json, tables, options,
chronicles, json_serialization, eth_common/eth_types_json_serialization,
2019-01-14 12:19:44 +00:00
spec/[datatypes, digest, crypto],
eth_trie/db, ssz
2019-01-25 14:17:35 +00:00
const STATE_STORAGE_PERIOD = 1000 # Save states once per this number of slots. TODO: Find a good number.
type
BeaconChainDB* = ref object
2019-01-14 12:19:44 +00:00
backend: TrieDatabaseRef
2019-01-14 12:19:44 +00:00
DbKeyKind = enum
kLastFinalizedState
kHashToBlock
2019-01-25 14:17:35 +00:00
kSlotToBlockHash
kSlotToState
kHashToValidatorRegistryChangeLog
2019-01-14 12:19:44 +00:00
2019-01-29 10:13:26 +00:00
proc lastFinalizedStateKey(): array[1, byte] =
result[0] = byte ord(kLastFinalizedState)
2019-01-14 12:19:44 +00:00
2019-01-29 10:13:26 +00:00
proc hashToBlockKey(h: Eth2Digest): array[32 + 1, byte] =
result[0] = byte ord(kHashToBlock)
result[1 .. ^1] = h.data
2019-01-14 12:19:44 +00:00
2019-01-29 10:13:26 +00:00
proc slotToBlockHashKey(s: uint64): array[sizeof(uint64) + 1, byte] =
result[0] = byte ord(kSlotToBlockHash)
copyMem(addr result[1], unsafeAddr(s), sizeof(s))
2019-01-25 14:17:35 +00:00
2019-01-29 10:13:26 +00:00
proc slotToStateKey(s: uint64): array[sizeof(uint64) + 1, byte] =
result[0] = byte ord(kSlotToState)
copyMem(addr result[1], unsafeAddr(s), sizeof(s))
2019-01-25 14:17:35 +00:00
2019-01-29 10:13:26 +00:00
proc hashToValidatorRegistryChangeLogKey(deltaChainTip: Eth2Digest): array[32 + 1, byte] =
result[0] = byte ord(kHashToValidatorRegistryChangeLog)
result[1 .. ^1] = deltaChainTip.data
2019-01-25 14:17:35 +00:00
2019-01-14 12:19:44 +00:00
proc init*(T: type BeaconChainDB, backend: TrieDatabaseRef): BeaconChainDB =
new result
2019-01-14 12:19:44 +00:00
result.backend = backend
2019-01-25 14:17:35 +00:00
proc lastFinalizedState*(db: BeaconChainDB): BeaconState =
2019-01-29 10:13:26 +00:00
let res = db.backend.get(lastFinalizedStateKey())
2019-01-25 14:17:35 +00:00
if res.len == 0:
raise newException(Exception, "Internal error: Database has no finalized state")
ssz.deserialize(res, BeaconState).get
proc isInitialized*(db: BeaconChainDB): bool =
2019-01-29 10:13:26 +00:00
db.backend.get(lastFinalizedStateKey()).len != 0
2019-01-25 14:17:35 +00:00
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)
2019-01-29 10:13:26 +00:00
db.backend.put(lastFinalizedStateKey(), serializedState)
2019-01-25 14:17:35 +00:00
if s.slot mod STATE_STORAGE_PERIOD == 0:
# Save slot to state mapping
2019-01-29 10:13:26 +00:00
db.backend.put(slotToStateKey(s.slot), serializedState)
proc persistBlock*(db: BeaconChainDB, s: BeaconState, b: BeaconBlock) =
2019-01-25 14:17:35 +00:00
var prevState = db.lastFinalizedState()
db.persistState(s)
let blockHash = b.hash_tree_root_final
2019-01-29 10:13:26 +00:00
db.backend.put(hashToBlockKey(blockHash), ssz.serialize(b))
db.backend.put(slotToBlockHashKey(b.slot), blockHash.data)
2019-01-25 14:17:35 +00:00
# proc getValidatorChangeLog*(deltaChainTip: Eth2Digest)
2019-01-14 12:19:44 +00:00
proc getBlock*(db: BeaconChainDB, hash: Eth2Digest, output: var BeaconBlock): bool =
2019-01-29 10:13:26 +00:00
let res = db.backend.get(hashToBlockKey(hash))
2019-01-14 12:19:44 +00:00
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")