2018-11-23 23:58:49 +00:00
|
|
|
import
|
2019-01-14 12:19:44 +00:00
|
|
|
os, json, tables, options,
|
2019-02-05 19:21:18 +00:00
|
|
|
chronicles, json_serialization, eth/common/eth_types_json_serialization,
|
2019-01-14 12:19:44 +00:00
|
|
|
spec/[datatypes, digest, crypto],
|
2019-02-05 19:21:18 +00:00
|
|
|
eth/trie/db, ssz
|
2018-11-23 23:58:49 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
BeaconChainDB* = ref object
|
2019-01-14 12:19:44 +00:00
|
|
|
backend: TrieDatabaseRef
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2019-01-14 12:19:44 +00:00
|
|
|
DbKeyKind = enum
|
2019-02-21 04:42:17 +00:00
|
|
|
kHashToState
|
2019-01-14 12:19:44 +00:00
|
|
|
kHashToBlock
|
2019-02-21 04:42:17 +00:00
|
|
|
kHeadBlock
|
2019-01-14 12:19:44 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
DbTypes = BeaconState | BeaconBlock
|
2019-01-14 12:19:44 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
func subkey(kind: DbKeyKind): array[1, byte] =
|
|
|
|
result[0] = byte ord(kind)
|
2019-01-14 12:19:44 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
func subkey[N: static int](kind: DbKeyKind, key: array[N, byte]):
|
|
|
|
array[N + 1, byte] =
|
|
|
|
result[0] = byte ord(kind)
|
|
|
|
result[1 .. ^1] = key
|
2019-01-25 14:17:35 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
func subkey(kind: type BeaconState, key: Eth2Digest): auto =
|
|
|
|
subkey(kHashToState, key.data)
|
2019-01-25 14:17:35 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
func subkey(kind: type BeaconBlock, key: Eth2Digest): auto =
|
|
|
|
subkey(kHashToBlock, key.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 =
|
2018-11-23 23:58:49 +00:00
|
|
|
new result
|
2019-01-14 12:19:44 +00:00
|
|
|
result.backend = backend
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
proc put*(db: BeaconChainDB, key: Eth2Digest, value: BeaconBlock) =
|
|
|
|
db.backend.put(subkey(type value, key), ssz.serialize(value))
|
2019-01-25 14:17:35 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
proc putHead*(db: BeaconChainDB, key: Eth2Digest) =
|
|
|
|
db.backend.put(subkey(kHeadBlock), key.data) # TODO head block?
|
2019-01-25 14:17:35 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
proc put*(db: BeaconChainDB, key: Eth2Digest, value: BeaconState) =
|
|
|
|
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 get(db: BeaconChainDB, key: auto, T: typedesc): Option[T] =
|
|
|
|
let res = db.backend.get(key)
|
2019-01-14 12:19:44 +00:00
|
|
|
if res.len != 0:
|
2019-02-21 04:42:17 +00:00
|
|
|
ssz.deserialize(res, T)
|
2019-01-14 12:19:44 +00:00
|
|
|
else:
|
2019-02-21 04:42:17 +00:00
|
|
|
none(T)
|
2019-01-14 12:19:44 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
# 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 get*(db: BeaconChainDB, key: Eth2Digest, T: type BeaconState): Option[T] =
|
|
|
|
db.get(subkey(T, key), T)
|
|
|
|
|
|
|
|
proc getHead*(db: BeaconChainDB, T: type BeaconBlock): Option[T] =
|
|
|
|
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)
|
|
|
|
else:
|
|
|
|
none(T)
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2019-02-21 04:42:17 +00:00
|
|
|
proc contains*(
|
|
|
|
db: BeaconChainDB, key: Eth2Digest, T: type DbTypes): bool =
|
|
|
|
db.backend.contains(subkey(T, key))
|