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:
parent
a25bc025d1
commit
49e9167b28
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue