clean up dump feature

* don't write blocks that get added to database
* don't write states
* write to folders
* add state dumping feature to `ncli_db` to get any known state from the
database
This commit is contained in:
Jacek Sieka 2020-06-16 10:49:32 +02:00 committed by tersec
parent a25bc025d1
commit 49e9167b28
6 changed files with 95 additions and 39 deletions

View File

@ -287,6 +287,22 @@ proc onAttestation(node: BeaconNode, attestation: Attestation) =
node.attestationPool.add(attestation) node.attestationPool.add(attestation)
proc dumpBlock[T](
node: BeaconNode, signedBlock: SignedBeaconBlock,
res: Result[T, BlockError]) =
if node.config.dumpEnabled and res.isErr:
case res.error
of Invalid:
dump(
node.config.dumpDirInvalid, signedBlock,
hash_tree_root(signedBlock.message))
of MissingParent:
dump(
node.config.dumpDirIncoming, signedBlock,
hash_tree_root(signedBlock.message))
else:
discard
proc storeBlock( proc storeBlock(
node: BeaconNode, signedBlock: SignedBeaconBlock): Result[void, BlockError] = node: BeaconNode, signedBlock: SignedBeaconBlock): Result[void, BlockError] =
let blockRoot = hash_tree_root(signedBlock.message) let blockRoot = hash_tree_root(signedBlock.message)
@ -296,28 +312,16 @@ proc storeBlock(
cat = "block_listener", cat = "block_listener",
pcs = "receive_block" pcs = "receive_block"
if node.config.dumpEnabled:
dump(node.config.dumpDir / "incoming", signedBlock, blockRoot)
beacon_blocks_received.inc() beacon_blocks_received.inc()
let blck = node.blockPool.add(blockRoot, signedBlock) let blck = node.blockPool.add(blockRoot, signedBlock)
node.dumpBlock(signedBlock, blck)
if blck.isErr: if blck.isErr:
if blck.error == Invalid and node.config.dumpEnabled:
dump(node.config.dumpDir / "invalid", signedBlock, blockRoot)
let parent = node.blockPool.getRef(signedBlock.message.parent_root)
if parent != nil:
let parentBs = parent.atSlot(signedBlock.message.slot - 1)
node.blockPool.withState(node.blockPool.tmpState, parentBs):
dump(node.config.dumpDir / "invalid", hashedState, parent)
return err(blck.error) return err(blck.error)
# The block we received contains attestations, and we might not yet know about # 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 the block # all of them. Let's add them to the attestation pool.
# is not yet resolved, neither will the attestations be!
# But please note that we only care about recent attestations.
# TODO shouldn't add attestations if the block turns out to be invalid..
let currentSlot = node.beaconClock.now.toSlot let currentSlot = node.beaconClock.now.toSlot
if currentSlot.afterGenesis and if currentSlot.afterGenesis and
signedBlock.message.slot.epoch + 1 >= currentSlot.slot.epoch: signedBlock.message.slot.epoch + 1 >= currentSlot.slot.epoch:
@ -770,7 +774,11 @@ proc run*(node: BeaconNode) =
let (afterGenesis, slot) = node.beaconClock.now.toSlot() let (afterGenesis, slot) = node.beaconClock.now.toSlot()
if not afterGenesis: if not afterGenesis:
return false return false
node.blockPool.isValidBeaconBlock(signedBlock, slot, {})
let blck = node.blockPool.isValidBeaconBlock(signedBlock, slot, {})
node.dumpBlock(signedBlock, blck)
blck.isOk
installAttestationHandlers(node) installAttestationHandlers(node)
@ -1080,10 +1088,7 @@ programMain:
createPidFile(config.dataDir.string / "beacon_node.pid") createPidFile(config.dataDir.string / "beacon_node.pid")
if config.dumpEnabled: config.createDumpDirs()
createDir(config.dumpDir)
createDir(config.dumpDir / "incoming")
createDir(config.dumpDir / "invalid")
var node = waitFor BeaconNode.init(config) var node = waitFor BeaconNode.init(config)

View File

@ -171,7 +171,8 @@ proc updateStateData*(pool: BlockPool, state: var StateData, bs: BlockSlot) =
proc loadTailState*(pool: BlockPool): StateData = proc loadTailState*(pool: BlockPool): StateData =
loadTailState(pool.dag) loadTailState(pool.dag)
proc isValidBeaconBlock*(pool: var BlockPool, proc isValidBeaconBlock*(
signed_beacon_block: SignedBeaconBlock, pool: var BlockPool, signed_beacon_block: SignedBeaconBlock,
current_slot: Slot, flags: UpdateFlags): bool = current_slot: Slot, flags: UpdateFlags): Result[void, BlockError] =
isValidBeaconBlock(pool.dag, pool.quarantine, signed_beacon_block, current_slot, flags) isValidBeaconBlock(
pool.dag, pool.quarantine, signed_beacon_block, current_slot, flags)

View File

@ -259,7 +259,7 @@ proc add*(
proc isValidBeaconBlock*( proc isValidBeaconBlock*(
dag: CandidateChains, quarantine: var Quarantine, dag: CandidateChains, quarantine: var Quarantine,
signed_beacon_block: SignedBeaconBlock, current_slot: Slot, signed_beacon_block: SignedBeaconBlock, current_slot: Slot,
flags: UpdateFlags): bool = flags: UpdateFlags): Result[void, BlockError] =
logScope: logScope:
topics = "clearance valid_blck" topics = "clearance valid_blck"
received_block = shortLog(signed_beacon_block.message) received_block = shortLog(signed_beacon_block.message)
@ -276,7 +276,7 @@ proc isValidBeaconBlock*(
if not (signed_beacon_block.message.slot <= current_slot + 1): if not (signed_beacon_block.message.slot <= current_slot + 1):
debug "block is from a future slot", debug "block is from a future slot",
current_slot current_slot
return false return err(Invalid)
# The block is from a slot greater than the latest finalized slot (with a # The block is from a slot greater than the latest finalized slot (with a
# MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. validate that # MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. validate that
@ -284,7 +284,7 @@ proc isValidBeaconBlock*(
# compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) # compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
if not (signed_beacon_block.message.slot > dag.finalizedHead.slot): if not (signed_beacon_block.message.slot > dag.finalizedHead.slot):
debug "block is not from a slot greater than the latest finalized slot" debug "block is not from a slot greater than the latest finalized slot"
return false return err(Invalid)
# The block is the first block with valid signature received for the proposer # The block is the first block with valid signature received for the proposer
# for the slot, signed_beacon_block.message.slot. # for the slot, signed_beacon_block.message.slot.
@ -324,7 +324,7 @@ proc isValidBeaconBlock*(
debug "block isn't first block with valid signature received for the proposer", debug "block isn't first block with valid signature received for the proposer",
blckRef = slotBlockRef, blckRef = slotBlockRef,
existing_block = shortLog(blck.message) existing_block = shortLog(blck.message)
return false return err(Invalid)
# If this block doesn't have a parent we know about, we can't/don't really # If this block doesn't have a parent we know about, we can't/don't really
# trace it back to a known-good state/checkpoint to verify its prevenance; # trace it back to a known-good state/checkpoint to verify its prevenance;
@ -347,7 +347,7 @@ proc isValidBeaconBlock*(
debug "parent unknown, putting block in quarantine" debug "parent unknown, putting block in quarantine"
quarantine.pending[hash_tree_root(signed_beacon_block.message)] = quarantine.pending[hash_tree_root(signed_beacon_block.message)] =
signed_beacon_block signed_beacon_block
return false return err(MissingParent)
# The proposer signature, signed_beacon_block.signature, is valid with # The proposer signature, signed_beacon_block.signature, is valid with
# respect to the proposer_index pubkey. # respect to the proposer_index pubkey.
@ -356,13 +356,13 @@ proc isValidBeaconBlock*(
if proposer.isNone: if proposer.isNone:
notice "cannot compute proposer for message" notice "cannot compute proposer for message"
return false return err(Invalid)
if proposer.get()[0] != if proposer.get()[0] !=
ValidatorIndex(signed_beacon_block.message.proposer_index): ValidatorIndex(signed_beacon_block.message.proposer_index):
debug "block had unexpected proposer", debug "block had unexpected proposer",
expected_proposer = proposer.get()[0] expected_proposer = proposer.get()[0]
return false return err(Invalid)
if not verify_block_signature( if not verify_block_signature(
dag.headState.data.data.fork, dag.headState.data.data.fork,
@ -374,6 +374,6 @@ proc isValidBeaconBlock*(
debug "block failed signature verification", debug "block failed signature verification",
signature = shortLog(signed_beacon_block.signature) signature = shortLog(signed_beacon_block.signature)
return false return err(Invalid)
true ok()

View File

@ -324,6 +324,25 @@ proc defaultDataDir*(conf: BeaconNodeConf|ValidatorClientConf): string =
func dumpDir*(conf: BeaconNodeConf|ValidatorClientConf): string = func dumpDir*(conf: BeaconNodeConf|ValidatorClientConf): string =
conf.dataDir / "dump" conf.dataDir / "dump"
func dumpDirInvalid*(conf: BeaconNodeConf|ValidatorClientConf): string =
conf.dumpDir / "invalid" # things that failed validation
func dumpDirIncoming*(conf: BeaconNodeConf|ValidatorClientConf): string =
conf.dumpDir / "incoming" # things that couldn't be validated (missingparent etc)
func dumpDirOutgoing*(conf: BeaconNodeConf|ValidatorClientConf): string =
conf.dumpDir / "outgoing" # things we produced
proc createDumpDirs*(conf: BeaconNodeConf) =
if conf.dumpEnabled:
try:
createDir(conf.dumpDirInvalid)
createDir(conf.dumpDirIncoming)
createDir(conf.dumpDirOutgoing)
except CatchableError as err:
# Dumping is mainly a debugging feature, so ignore these..
warn "Cannot create dump directories", msg = err.msg
func validatorsDir*(conf: BeaconNodeConf|ValidatorClientConf): string = func validatorsDir*(conf: BeaconNodeConf|ValidatorClientConf): string =
string conf.validatorsDirFlag.get(InputDir(conf.dataDir / "validators")) string conf.validatorsDirFlag.get(InputDir(conf.dataDir / "validators"))

View File

@ -122,7 +122,7 @@ proc createAndSendAttestation(node: BeaconNode,
node.sendAttestation(attestation) node.sendAttestation(attestation)
if node.config.dumpEnabled: if node.config.dumpEnabled:
dump(node.config.dumpDir, attestation.data, validator.pubKey) dump(node.config.dumpDirOutgoing, attestation.data, validator.pubKey)
info "Attestation sent", info "Attestation sent",
attestation = shortLog(attestation), attestation = shortLog(attestation),
@ -221,10 +221,7 @@ proc proposeSignedBlock*(node: BeaconNode,
cat = "consensus" cat = "consensus"
if node.config.dumpEnabled: if node.config.dumpEnabled:
dump(node.config.dumpDir, newBlock, newBlockRef[]) dump(node.config.dumpDirOutgoing, newBlock, newBlockRef[])
node.blockPool.withState(
node.blockPool.tmpState, newBlockRef[].atSlot(newBlockRef[].slot)):
dump(node.config.dumpDir, hashedState, newBlockRef[])
node.network.broadcast(node.topicBeaconBlocks, newBlock) node.network.broadcast(node.topicBeaconBlocks, newBlock)

View File

@ -18,6 +18,7 @@ type
DbCmd* = enum DbCmd* = enum
bench bench
dumpState dumpState
rewindState
DbConf = object DbConf = object
databaseDir* {. databaseDir* {.
@ -40,6 +41,15 @@ type
argument argument
desc: "State roots to save".}: seq[string] desc: "State roots to save".}: seq[string]
of rewindState:
blockRoot* {.
argument
desc: "Block root".}: string
slot* {.
argument
desc: "Slot".}: uint64
proc cmdBench(conf: DbConf) = proc cmdBench(conf: DbConf) =
var timers: array[Timers, RunningStat] var timers: array[Timers, RunningStat]
@ -104,6 +114,28 @@ proc cmdDumpState(conf: DbConf) =
except CatchableError as e: except CatchableError as e:
echo "Couldn't load ", stateRoot, ": ", e.msg echo "Couldn't load ", stateRoot, ": ", e.msg
proc cmdRewindState(conf: DbConf) =
echo "Opening database..."
let
db = BeaconChainDB.init(
kvStore SqStoreRef.init(conf.databaseDir.string, "nbc").tryGet())
if not BlockPool.isInitialized(db):
echo "Database not initialized"
quit 1
echo "Initializing block pool..."
let pool = BlockPool.init(db, {})
let blckRef = pool.getRef(fromHex(Eth2Digest, conf.blockRoot))
if blckRef == nil:
echo "Block not found in database"
return
pool.withState(pool.tmpState, blckRef.atSlot(Slot(conf.slot))):
echo "Writing state..."
dump("./", hashedState, blck)
when isMainModule: when isMainModule:
let let
conf = DbConf.load() conf = DbConf.load()
@ -113,3 +145,5 @@ when isMainModule:
cmdBench(conf) cmdBench(conf)
of dumpState: of dumpState:
cmdDumpState(conf) cmdDumpState(conf)
of rewindState:
cmdRewindState(conf)