trie -> kv store

* simplify data storage to key-value, tries are not relevant for NBC
* locked-down version of lmdb dependency
* easier to build / maintain on various platforms
This commit is contained in:
Jacek Sieka 2020-01-15 16:06:50 +01:00 committed by tersec
parent 3dcdce137a
commit 2a67ac3c05
17 changed files with 365 additions and 62 deletions

3
.gitmodules vendored
View File

@ -136,3 +136,6 @@
url = https://github.com/status-im/nim-bearssl.git url = https://github.com/status-im/nim-bearssl.git
ignore = dirty ignore = dirty
branch = master branch = master
[submodule "vendor/lmdb"]
path = vendor/lmdb
url = https://github.com/status-im/lmdb.git

View File

@ -7,7 +7,6 @@ cache:
directories: directories:
- vendor/nimbus-build-system/vendor/Nim/bin - vendor/nimbus-build-system/vendor/Nim/bin
- vendor/go/bin - vendor/go/bin
- rocksdbCache
- jsonTestsCache - jsonTestsCache
git: git:
@ -27,7 +26,6 @@ matrix:
before_install: before_install:
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
- sudo apt-get -q update - sudo apt-get -q update
- sudo apt-get install -y librocksdb-dev
- os: linux - os: linux
arch: arm64 arch: arm64
sudo: required sudo: required
@ -37,14 +35,10 @@ matrix:
before_install: before_install:
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
- sudo apt-get -q update - sudo apt-get -q update
- sudo apt-get install -y libpcre3-dev librocksdb-dev - sudo apt-get install -y libpcre3-dev
- os: osx - os: osx
env: env:
- NPROC=2 - NPROC=2
before_install:
- launchctl setenv LIBRARY_PATH /usr/local/lib # for RocksDB
# build our own rocksdb to test with a fixed version that we think works
- vendor/nimbus-build-system/scripts/build_rocksdb.sh rocksdbCache
install: install:

View File

@ -52,7 +52,6 @@ Nimbus has 4 external dependencies:
* Go 1.12 (for compiling libp2p daemon - being phased out) * Go 1.12 (for compiling libp2p daemon - being phased out)
* Developer tools (C compiler, Make, Bash, Git) * Developer tools (C compiler, Make, Bash, Git)
* [RocksDB](https://github.com/facebook/rocksdb/)
* PCRE * PCRE
Nim is not an external dependency, Nimbus will build its own local copy. Nim is not an external dependency, Nimbus will build its own local copy.
@ -62,13 +61,13 @@ Nim is not an external dependency, Nimbus will build its own local copy.
On common Linux distributions the dependencies can be installed with: On common Linux distributions the dependencies can be installed with:
```sh ```sh
# Debian and Ubuntu # Debian and Ubuntu
sudo apt-get install build-essential git golang-go librocksdb-dev libpcre3-dev sudo apt-get install build-essential git golang-go libpcre3-dev
# Fedora # Fedora
dnf install @development-tools go rocksdb-devel pcre dnf install @development-tools go pcre
# Archlinux, using an AUR manager for pcre-static # Archlinux, using an AUR manager for pcre-static
yourAURmanager -S base-devel go rocksdb pcre-static yourAURmanager -S base-devel go pcre-static
``` ```
### MacOS ### MacOS
@ -76,14 +75,14 @@ yourAURmanager -S base-devel go rocksdb pcre-static
Assuming you use [Homebrew](https://brew.sh/) to manage packages Assuming you use [Homebrew](https://brew.sh/) to manage packages
```sh ```sh
brew install go rocksdb pcre brew install go pcre
``` ```
### Windows ### Windows
* install [Go](https://golang.org/doc/install#windows) * install [Go](https://golang.org/doc/install#windows)
You can install the developer tools by following the instruction in our [Windows dev environment section](#windows-dev-environment). You can install the developer tools by following the instruction in our [Windows dev environment section](#windows-dev-environment).
It also provides a downloading script for prebuilt PCRE and RocksDB. It also provides a downloading script for prebuilt PCRE.
If you choose to install Go from source, both Go and Nimbus requires the same initial steps of installing Mingw. If you choose to install Go from source, both Go and Nimbus requires the same initial steps of installing Mingw.
@ -220,7 +219,7 @@ Variables -> Path -> Edit -> New -> C:\mingw-w64\mingw64\bin (it's "C:\mingw-w64
Install [Git for Windows](https://gitforwindows.org/) and use a "Git Bash" shell to clone and build nim-beacon-chain. Install [Git for Windows](https://gitforwindows.org/) and use a "Git Bash" shell to clone and build nim-beacon-chain.
If you don't want to compile RocksDB and SQLite separately, you can fetch pre-compiled DLLs with: If you don't want to compile PCRE separately, you can fetch pre-compiled DLLs with:
```bash ```bash
mingw32-make # this first invocation will update the Git submodules mingw32-make # this first invocation will update the Git submodules
mingw32-make fetch-dlls # this will place the right DLLs for your architecture in the "build/" directory mingw32-make fetch-dlls # this will place the right DLLs for your architecture in the "build/" directory
@ -286,19 +285,6 @@ sudo apt-get install git libgflags-dev libsnappy-dev libpcre3-dev
mkdir status mkdir status
cd status cd status
# Install rocksdb
git clone https://github.com/facebook/rocksdb.git
cd rocksdb
make shared_lib
sudo make install-shared
cd ..
# Raspberry pi doesn't include /usr/local/lib in library search path
# Add it to your profile
echo '# Local compiles (nimbus - rocksdb)' >> ~/.profile
echo 'export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH' >> ~/.profile
echo '' >> ~/.profile
# Install Go at least 1.12 (Buster only includes up to 1.11) # Install Go at least 1.12 (Buster only includes up to 1.11)
# Raspbian is 32-bit, so the package is go1.XX.X.linux-armv6l.tar.gz (and not arm64) # Raspbian is 32-bit, so the package is go1.XX.X.linux-armv6l.tar.gz (and not arm64)
curl -O https://storage.googleapis.com/golang/go1.13.3.linux-armv6l.tar.gz curl -O https://storage.googleapis.com/golang/go1.13.3.linux-armv6l.tar.gz

View File

@ -1,14 +1,14 @@
import import
json, tables, options, options,
chronicles, serialization, json_serialization, eth/common/eth_types_json_serialization, serialization,
spec/[datatypes, digest, crypto], spec/[datatypes, digest, crypto],
eth/trie/db, ssz kvstore, ssz
type type
BeaconChainDB* = ref object BeaconChainDB* = ref object
## Database storing resolved blocks and states - resolved blocks are such ## Database storing resolved blocks and states - resolved blocks are such
## blocks that form a chain back to the tail block. ## blocks that form a chain back to the tail block.
backend: TrieDatabaseRef backend: KVStoreRef
DbKeyKind = enum DbKeyKind = enum
kHashToState kHashToState
@ -61,7 +61,7 @@ func subkey(root: Eth2Digest, slot: Slot): auto =
ret ret
proc init*(T: type BeaconChainDB, backend: TrieDatabaseRef): BeaconChainDB = proc init*(T: type BeaconChainDB, backend: KVStoreRef): BeaconChainDB =
T(backend: backend) T(backend: backend)
proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: SignedBeaconBlock) = proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: SignedBeaconBlock) =
@ -99,22 +99,18 @@ proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
db.backend.put(subkey(kTailBlock), key.data) db.backend.put(subkey(kTailBlock), key.data)
proc get(db: BeaconChainDB, key: auto, T: typedesc): Option[T] = proc get(db: BeaconChainDB, key: auto, T: typedesc): Option[T] =
let res = db.backend.get(key) var res: Option[T]
if res.len != 0: discard db.backend.get(key, proc (data: openArray[byte]) =
try: try:
some(SSZ.decode(res, T)) res = some(SSZ.decode(data, T))
except SerializationError: except SerializationError:
none(T) discard
else: )
none(T) res
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Option[SignedBeaconBlock] = proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Option[SignedBeaconBlock] =
db.get(subkey(SignedBeaconBlock, key), SignedBeaconBlock) db.get(subkey(SignedBeaconBlock, key), SignedBeaconBlock)
proc getBlock*(db: BeaconChainDB, slot: Slot): Option[SignedBeaconBlock] =
# TODO implement this
discard
proc getState*(db: BeaconChainDB, key: Eth2Digest): Option[BeaconState] = proc getState*(db: BeaconChainDB, key: Eth2Digest): Option[BeaconState] =
db.get(subkey(BeaconState, key), BeaconState) db.get(subkey(BeaconState, key), BeaconState)

View File

@ -3,10 +3,10 @@ import
os, net, tables, random, strutils, times, sequtils, os, net, tables, random, strutils, times, sequtils,
# Nimble packages # Nimble packages
stew/[objects, bitseqs, byteutils], stew/ranges/ptr_arith, stew/[objects, bitseqs, byteutils],
chronos, chronicles, confutils, metrics, chronos, chronicles, confutils, metrics,
json_serialization/std/[options, sets], serialization/errors, json_serialization/std/[options, sets], serialization/errors,
eth/trie/db, eth/trie/backends/rocksdb_backend, eth/async_utils, kvstore, kvstore_lmdb, eth/async_utils,
# Local modules # Local modules
spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network], spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network],
@ -135,7 +135,7 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
networkId = getPersistentNetIdentity(conf) networkId = getPersistentNetIdentity(conf)
nickname = if conf.nodeName == "auto": shortForm(networkId) nickname = if conf.nodeName == "auto": shortForm(networkId)
else: conf.nodeName else: conf.nodeName
db = BeaconChainDB.init(trieDB newChainDb(conf.databaseDir)) db = BeaconChainDB.init(kvStore LmdbStoreRef.init(conf.databaseDir))
var mainchainMonitor: MainchainMonitor var mainchainMonitor: MainchainMonitor

94
beacon_chain/kvstore.nim Normal file
View File

@ -0,0 +1,94 @@
# Simple Key-Value store database interface
import
tables, hashes, sets
type
MemoryStoreRef* = ref object of RootObj
records: Table[seq[byte], seq[byte]]
DataProc* = proc(val: openArray[byte])
PutProc = proc (db: RootRef, key, val: openArray[byte]) {.gcsafe.}
GetProc = proc (db: RootRef, key: openArray[byte], onData: DataProc): bool {.gcsafe.}
DelProc = proc (db: RootRef, key: openArray[byte]) {.gcsafe.}
ContainsProc = proc (db: RootRef, key: openArray[byte]): bool {.gcsafe.}
KVStoreRef* = ref object
## Key-Value store virtual interface
obj: RootRef
putProc: PutProc
getProc: GetProc
delProc: DelProc
containsProc: ContainsProc
template put*(db: KVStoreRef, key, val: openArray[byte]) =
## Store ``value`` at ``key`` - overwrites existing value if already present
db.putProc(db.obj, key, val)
template get*(db: KVStoreRef, key: openArray[byte], onData: untyped): bool =
## Retrive value at ``key`` and call ``onData`` with the value. The data is
## valid for the duration of the callback.
## ``onData``: ``proc(data: openArray[byte])``
## returns true if found and false otherwise.
db.getProc(db.obj, key, onData)
template del*(db: KVStoreRef, key: openArray[byte]) =
## Remove value at ``key`` from store - do nothing if the value is not present
db.delProc(db.obj, key)
template contains*(db: KVStoreRef, key: openArray[byte]): bool =
## Return true iff ``key`` has a value in store
db.containsProc(db.obj, key)
proc get*(db: MemoryStoreRef, key: openArray[byte], onData: DataProc): bool =
let key = @key
db.records.withValue(key, v):
onData(v[])
return true
proc del*(db: MemoryStoreRef, key: openArray[byte]) =
# TODO: This is quite inefficient and it won't be necessary once
# https://github.com/nim-lang/Nim/issues/7457 is developed.
let key = @key
db.records.del(key)
proc contains*(db: MemoryStoreRef, key: openArray[byte]): bool =
db.records.contains(@key)
proc put*(db: MemoryStoreRef, key, val: openArray[byte]) =
# TODO: This is quite inefficient and it won't be necessary once
# https://github.com/nim-lang/Nim/issues/7457 is developed.
let key = @key
db.records[key] = @val
proc init*(T: type MemoryStoreRef): T =
T(
records: initTable[seq[byte], seq[byte]]()
)
proc putImpl[T](db: RootRef, key, val: openArray[byte]) =
mixin put
put(T(db), key, val)
proc getImpl[T](db: RootRef, key: openArray[byte], onData: DataProc): bool =
mixin get
get(T(db), key, onData)
proc delImpl[T](db: RootRef, key: openArray[byte]) =
mixin del
del(T(db), key)
proc containsImpl[T](db: RootRef, key: openArray[byte]): bool =
mixin contains
contains(T(db), key)
func kvStore*[T: RootRef](x: T): KVStoreRef =
mixin del, get, put, contains
KVStoreRef(
obj: x,
putProc: putImpl[T],
getProc: getImpl[T],
delProc: delImpl[T],
containsProc: containsImpl[T]
)

View File

@ -0,0 +1,159 @@
## Implementation of KVStore based on LMDB
## TODO: crashes on win32, investigate
import os
import ./kvstore
{.compile: "../vendor/lmdb/libraries/liblmdb/mdb.c".}
{.compile: "../vendor/lmdb/libraries/liblmdb/midl.c".}
const
MDB_NOSUBDIR = 0x4000
MDB_RDONLY = 0x20000
MDB_NOTFOUND = -30798
when defined(cpu64):
const LMDB_MAP_SIZE = 1024'u64 * 1024'u64 * 1024'u64 * 10'u64 # 10TB enough?
else:
const LMDB_MAP_SIZE = 1024'u64 * 1024'u64 * 1024'u64 # 32bit limitation
type
MDB_Env = distinct pointer
MDB_Txn = distinct pointer
MDB_Dbi = distinct cuint
MDB_val = object
mv_size: csize
mv_data: pointer
LmdbError* = object of CatchableError
# Used subset of the full LMDB API
proc mdb_env_create(env: var MDB_Env): cint {.importc.}
proc mdb_env_open(env: MDB_Env, path: cstring, flags: cuint, mode: cint): cint {.importc.}
proc mdb_txn_begin(env: MDB_Env, parent: MDB_Txn, flags: cuint, txn: var MDB_Txn): cint {.importc.}
proc mdb_txn_commit(txn: MDB_Txn): cint {.importc.}
proc mdb_txn_abort(txn: MDB_Txn) {.importc.}
proc mdb_dbi_open(txn: MDB_Txn, name: cstring, flags: cuint, dbi: var MDB_Dbi): cint {.importc.}
proc mdb_env_close(env: MDB_Env) {.importc.}
proc mdb_strerror(err: cint): cstring {.importc.}
proc mdb_get(txn: MDB_Txn, dbi: MDB_Dbi, key: var MDB_val, data: var MDB_val): cint {.importc.}
proc mdb_del(txn: MDB_Txn, dbi: MDB_Dbi, key: var MDB_val, data: ptr MDB_val): cint {.importc.}
proc mdb_put(txn: MDB_Txn, dbi: MDB_Dbi, key: var MDB_val, data: var MDB_val, flags: cuint): cint {.importc.}
proc mdb_env_set_mapsize(env: MDB_Env, size: uint64): cint {.importc.}
func raiseLmdbError(err: cint) {.noreturn.} =
let tmp = mdb_strerror(err)
raise (ref LmdbError)(msg: $tmp)
type
LmdbStoreRef* = ref object of RootObj
env: MDB_Env
template init(T: type MDB_Val, val: openArray[byte]): T =
T(
mv_size: val.len,
mv_data: unsafeAddr val[0]
)
proc begin(db: LmdbStoreRef, flags: cuint): tuple[txn: MDB_Txn, dbi: MDB_Dbi] =
var
txn: MDB_Txn
dbi: MDB_Dbi
if (let x = mdb_txn_begin(db.env, nil, flags, txn); x != 0):
raiseLmdbError(x)
if (let x = mdb_dbi_open(txn, nil, 0, dbi); x != 0):
mdb_txn_abort(txn)
raiseLmdbError(x)
(txn, dbi)
proc get*(db: LmdbStoreRef, key: openarray[byte], onData: DataProc): bool =
if key.len == 0:
return
var
(txn, dbi) = db.begin(MDB_RDONLY)
dbKey = MDB_Val.init(key)
dbVal: MDB_val
# abort ok for read-only and easier for exception safety
defer: mdb_txn_abort(txn)
if (let x = mdb_get(txn, dbi, dbKey, dbVal); x != 0):
if x == MDB_NOTFOUND:
return false
raiseLmdbError(x)
if not onData.isNil:
onData(toOpenArrayByte(cast[cstring](dbVal.mv_data), 0, dbVal.mv_size.int - 1))
true
proc put*(db: LmdbStoreRef, key, value: openarray[byte]) =
if key.len == 0: return
var
(txn, dbi) = db.begin(0)
dbKey = MDB_Val.init(key)
dbVal = MDB_Val.init(value)
if (let x = mdb_put(txn, dbi, dbKey, dbVal, 0); x != 0):
mdb_txn_abort(txn)
raiseLmdbError(x)
if (let x = mdb_txn_commit(txn); x != 0):
raiseLmdbError(x)
proc contains*(db: LmdbStoreRef, key: openarray[byte]): bool =
db.get(key, nil)
proc del*(db: LmdbStoreRef, key: openarray[byte]) =
if key.len == 0: return
var
(txn, dbi) = db.begin(0)
dbKey = MDB_Val.init(key)
if (let x = mdb_del(txn, dbi, dbKey, nil); x != 0):
mdb_txn_abort(txn)
if x != MDB_NOTFOUND:
raiseLmdbError(x)
return
if (let x = mdb_txn_commit(txn); x != 0):
raiseLmdbError(x)
proc close*(db: LmdbStoreRef) =
mdb_env_close(db.env)
proc init*(T: type LmdbStoreRef, basePath: string, readOnly = false): T =
var
env: MDB_Env
if (let x = mdb_env_create(env); x != 0):
raiseLmdbError(x)
let dataDir = basePath / "nimbus.lmdb"
if (let x = mdb_env_set_mapsize(env, LMDB_MAP_SIZE); x != 0):
mdb_env_close(env)
raiseLmdbError(x)
var openFlags = MDB_NOSUBDIR
if readOnly: openFlags = openFlags or MDB_RDONLY
# file mode ignored on windows
if (let x = mdb_env_open(env, dataDir, openFlags.cuint, 0o664.cint); x != 0):
mdb_env_close(env)
raiseLmdbError(x)
T(env: env)

View File

@ -19,7 +19,7 @@
import import
macros, hashes, json, strutils, tables, macros, hashes, json, strutils, tables,
stew/[byteutils, bitseqs], chronicles, eth/common, stew/[byteutils, bitseqs], chronicles,
../version, ../ssz/types, ./crypto, ./digest ../version, ../ssz/types, ./crypto, ./digest
# TODO Data types: # TODO Data types:

View File

@ -21,11 +21,11 @@
import import
chronicles, chronicles,
nimcrypto/[sha2, hash, utils], eth/common/eth_types_json_serialization, nimcrypto/[sha2, hash, utils],
hashes hashes
export export
eth_types_json_serialization, hash.`$` hash.`$`
type type
Eth2Digest* = MDigest[32 * 8] ## `hash32` from spec Eth2Digest* = MDigest[32 * 8] ## `hash32` from spec

View File

@ -12,7 +12,7 @@ import
endians, stew/shims/macros, options, algorithm, options, endians, stew/shims/macros, options, algorithm, options,
stew/[bitops2, bitseqs, objects, varints, ptrops, ranges/ptr_arith], stint, stew/[bitops2, bitseqs, objects, varints, ptrops, ranges/ptr_arith], stint,
faststreams/input_stream, serialization, serialization/testing/tracing, faststreams/input_stream, serialization, serialization/testing/tracing,
nimcrypto/sha2, blscurve, eth/common, nimcrypto/sha2, blscurve,
./spec/[crypto, datatypes, digest], ./spec/[crypto, datatypes, digest],
./ssz/[types, bytes_reader] ./ssz/[types, bytes_reader]

View File

@ -3,7 +3,7 @@ FROM debian:bullseye-slim AS build
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
RUN apt-get -qq update \ RUN apt-get -qq update \
&& apt-get -qq -y install build-essential make wget librocksdb-dev libpcre3-dev golang-go git &>/dev/null \ && apt-get -qq -y install build-essential make wget libpcre3-dev golang-go git &>/dev/null \
&& apt-get -qq clean && apt-get -qq clean
# let Docker cache this between Git revision and testnet version changes # let Docker cache this between Git revision and testnet version changes
@ -36,7 +36,7 @@ FROM debian:bullseye-slim
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
RUN apt-get -qq update \ RUN apt-get -qq update \
&& apt-get -qq -y install librocksdb-dev libpcre3 psmisc &>/dev/null \ && apt-get -qq -y install libpcre3 psmisc &>/dev/null \
&& apt-get -qq clean \ && apt-get -qq clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

View File

@ -18,6 +18,8 @@ import # Unit test
./test_block_pool, ./test_block_pool,
./test_helpers, ./test_helpers,
./test_interop, ./test_interop,
./test_kvstore,
./test_kvstore_lmdb,
./test_ssz, ./test_ssz,
./test_state_transition, ./test_state_transition,
./test_sync_protocol, ./test_sync_protocol,

View File

@ -7,17 +7,16 @@
{.used.} {.used.}
import options, unittest, sequtils, eth/trie/[db], import options, unittest, sequtils,
../beacon_chain/[beacon_chain_db, extras, interop, ssz], ../beacon_chain/[beacon_chain_db, extras, interop, ssz, kvstore],
../beacon_chain/spec/[beaconstate, datatypes, digest, crypto], ../beacon_chain/spec/[beaconstate, datatypes, digest, crypto],
# test utilies # test utilies
./testutil, ./testblockutil ./testutil, ./testblockutil
suite "Beacon chain DB" & preset(): suite "Beacon chain DB" & preset():
timedTest "empty database" & preset(): timedTest "empty database" & preset():
var var
db = init(BeaconChainDB, newMemoryDB()) db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
check: check:
when const_preset=="minimal": when const_preset=="minimal":
@ -28,7 +27,7 @@ suite "Beacon chain DB" & preset():
timedTest "sanity check blocks" & preset(): timedTest "sanity check blocks" & preset():
var var
db = init(BeaconChainDB, newMemoryDB()) db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
let let
blck = SignedBeaconBlock() blck = SignedBeaconBlock()
@ -46,7 +45,7 @@ suite "Beacon chain DB" & preset():
timedTest "sanity check states" & preset(): timedTest "sanity check states" & preset():
var var
db = init(BeaconChainDB, newMemoryDB()) db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
let let
state = BeaconState() state = BeaconState()
@ -60,7 +59,7 @@ suite "Beacon chain DB" & preset():
timedTest "find ancestors" & preset(): timedTest "find ancestors" & preset():
var var
db = init(BeaconChainDB, newMemoryDB()) db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
x: ValidatorSig x: ValidatorSig
y = init(ValidatorSig, x.getBytes()) y = init(ValidatorSig, x.getBytes())
@ -101,7 +100,7 @@ suite "Beacon chain DB" & preset():
# serialization where an all-zero default-initialized bls signature could # serialization where an all-zero default-initialized bls signature could
# not be deserialized because the deserialization was too strict. # not be deserialized because the deserialization was too strict.
var var
db = init(BeaconChainDB, newMemoryDB()) db = init(BeaconChainDB, kvStore MemoryStoreRef.init())
let let
state = initialize_beacon_state_from_eth1( state = initialize_beacon_state_from_eth1(

45
tests/test_kvstore.nim Normal file
View File

@ -0,0 +1,45 @@
{.used.}
import
unittest,
../beacon_chain/kvstore
proc testKVStore*(db: KVStoreRef) =
let
key = [0'u8, 1, 2, 3]
value = [3'u8, 2, 1, 0]
value2 = [5'u8, 2, 1, 0]
check:
db != nil
not db.get(key, proc(data: openArray[byte]) = discard)
not db.contains(key)
db.del(key) # does nothing
db.put(key, value)
check:
db.contains(key)
db.get(key, proc(data: openArray[byte]) =
check data == value
)
db.put(key, value2) # overwrite old value
check:
db.contains(key)
db.get(key, proc(data: openArray[byte]) =
check data == value2
)
db.del(key)
check:
not db.get(key, proc(data: openArray[byte]) = discard)
not db.contains(key)
db.del(key) # does nothing
suite "MemoryStoreRef":
test "KVStore interface":
testKVStore(kvStore MemoryStoreRef.init())

View File

@ -0,0 +1,24 @@
{.used.}
import
os,
unittest,
../beacon_chain/[kvstore, kvstore_lmdb],
./test_kvstore
suite "LMDB":
setup:
let
path = os.getTempDir() / "test_kvstore_lmdb"
os.removeDir(path)
os.createDir(path)
teardown:
os.removeDir(path)
test "KVStore interface":
let db = LmdbStoreRef.init(path)
defer: db.close()
testKVStore(kvStore db)

View File

@ -7,8 +7,8 @@
import import
algorithm, strformat, stats, times, std/monotimes, stew/endians2, algorithm, strformat, stats, times, std/monotimes, stew/endians2,
chronicles, eth/trie/[db], chronicles,
../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, beacon_node_types], ../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, kvstore, beacon_node_types],
../beacon_chain/spec/[digest, beaconstate, datatypes], ../beacon_chain/spec/[digest, beaconstate, datatypes],
testblockutil testblockutil
@ -73,7 +73,7 @@ template timedTest*(name, body) =
testTimes.add (f, name) testTimes.add (f, name)
proc makeTestDB*(tailState: BeaconState, tailBlock: SignedBeaconBlock): BeaconChainDB = proc makeTestDB*(tailState: BeaconState, tailBlock: SignedBeaconBlock): BeaconChainDB =
result = init(BeaconChainDB, newMemoryDB()) result = init(BeaconChainDB, kvStore MemoryStoreRef.init())
BlockPool.preInit(result, tailState, tailBlock) BlockPool.preInit(result, tailState, tailBlock)
proc makeTestDB*(validators: int): BeaconChainDB = proc makeTestDB*(validators: int): BeaconChainDB =

1
vendor/lmdb vendored Submodule

@ -0,0 +1 @@
Subproject commit c8ecc17b38e164e6a728d66a9b1d05bc18dd3ace