diff --git a/beacon_chain/beacon_node_common.nim b/beacon_chain/beacon_node_common.nim index 62340a1dc..9b44943a9 100644 --- a/beacon_chain/beacon_node_common.nim +++ b/beacon_chain/beacon_node_common.nim @@ -107,7 +107,17 @@ proc storeBlock*( dump(node.config.dumpDir / "incoming", signedBlock, blockRoot) beacon_blocks_received.inc() - discard ? node.blockPool.add(blockRoot, signedBlock) + let blck = node.blockPool.add(blockRoot, signedBlock) + if blck.isErr: + if blck.error == Invalid and node.config.dumpEnabled: + let parent = node.blockPool.getRef(signedBlock.message.parent_root) + if parent != nil: + node.blockPool.withState( + node.blockPool.tmpState, parent.atSlot(signedBlock.message.slot - 1)): + dump(node.config.dumpDir / "invalid", hashedState, parent) + dump(node.config.dumpDir / "invalid", signedBlock, blockRoot) + + return err(blck.error) # The block we received contains attestations, and we might not yet know about # all of them. Let's add them to the attestation pool - in case they block diff --git a/beacon_chain/sszdump.nim b/beacon_chain/sszdump.nim index 18e872283..dbd1a7151 100644 --- a/beacon_chain/sszdump.nim +++ b/beacon_chain/sszdump.nim @@ -18,3 +18,7 @@ proc dump*(dir: string, v: HashedBeaconState, blck: BlockRef) = dir / &"state-{v.data.slot}-{shortLog(blck.root)}-{shortLog(v.root)}.ssz", v.data) +proc dump*(dir: string, v: HashedBeaconState) = + SSZ.saveFile( + dir / &"state-{v.data.slot}-{shortLog(v.root)}.ssz", + v.data) diff --git a/ncli/ncli_db.nim b/ncli/ncli_db.nim index 4a8a4e6f2..37817ef8d 100644 --- a/ncli/ncli_db.nim +++ b/ncli/ncli_db.nim @@ -1,8 +1,9 @@ import confutils, stats, chronicles, strformat, tables, - ../beacon_chain/block_pool, - ../beacon_chain/spec/[crypto, datatypes, helpers], - ../beacon_chain/[beacon_chain_db, extras, state_transition], + stew/byteutils, + ../beacon_chain/[beacon_chain_db, block_pool, extras, state_transition], + ../beacon_chain/spec/[crypto, datatypes, digest, helpers], + ../beacon_chain/sszdump, ../research/simutils, eth/db/[kvstore, kvstore_sqlite3] @@ -16,6 +17,7 @@ type Timers = enum type DbCmd* = enum bench + dumpState DbConf = object databaseDir* {. @@ -25,7 +27,7 @@ type case cmd* {. command - desc: "Run benchmark by applying all blocks from database" + desc: "" .}: DbCmd of bench: @@ -33,6 +35,11 @@ type defaultValue: true desc: "Enable BLS validation" }: bool + of dumpState: + stateRoot* {. + argument + desc: "State roots to save".}: seq[string] + proc cmdBench(conf: DbConf) = var timers: array[Timers, RunningStat] @@ -81,10 +88,28 @@ proc cmdBench(conf: DbConf) = printTimers(conf.validate, timers) +proc cmdDumpState(conf: DbConf) = + let + db = BeaconChainDB.init( + kvStore SqStoreRef.init(conf.databaseDir.string, "nbc").tryGet()) + + for stateRoot in conf.stateRoot: + try: + let root = Eth2Digest(data: hexToByteArray[32](stateRoot)) + var state = (ref HashedBeaconState)(root: root) + if not db.getState(root, state.data, noRollback): + echo "Couldn't load ", root + else: + dump("./", state[]) + except CatchableError as e: + echo "Couldn't load ", stateRoot, ": ", e.msg + when isMainModule: let - config = DbConf.load() + conf = DbConf.load() - case config.cmd + case conf.cmd of bench: - cmdBench(config) + cmdBench(conf) + of dumpState: + cmdDumpState(conf)