cache block hash (#1329)

hash_tree_root was turning up when running beacon_node, turns out to be
repeated hash_tree_root invocations - this pr brings them back down to
normal.

this PR caches the root of a block in the SignedBeaconBlock object -
this has the potential downside that even invalid blocks will be hashed
(as part of deserialization) - later, one could imagine delaying this
until checks have passed

there's also some cleanup of the `cat=` logs which were applied randomly
and haphazardly, and to a large degree are duplicated by other
information in the log statements - in particular, topics fulfill the
same role
This commit is contained in:
Jacek Sieka 2020-07-16 15:16:51 +02:00 committed by GitHub
parent 6052f36fcd
commit 8b01284b0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 227 additions and 324 deletions

View File

@ -135,16 +135,14 @@ proc slotIndex(
# to start counting at the last finalized epoch start slot - anything
# earlier than that is thrown out by the above check
info "First attestation!",
attestationSlot = $shortLog(attestationSlot),
cat = "init"
attestationSlot = shortLog(attestationSlot)
pool.startingSlot =
state.finalized_checkpoint.epoch.compute_start_slot_at_epoch()
if pool.startingSlot + pool.mapSlotsToAttestations.len.uint64 <= attestationSlot:
trace "Growing attestation pool",
attestationSlot = $shortLog(attestationSlot),
startingSlot = $shortLog(pool.startingSlot),
cat = "caching"
attestationSlot = shortLog(attestationSlot),
startingSlot = shortLog(pool.startingSlot)
# Make sure there's a pool entry for every slot, even when there's a gap
while pool.startingSlot + pool.mapSlotsToAttestations.len.uint64 <= attestationSlot:
@ -153,11 +151,10 @@ proc slotIndex(
if pool.startingSlot <
state.finalized_checkpoint.epoch.compute_start_slot_at_epoch():
debug "Pruning attestation pool",
startingSlot = $shortLog(pool.startingSlot),
finalizedSlot = $shortLog(
startingSlot = shortLog(pool.startingSlot),
finalizedSlot = shortLog(
state.finalized_checkpoint
.epoch.compute_start_slot_at_epoch()),
cat = "pruning"
.epoch.compute_start_slot_at_epoch())
# TODO there should be a better way to remove a whole epoch of stuff..
while pool.startingSlot <
@ -245,8 +242,7 @@ proc addResolved(pool: var AttestationPool, blck: BlockRef, attestation: Attesta
if not isValidAttestationTargetEpoch(state, attestation.data):
notice "Invalid attestation",
attestation = shortLog(attestation),
current_epoch = get_current_epoch(state),
cat = "filtering"
current_epoch = get_current_epoch(state)
return
# TODO inefficient data structures..
@ -274,8 +270,7 @@ proc addResolved(pool: var AttestationPool, blck: BlockRef, attestation: Attesta
# sets by virtue of not overlapping with some other attestation
# and therefore being useful after all?
trace "Ignoring subset attestation",
newParticipants = participants,
cat = "filtering"
newParticipants = participants
found = true
break
@ -284,8 +279,7 @@ proc addResolved(pool: var AttestationPool, blck: BlockRef, attestation: Attesta
# can now be removed per same logic as above
trace "Removing subset attestations",
newParticipants = participants,
cat = "pruning"
newParticipants = participants
a.validations.keepItIf(
not it.aggregation_bits.isSubsetOf(validation.aggregation_bits))
@ -297,8 +291,7 @@ proc addResolved(pool: var AttestationPool, blck: BlockRef, attestation: Attesta
attestation = shortLog(attestation),
validations = a.validations.len(),
current_epoch = get_current_epoch(state),
blockSlot = shortLog(blck.slot),
cat = "filtering"
blockSlot = shortLog(blck.slot)
found = true
@ -316,8 +309,7 @@ proc addResolved(pool: var AttestationPool, blck: BlockRef, attestation: Attesta
attestation = shortLog(attestation),
current_epoch = get_current_epoch(state),
validations = 1,
blockSlot = shortLog(blck.slot),
cat = "filtering"
blockSlot = shortLog(blck.slot)
proc addAttestation*(pool: var AttestationPool, attestation: Attestation) =
## Add a verified attestation to the fork choice context
@ -400,14 +392,12 @@ proc getAttestationsForSlot*(pool: AttestationPool, newBlockSlot: Slot):
Option[AttestationsSeen] =
if newBlockSlot < (GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY):
debug "Too early for attestations",
newBlockSlot = shortLog(newBlockSlot),
cat = "query"
newBlockSlot = shortLog(newBlockSlot)
return none(AttestationsSeen)
if pool.mapSlotsToAttestations.len == 0: # startingSlot not set yet!
info "No attestations found (pool empty)",
newBlockSlot = shortLog(newBlockSlot),
cat = "query"
newBlockSlot = shortLog(newBlockSlot)
return none(AttestationsSeen)
let
@ -423,8 +413,7 @@ proc getAttestationsForSlot*(pool: AttestationPool, newBlockSlot: Slot):
info "No attestations matching the slot range",
attestationSlot = shortLog(attestationSlot),
startingSlot = shortLog(pool.startingSlot),
endingSlot = shortLog(pool.startingSlot + pool.mapSlotsToAttestations.len.uint64),
cat = "query"
endingSlot = shortLog(pool.startingSlot + pool.mapSlotsToAttestations.len.uint64)
return none(AttestationsSeen)
let slotDequeIdx = int(attestationSlot - pool.startingSlot)
@ -484,7 +473,7 @@ proc getAttestationsForBlock*(pool: AttestationPool,
# to include a broken attestation
if not check_attestation(state, attestation, {}, cache):
warn "Attestation no longer validates...",
cat = "query"
attestation = shortLog(attestation)
continue
for v in a.validations[1..^1]:
@ -637,7 +626,7 @@ proc pruneBefore*(pool: var AttestationPool, finalizedhead: BlockSlot) =
proc selectHead*(pool: var AttestationPool): BlockRef =
let head_v1 = pool.selectHead_v1()
# let head_v2 = pool.selectHead_v2()
#
#
# if head_v1 != head_v2:
# error "Fork choice engines in disagreement, using block from v1.",
# v1_block = shortlog(head_v1),

View File

@ -115,10 +115,10 @@ proc get(db: BeaconChainDB, key: openArray[byte], res: var auto): bool =
found
proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: SignedBeaconBlock) =
db.put(subkey(type value, key), value)
proc putBlock*(db: BeaconChainDB, key: Eth2Digest, value: TrustedSignedBeaconBlock) =
db.put(subkey(SignedBeaconBlock, key), value)
proc putBlock*(db: BeaconChainDB, value: SignedBeaconBlock) =
db.put(subkey(type value, value.root), value)
proc putBlock*(db: BeaconChainDB, value: TrustedSignedBeaconBlock) =
db.put(subkey(SignedBeaconBlock, value.root), value)
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: BeaconState) =
# TODO prune old states - this is less easy than it seems as we never know
@ -133,11 +133,6 @@ proc putStateRoot*(db: BeaconChainDB, root: Eth2Digest, slot: Slot,
value: Eth2Digest) =
db.put(subkey(root, slot), value)
proc putBlock*(db: BeaconChainDB, value: SomeSignedBeaconBlock) =
# TODO this should perhaps be a TrustedSignedBeaconBlock, but there's no
# trivial way to coerce one type into the other, as it stands..
db.putBlock(hash_tree_root(value.message), value)
proc delBlock*(db: BeaconChainDB, key: Eth2Digest) =
db.backend.del(subkey(SignedBeaconBlock, key)).expect(
"working database")
@ -156,7 +151,7 @@ proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database
result.ok(TrustedSignedBeaconBlock())
result.ok(TrustedSignedBeaconBlock(root: key))
if not db.get(subkey(SignedBeaconBlock, key), result.get):
result.err()
@ -195,14 +190,14 @@ proc containsState*(db: BeaconChainDB, key: Eth2Digest): bool =
db.backend.contains(subkey(BeaconState, key)).expect("working database")
iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
tuple[root: Eth2Digest, blck: TrustedSignedBeaconBlock] =
TrustedSignedBeaconBlock =
## Load a chain of ancestors for blck - returns a list of blocks with the
## oldest block last (blck will be at result[0]).
##
## The search will go on until the ancestor cannot be found.
var res: tuple[root: Eth2Digest, blck: TrustedSignedBeaconBlock]
var res: TrustedSignedBeaconBlock
res.root = root
while db.get(subkey(SignedBeaconBlock, res.root), res.blck):
while db.get(subkey(SignedBeaconBlock, res.root), res):
yield res
res.root = res.blck.message.parent_root
res.root = res.message.parent_root

View File

@ -270,31 +270,29 @@ proc onAttestation(node: BeaconNode, attestation: Attestation) =
# We received an attestation from the network but don't know much about it
# yet - in particular, we haven't verified that it belongs to particular chain
# we're on, or that it follows the rules of the protocol
logScope: pcs = "on_attestation"
logScope:
attestation = shortLog(attestation)
pcs = "on_attestation"
let
wallSlot = node.beaconClock.now().toSlot()
head = node.blockPool.head
debug "Attestation received",
attestation = shortLog(attestation),
headRoot = shortLog(head.blck.root),
headSlot = shortLog(head.blck.slot),
wallSlot = shortLog(wallSlot.slot),
cat = "consensus" # Tag "consensus|attestation"?
head = shortLog(head.blck),
wallSlot = shortLog(wallSlot.slot)
if not wallSlot.afterGenesis or wallSlot.slot < head.blck.slot:
warn "Received attestation before genesis or head - clock is wrong?",
afterGenesis = wallSlot.afterGenesis,
wallSlot = shortLog(wallSlot.slot),
headSlot = shortLog(head.blck.slot),
cat = "clock_drift" # Tag "attestation|clock_drift"?
head = shortLog(head.blck)
return
if attestation.data.slot > head.blck.slot and
(attestation.data.slot - head.blck.slot) > MaxEmptySlotCount:
warn "Ignoring attestation, head block too old (out of sync?)",
attestationSlot = attestation.data.slot, headSlot = head.blck.slot
head = head.blck
return
node.attestationPool.addAttestation(attestation)
@ -306,28 +304,24 @@ proc dumpBlock[T](
case res.error
of Invalid:
dump(
node.config.dumpDirInvalid, signedBlock,
hash_tree_root(signedBlock.message))
node.config.dumpDirInvalid, signedBlock)
of MissingParent:
dump(
node.config.dumpDirIncoming, signedBlock,
hash_tree_root(signedBlock.message))
node.config.dumpDirIncoming, signedBlock)
else:
discard
proc storeBlock(
node: BeaconNode, signedBlock: SignedBeaconBlock): Result[void, BlockError] =
let blockRoot = hash_tree_root(signedBlock.message)
debug "Block received",
signedBlock = shortLog(signedBlock.message),
blockRoot = shortLog(blockRoot),
cat = "block_listener",
blockRoot = shortLog(signedBlock.root),
pcs = "receive_block"
beacon_blocks_received.inc()
{.gcsafe.}: # TODO: fork choice and blockpool should sync via messages instead of callbacks
let blck = node.blockPool.addRawBlock(blockRoot, signedBlock) do (validBlock: BlockRef):
let blck = node.blockPool.addRawBlock(signedBlock) do (validBlock: BlockRef):
# Callback add to fork choice if valid
# node.attestationPool.addForkChoice_v2(validBlock)
discard "TODO: Deactivated"
@ -344,8 +338,7 @@ proc storeBlock(
# all of them. Let's add them to the attestation pool.
for attestation in signedBlock.message.body.attestations:
debug "Attestation from block",
attestation = shortLog(attestation),
cat = "consensus" # Tag "consensus|attestation"?
attestation = shortLog(attestation)
node.attestationPool.addAttestation(attestation)
ok()
@ -398,8 +391,7 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
headRoot = shortLog(node.blockPool.head.blck.root),
finalizedSlot = shortLog(node.blockPool.finalizedHead.blck.slot),
finalizedRoot = shortLog(node.blockPool.finalizedHead.blck.root),
finalizedEpoch = shortLog(node.blockPool.finalizedHead.blck.slot.compute_epoch_at_slot()),
cat = "scheduling"
finalizedEpoch = shortLog(node.blockPool.finalizedHead.blck.slot.compute_epoch_at_slot())
# Check before any re-scheduling of onSlotStart()
# Offset backwards slightly to allow this epoch's finalization check to occur
@ -427,8 +419,7 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
beaconTime = shortLog(beaconTime),
lastSlot = shortLog(lastSlot),
scheduledSlot = shortLog(scheduledSlot),
nextSlot = shortLog(nextSlot),
cat = "clock_drift" # tag "scheduling|clock_drift"?
nextSlot = shortLog(nextSlot)
addTimer(saturate(node.beaconClock.fromNow(nextSlot))) do (p: pointer):
asyncCheck node.onSlotStart(slot, nextSlot)
@ -454,8 +445,7 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
lastSlot = shortLog(lastSlot),
slot = shortLog(slot),
nextSlot = shortLog(nextSlot),
scheduledSlot = shortLog(scheduledSlot),
cat = "overload"
scheduledSlot = shortLog(scheduledSlot)
addTimer(saturate(node.beaconClock.fromNow(nextSlot))) do (p: pointer):
# We pass the current slot here to indicate that work should be skipped!
@ -502,8 +492,7 @@ proc onSlotStart(node: BeaconNode, lastSlot, scheduledSlot: Slot) {.gcsafe, asyn
headRoot = shortLog(node.blockPool.head.blck.root),
finalizedSlot = shortLog(node.blockPool.finalizedHead.blck.slot),
finalizedEpoch = shortLog(node.blockPool.finalizedHead.blck.slot.compute_epoch_at_slot()),
finalizedRoot = shortLog(node.blockPool.finalizedHead.blck.root),
cat = "scheduling"
finalizedRoot = shortLog(node.blockPool.finalizedHead.blck.root)
when declared(GC_fullCollect):
# The slots in the beacon node work as frames in a game: we want to make
@ -824,8 +813,7 @@ proc run*(node: BeaconNode) =
info "Scheduling first slot action",
beaconTime = shortLog(node.beaconClock.now()),
nextSlot = shortLog(nextSlot),
fromNow = shortLog(fromNow),
cat = "scheduling"
fromNow = shortLog(fromNow)
addTimer(fromNow) do (p: pointer):
asyncCheck node.onSlotStart(curSlot, nextSlot)
@ -876,15 +864,12 @@ proc start(node: BeaconNode) =
timeSinceFinalization =
int64(finalizedHead.slot.toBeaconTime()) -
int64(node.beaconClock.now()),
headSlot = shortLog(head.blck.slot),
headRoot = shortLog(head.blck.root),
finalizedSlot = shortLog(finalizedHead.blck.slot),
finalizedRoot = shortLog(finalizedHead.blck.root),
head = shortLog(head.blck),
finalizedHead = shortLog(finalizedHead),
SLOTS_PER_EPOCH,
SECONDS_PER_SLOT,
SPEC_VERSION,
dataDir = node.config.dataDir.string,
cat = "init",
pcs = "start_beacon_node"
if genesisTime.inFuture:

View File

@ -53,8 +53,7 @@ template head*(pool: BlockPool): Head =
template finalizedHead*(pool: BlockPool): BlockSlot =
pool.dag.finalizedHead
proc addRawBlock*(pool: var BlockPool, blockRoot: Eth2Digest,
signedBlock: SignedBeaconBlock,
proc addRawBlock*(pool: var BlockPool, signedBlock: SignedBeaconBlock,
callback: proc(blck: BlockRef)
): Result[BlockRef, BlockError] =
## Add a raw block to the blockpool
@ -65,7 +64,7 @@ proc addRawBlock*(pool: var BlockPool, blockRoot: Eth2Digest,
# - the ugly `inAdd` field
# - the callback
# - callback may be problematic as it's called in async validator duties
result = addRawBlock(pool.dag, pool.quarantine, blockRoot, signedBlock, callback)
result = addRawBlock(pool.dag, pool.quarantine, signedBlock, callback)
export parent # func parent*(bs: BlockSlot): BlockSlot
export isAncestorOf # func isAncestorOf*(a, b: BlockRef): bool

View File

@ -26,8 +26,8 @@ declareCounter beacon_state_data_cache_misses, "dag.cachedStates misses"
logScope: topics = "hotdb"
proc putBlock*(
dag: var CandidateChains, blockRoot: Eth2Digest, signedBlock: SignedBeaconBlock) =
dag.db.putBlock(blockRoot, signedBlock)
dag: var CandidateChains, signedBlock: SignedBeaconBlock) =
dag.db.putBlock(signedBlock)
proc updateStateData*(
dag: CandidateChains, state: var StateData, bs: BlockSlot) {.gcsafe.}
@ -226,14 +226,14 @@ proc init*(T: type CandidateChains,
if headRoot != tailRoot:
var curRef: BlockRef
for root, blck in db.getAncestors(headRoot):
if root == tailRef.root:
for blck in db.getAncestors(headRoot):
if blck.root == tailRef.root:
doAssert(not curRef.isNil)
link(tailRef, curRef)
curRef = curRef.parent
break
let newRef = BlockRef.init(root, blck.message)
let newRef = BlockRef.init(blck.root, blck.message)
if curRef == nil:
curRef = newRef
headRef = newRef
@ -428,8 +428,8 @@ proc putState*(dag: CandidateChains, state: HashedBeaconState, blck: BlockRef) =
info "Storing state",
blck = shortLog(blck),
stateSlot = shortLog(state.data.slot),
stateRoot = shortLog(state.root),
cat = "caching"
stateRoot = shortLog(state.root)
dag.db.putState(state.root, state.data)
if not rootWritten:
dag.db.putStateRoot(blck.root, state.data.slot, state.root)
@ -542,7 +542,9 @@ proc skipAndUpdateState(
proc rewindState(dag: CandidateChains, state: var StateData, bs: BlockSlot):
seq[BlockRef] =
logScope: pcs = "replay_state"
logScope:
blockSlot = shortLog(bs)
pcs = "replay_state"
var ancestors = @[bs.blck]
# Common case: the last block applied is the parent of the block to apply:
@ -586,11 +588,7 @@ proc rewindState(dag: CandidateChains, state: var StateData, bs: BlockSlot):
trace "Replaying state transitions via in-memory cache",
stateSlot = shortLog(state.data.data.slot),
ancestorStateRoot = shortLog(state.data.root),
ancestorStateSlot = shortLog(state.data.data.slot),
slot = shortLog(bs.slot),
blockRoot = shortLog(bs.blck.root),
ancestors = ancestors.len,
cat = "replay_state"
ancestors = ancestors.len
return ancestors
@ -607,11 +605,7 @@ proc rewindState(dag: CandidateChains, state: var StateData, bs: BlockSlot):
# list of parent blocks and couldn't find a corresponding state in the
# database, which should never happen (at least we should have the
# tail state in there!)
error "Couldn't find ancestor state root!",
blockRoot = shortLog(bs.blck.root),
blockSlot = shortLog(bs.blck.slot),
slot = shortLog(bs.slot),
cat = "crash"
fatal "Couldn't find ancestor state root!"
doAssert false, "Oh noes, we passed big bang!"
let
@ -624,20 +618,12 @@ proc rewindState(dag: CandidateChains, state: var StateData, bs: BlockSlot):
# list of parent blocks and couldn't find a corresponding state in the
# database, which should never happen (at least we should have the
# tail state in there!)
error "Couldn't find ancestor state or block parent missing!",
blockRoot = shortLog(bs.blck.root),
blockSlot = shortLog(bs.blck.slot),
slot = shortLog(bs.slot),
cat = "crash"
fatal "Couldn't find ancestor state or block parent missing!"
doAssert false, "Oh noes, we passed big bang!"
trace "Replaying state transitions",
stateSlot = shortLog(state.data.data.slot),
ancestorStateSlot = shortLog(state.data.data.slot),
slot = shortLog(bs.slot),
blockRoot = shortLog(bs.blck.root),
ancestors = ancestors.len,
cat = "replay_state"
ancestors = ancestors.len
ancestors
@ -743,12 +729,12 @@ proc updateHead*(dag: CandidateChains, newHead: BlockRef) =
## blocks that were once considered potential candidates for a tree will
## now fall from grace, or no longer be considered resolved.
doAssert newHead.parent != nil or newHead.slot == 0
logScope: pcs = "fork_choice"
logScope:
newHead = shortLog(newHead)
pcs = "fork_choice"
if dag.head.blck == newHead:
info "No head block update",
head = shortLog(newHead),
cat = "fork_choice"
info "No head block update"
return
@ -779,8 +765,7 @@ proc updateHead*(dag: CandidateChains, newHead: BlockRef) =
headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(dag.headState.data.data.slot),
justifiedEpoch = shortLog(dag.headState.data.data.current_justified_checkpoint.epoch),
finalizedEpoch = shortLog(dag.headState.data.data.finalized_checkpoint.epoch),
cat = "fork_choice"
finalizedEpoch = shortLog(dag.headState.data.data.finalized_checkpoint.epoch)
# A reasonable criterion for "reorganizations of the chain"
beacon_reorgs_total.inc()
@ -790,9 +775,7 @@ proc updateHead*(dag: CandidateChains, newHead: BlockRef) =
headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(dag.headState.data.data.slot),
justifiedEpoch = shortLog(dag.headState.data.data.current_justified_checkpoint.epoch),
finalizedEpoch = shortLog(dag.headState.data.data.finalized_checkpoint.epoch),
cat = "fork_choice"
finalizedEpoch = shortLog(dag.headState.data.data.finalized_checkpoint.epoch)
let
finalizedEpochStartSlot =
dag.headState.data.data.finalized_checkpoint.epoch.
@ -855,9 +838,7 @@ proc updateHead*(dag: CandidateChains, newHead: BlockRef) =
info "Finalized block",
finalizedHead = shortLog(finalizedHead),
head = shortLog(newHead),
heads = dag.heads.len,
cat = "fork_choice"
heads = dag.heads.len
# TODO prune everything before weak subjectivity period
@ -904,22 +885,18 @@ proc preInit*(
# TODO probably should just init a blockpool with the freshly written
# state - but there's more refactoring needed to make it nice - doing
# a minimal patch for now..
let
blockRoot = hash_tree_root(signedBlock.message)
doAssert signedBlock.message.state_root == hash_tree_root(state)
notice "New database from snapshot",
blockRoot = shortLog(blockRoot),
blockRoot = shortLog(signedBlock.root),
stateRoot = shortLog(signedBlock.message.state_root),
fork = state.fork,
validators = state.validators.len(),
cat = "initialization"
validators = state.validators.len()
db.putState(state)
db.putBlock(signedBlock)
db.putTailBlock(blockRoot)
db.putHeadBlock(blockRoot)
db.putStateRoot(blockRoot, state.slot, signedBlock.message.state_root)
db.putTailBlock(signedBlock.root)
db.putHeadBlock(signedBlock.root)
db.putStateRoot(signedBlock.root, state.slot, signedBlock.message.state_root)
proc getProposer*(
dag: CandidateChains, head: BlockRef, slot: Slot):

View File

@ -36,15 +36,12 @@ func getOrResolve*(dag: CandidateChains, quarantine: var Quarantine, root: Eth2D
proc addRawBlock*(
dag: var CandidateChains, quarantine: var Quarantine,
blockRoot: Eth2Digest,
signedBlock: SignedBeaconBlock,
callback: proc(blck: BlockRef)
signedBlock: SignedBeaconBlock, callback: proc(blck: BlockRef)
): Result[BlockRef, BlockError]
proc addResolvedBlock(
dag: var CandidateChains, quarantine: var Quarantine,
state: BeaconState, blockRoot: Eth2Digest,
signedBlock: SignedBeaconBlock, parent: BlockRef,
state: BeaconState, signedBlock: SignedBeaconBlock, parent: BlockRef,
callback: proc(blck: BlockRef)
): BlockRef =
# TODO: `addResolvedBlock` is accumulating significant cruft
@ -55,7 +52,9 @@ proc addResolvedBlock(
logScope: pcs = "block_resolution"
doAssert state.slot == signedBlock.message.slot, "state must match block"
let blockRef = BlockRef.init(blockRoot, signedBlock.message)
let
blockRoot = signedBlock.root
blockRef = BlockRef.init(blockRoot, signedBlock.message)
blockRef.epochsInfo = filterIt(parent.epochsInfo,
it.epoch + 1 >= state.slot.compute_epoch_at_slot)
link(parent, blockRef)
@ -64,7 +63,7 @@ proc addResolvedBlock(
trace "Populating block dag", key = blockRoot, val = blockRef
# Resolved blocks should be stored in database
dag.putBlock(blockRoot, signedBlock)
dag.putBlock(signedBlock)
# This block *might* have caused a justification - make sure we stow away
# that information:
@ -92,8 +91,7 @@ proc addResolvedBlock(
blck = shortLog(signedBlock.message),
blockRoot = shortLog(blockRoot),
justifiedHead = foundHead.get().justified,
heads = dag.heads.len(),
cat = "filtering"
heads = dag.heads.len()
# This MUST be added before the quarantine
callback(blockRef)
@ -113,8 +111,8 @@ proc addResolvedBlock(
var keepGoing = true
while keepGoing:
let retries = quarantine.orphans
for k, v in retries:
discard addRawBlock(dag, quarantine, k, v, callback)
for _, v in retries:
discard addRawBlock(dag, quarantine, v, callback)
# Keep going for as long as the pending dag is shrinking
# TODO inefficient! so what?
keepGoing = quarantine.orphans.len < retries.len
@ -123,7 +121,6 @@ proc addResolvedBlock(
proc addRawBlock*(
dag: var CandidateChains, quarantine: var Quarantine,
blockRoot: Eth2Digest,
signedBlock: SignedBeaconBlock,
callback: proc(blck: BlockRef)
): Result[BlockRef, BlockError] =
@ -141,18 +138,16 @@ proc addRawBlock*(
# This would be easy apart from the "Block already exists"
# early return.
logScope:
blck = shortLog(signedBlock.message)
blockRoot = shortLog(signedBlock.root)
let blck = signedBlock.message
doAssert blockRoot == hash_tree_root(blck), "blockRoot: 0x" & shortLog(blockRoot) & ", signedBlock: 0x" & shortLog(hash_tree_root(blck))
logScope: pcs = "block_addition"
template blck(): untyped = signedBlock.message # shortcuts without copy
template blockRoot(): untyped = signedBlock.root
# Already seen this block??
if blockRoot in dag.blocks:
debug "Block already exists",
blck = shortLog(blck),
blockRoot = shortLog(blockRoot),
cat = "filtering"
debug "Block already exists"
# There can be a scenario where we receive a block we already received.
# However this block was before the last finalized epoch and so its parent
@ -168,11 +163,8 @@ proc addRawBlock*(
# by the time it gets here.
if blck.slot <= dag.finalizedHead.slot:
debug "Old block, dropping",
blck = shortLog(blck),
finalizedHead = shortLog(dag.finalizedHead),
tail = shortLog(dag.tail),
blockRoot = shortLog(blockRoot),
cat = "filtering"
tail = shortLog(dag.tail)
return err Unviable
@ -183,8 +175,6 @@ proc addRawBlock*(
# A block whose parent is newer than the block itself is clearly invalid -
# discard it immediately
notice "Invalid block slot",
blck = shortLog(blck),
blockRoot = shortLog(blockRoot),
parentBlock = shortLog(parent)
return err Invalid
@ -199,11 +189,8 @@ proc addRawBlock*(
# latest thing that happened on the chain and they're performing their
# duty correctly.
debug "Unviable block, dropping",
blck = shortLog(blck),
finalizedHead = shortLog(dag.finalizedHead),
tail = shortLog(dag.tail),
blockRoot = shortLog(blockRoot),
cat = "filtering"
tail = shortLog(dag.tail)
return err Unviable
@ -233,17 +220,14 @@ proc addRawBlock*(
if not state_transition(dag.runtimePreset, dag.tmpState.data, signedBlock,
stateCache, dag.updateFlags, restore):
# TODO find a better way to log all this block data
notice "Invalid block",
blck = shortLog(blck),
blockRoot = shortLog(blockRoot),
cat = "filtering"
notice "Invalid block"
return err Invalid
# Careful, tmpState.data has been updated but not blck - we need to create
# the BlockRef first!
dag.tmpState.blck = addResolvedBlock(
dag, quarantine,
dag.tmpState.data.data, blockRoot, signedBlock, parent,
dag.tmpState.data.data, signedBlock, parent,
callback
)
dag.putState(dag.tmpState.data, dag.tmpState.blck)
@ -255,7 +239,7 @@ proc addRawBlock*(
# the pending dag calls this function back later in a loop, so as long
# as dag.add(...) requires a SignedBeaconBlock, easier to keep them in
# pending too.
quarantine.add(dag, signedBlock, some(blockRoot))
quarantine.add(dag, signedBlock)
# TODO possibly, it makes sense to check the database - that would allow sync
# to simply fill up the database with random blocks the other clients
@ -280,11 +264,8 @@ proc addRawBlock*(
# from that branch, so right now, we'll just do a blind guess
debug "Unresolved block (parent missing)",
blck = shortLog(blck),
blockRoot = shortLog(blockRoot),
orphans = quarantine.orphans.len,
missing = quarantine.missing.len,
cat = "filtering"
missing = quarantine.missing.len
return err MissingParent
@ -296,6 +277,7 @@ proc isValidBeaconBlock*(
logScope:
topics = "clearance valid_blck"
received_block = shortLog(signed_beacon_block.message)
blockRoot = shortLog(signed_beacon_block.root)
# In general, checks are ordered from cheap to expensive. Especially, crypto
# verification could be quite a bit more expensive than the rest. This is an

View File

@ -10,12 +10,13 @@ import
stew/bitops2,
metrics,
../spec/[datatypes, digest],
../ssz/merkleization,
block_pools_types
export options
logScope: topics = "quarant"
logScope:
topics = "quarant"
{.push raises: [Defect].}
func checkMissing*(quarantine: var Quarantine): seq[FetchRecord] =
@ -43,15 +44,9 @@ func addMissing*(quarantine: var Quarantine, broot: Eth2Digest) {.inline.} =
discard quarantine.missing.hasKeyOrPut(broot, MissingBlock())
func add*(quarantine: var Quarantine, dag: CandidateChains,
sblck: SignedBeaconBlock,
broot: Option[Eth2Digest] = none[Eth2Digest]()) =
sblck: SignedBeaconBlock) =
## Adds block to quarantine's `orphans` and `missing` lists.
let blockRoot = if broot.isSome():
broot.get()
else:
hash_tree_root(sblck.message)
quarantine.orphans[blockRoot] = sblck
quarantine.orphans[sblck.root] = sblck
let parentRoot = sblck.message.parent_root
quarantine.addMissing(parentRoot)

View File

@ -45,7 +45,6 @@ func compute_deltas(
logScope:
topics = "fork_choice"
cat = "fork_choice"
# API:
# - The private procs uses the ForkChoiceError error code

View File

@ -19,7 +19,6 @@ import
logScope:
topics = "fork_choice"
cat = "fork_choice"
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/fork-choice.md
# This is a port of https://github.com/sigp/lighthouse/pull/804

View File

@ -80,8 +80,7 @@ proc sleepToSlotOffset*(clock: BeaconClock, extra: chronos.Duration,
if fromNow.inFuture:
trace msg,
slot = shortLog(slot),
fromNow = shortLog(fromNow.offset),
cat = "scheduling"
fromNow = shortLog(fromNow.offset)
await sleepAsync(fromNow.offset)
return true

View File

@ -41,8 +41,7 @@ proc checkResponse(roots: openArray[Eth2Digest],
if len(blocks) > len(roots):
return false
for blk in blocks:
let blockRoot = hash_tree_root(blk.message)
let res = checks.find(blockRoot)
let res = checks.find(blk.root)
if res == -1:
return false
else:

View File

@ -295,15 +295,15 @@ func is_valid_genesis_state*(preset: RuntimePreset,
# TODO this is now a non-spec helper function, and it's not really accurate
# so only usable/used in research/ and tests/
func get_initial_beacon_block*(state: BeaconState): SignedBeaconBlock =
SignedBeaconBlock(
message: BeaconBlock(
let message = BeaconBlock(
slot: GENESIS_SLOT,
state_root: hash_tree_root(state),
body: BeaconBlockBody(
# TODO: This shouldn't be necessary if OpaqueBlob is the default
randao_reveal: ValidatorSig(kind: OpaqueBlob))))
randao_reveal: ValidatorSig(kind: OpaqueBlob)))
# parent_root, randao_reveal, eth1_data, signature, and body automatically
# initialized to default values.
SignedBeaconBlock(message: message, root: hash_tree_root(message))
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: BeaconState,
@ -589,16 +589,16 @@ proc check_attestation*(
stateSlot = state.slot
data = attestation.data
trace "process_attestation: beginning",
attestation=attestation
logScope:
attestation = shortLog(attestation)
trace "process_attestation: beginning"
let committee_count_at_slot =
get_committee_count_at_slot(get_shuffled_active_validator_indices(
state, stateSlot.compute_epoch_at_slot, stateCache).len.uint64).uint64
if not (data.index < committee_count_at_slot):
warn("Data index exceeds committee count",
data_index = data.index,
committee_count = committee_count_at_slot)
warn "Data index exceeds committee count",
committee_count = committee_count_at_slot
return
if not isValidAttestationTargetEpoch(state, data):
@ -612,10 +612,10 @@ proc check_attestation*(
let committee = get_beacon_committee(
state, data.slot, data.index.CommitteeIndex, stateCache)
if attestation.aggregation_bits.len != committee.len:
warn("Inconsistent aggregation and committee length",
warn "Inconsistent aggregation and committee length",
aggregation_bits_len = attestation.aggregation_bits.len,
committee_len = committee.len
)
return
let ffg_check_data = (data.source.epoch, data.source.root, data.target.epoch)
@ -623,17 +623,17 @@ proc check_attestation*(
if data.target.epoch == get_current_epoch(state):
if not (ffg_check_data == (state.current_justified_checkpoint.epoch,
state.current_justified_checkpoint.root, get_current_epoch(state))):
warn("FFG data not matching current justified epoch")
warn "FFG data not matching current justified epoch"
return
else:
if not (ffg_check_data == (state.previous_justified_checkpoint.epoch,
state.previous_justified_checkpoint.root, get_previous_epoch(state))):
warn("FFG data not matching previous justified epoch")
warn "FFG data not matching previous justified epoch"
return
if not is_valid_indexed_attestation(
state, get_indexed_attestation(state, attestation, stateCache), flags):
warn("process_attestation: signature or bitfields incorrect")
warn "process_attestation: signature or bitfields incorrect"
return
true

View File

@ -416,10 +416,14 @@ type
message*: BeaconBlock
signature*: ValidatorSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
TrustedSignedBeaconBlock* = object
message*: TrustedBeaconBlock
signature*: TrustedSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#signedbeaconblockheader
SignedBeaconBlockHeader* = object
message*: BeaconBlockHeader

View File

@ -235,9 +235,9 @@ proc state_transition*(
verify_block_signature(state.data, signedBlock):
# TODO after checking scaffolding, remove this
trace "in state_transition: processing block, signature passed",
signature = signedBlock.signature,
blockRoot = hash_tree_root(signedBlock.message)
trace "state_transition: processing block, signature passed",
signature = shortLog(signedBlock.signature),
blockRoot = shortLog(signedBlock.root)
if process_block(preset, state.data, signedBlock.message, flags, stateCache):
if skipStateRootValidation in flags or verifyStateRoot(state.data, signedBlock.message):
# State root is what it should be - we're done!

View File

@ -173,8 +173,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Justified with previous epoch",
current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint),
cat = "justification"
checkpoint = shortLog(state.current_justified_checkpoint)
let matching_target_attestations_current =
get_matching_target_attestations(state, current_epoch) # Current epoch
@ -187,8 +186,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Justified with current epoch",
current_epoch = current_epoch,
checkpoint = shortLog(state.current_justified_checkpoint),
cat = "justification"
checkpoint = shortLog(state.current_justified_checkpoint)
# Process finalizations
let bitfield = state.justification_bits
@ -201,8 +199,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Finalized with rule 234",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint),
cat = "finalization"
checkpoint = shortLog(state.finalized_checkpoint)
## The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as
## source
@ -212,8 +209,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Finalized with rule 23",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint),
cat = "finalization"
checkpoint = shortLog(state.finalized_checkpoint)
## The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as
## source
@ -223,8 +219,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Finalized with rule 123",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint),
cat = "finalization"
checkpoint = shortLog(state.finalized_checkpoint)
## The 1st/2nd most recent epochs are justified, the 1st using the 2nd as
## source
@ -234,8 +229,7 @@ proc process_justification_and_finalization*(state: var BeaconState,
debug "Finalized with rule 12",
current_epoch = current_epoch,
checkpoint = shortLog(state.finalized_checkpoint),
cat = "finalization"
checkpoint = shortLog(state.finalized_checkpoint)
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#helpers
func get_base_reward(state: BeaconState, index: ValidatorIndex,

View File

@ -4,7 +4,7 @@
import
typetraits, options,
stew/[bitops2, endians2, objects], serialization/testing/tracing,
../spec/[digest, datatypes], ./types, ./spec_types
../spec/[digest, datatypes], ./types, ./spec_types, ./merkleization
template raiseIncorrectSize(T: type) =
const typeName = name(T)
@ -267,5 +267,7 @@ func readSszValue*[T](input: openarray[byte], val: var T) {.raisesssz.} =
type(field),
input.toOpenArray(int(startOffset), int(endOffset - 1)))
when val is SignedBeaconBlock | TrustedSignedBeaconBlock:
val.root = hash_tree_root(val.message)
else:
unsupported T

View File

@ -18,16 +18,13 @@ proc dump*(dir: string, v: AttestationData, validator: ValidatorPubKey) =
logErrors:
SSZ.saveFile(dir / &"att-{v.slot}-{v.index}-{shortLog(validator)}.ssz", v)
proc dump*(dir: string, v: SignedBeaconBlock, root: Eth2Digest) =
proc dump*(dir: string, v: SignedBeaconBlock) =
logErrors:
SSZ.saveFile(dir / &"block-{v.message.slot}-{shortLog(root)}.ssz", v)
SSZ.saveFile(dir / &"block-{v.message.slot}-{shortLog(v.root)}.ssz", v)
proc dump*(dir: string, v: TrustedSignedBeaconBlock, root: Eth2Digest) =
proc dump*(dir: string, v: TrustedSignedBeaconBlock) =
logErrors:
SSZ.saveFile(dir / &"block-{v.message.slot}-{shortLog(root)}.ssz", v)
proc dump*(dir: string, v: SomeSignedBeaconBlock, blck: BlockRef) =
dump(dir, v, blck.root)
SSZ.saveFile(dir / &"block-{v.message.slot}-{shortLog(v.root)}.ssz", v)
proc dump*(dir: string, v: HashedBeaconState, blck: BlockRef) =
logErrors:

View File

@ -195,7 +195,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) =
rpcServer.rpc("get_v1_beacon_states_fork") do (stateId: string) -> Fork:
withStateForStateId(stateId):
return state.fork
rpcServer.rpc("get_v1_beacon_states_finality_checkpoints") do (
stateId: string) -> BeaconStatesFinalityCheckpointsTuple:
withStateForStateId(stateId):
@ -229,11 +229,11 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) =
seq[BeaconStatesCommitteesTuple]:
withStateForStateId(stateId):
var cache = StateCache() # TODO is this OK?
proc getCommittee(slot: Slot, index: CommitteeIndex): BeaconStatesCommitteesTuple =
let vals = get_beacon_committee(state, slot, index, cache).mapIt(it.uint64)
return (index: index.uint64, slot: slot.uint64, validators: vals)
proc forSlot(slot: Slot, res: var seq[BeaconStatesCommitteesTuple]) =
if index == 0: # TODO this means if the parameter is missing (its optional)
let committees_per_slot = get_committee_count_at_slot(state, slot)
@ -323,8 +323,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) =
if head.slot >= body.message.slot:
raise newException(CatchableError,
"Proposal is for a past slot: " & $body.message.slot)
if head == await proposeSignedBlock(node, head, AttachedValidator(),
body, hash_tree_root(body.message)):
if head == await proposeSignedBlock(node, head, AttachedValidator(), body):
raise newException(CatchableError, "Could not propose block")
return true

View File

@ -115,8 +115,7 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
lastSlot = shortLog(lastSlot),
scheduledSlot = shortLog(scheduledSlot),
beaconTime = shortLog(beaconTime),
portBN = vc.config.rpcPort,
cat = "scheduling"
portBN = vc.config.rpcPort
try:
# at the start of each epoch - request all validator duties
@ -141,9 +140,9 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
message: await vc.client.get_v1_validator_block(slot, vc.graffitiBytes, randao_reveal)
)
let blockRoot = hash_tree_root(newBlock.message)
newBlock.root = hash_tree_root(newBlock.message)
newBlock.signature = await validator.signBlockProposal(
vc.fork, vc.beaconGenesis.genesis_validators_root, slot, blockRoot)
vc.fork, vc.beaconGenesis.genesis_validators_root, slot, newBlock.root)
discard await vc.client.post_v1_validator_block(newBlock)
@ -181,8 +180,7 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
info "Slot end",
slot = shortLog(slot),
nextSlot = shortLog(nextSlot),
portBN = vc.config.rpcPort,
cat = "scheduling"
portBN = vc.config.rpcPort
when declared(GC_fullCollect):
# The slots in the validator client work as frames in a game: we want to make
@ -240,8 +238,7 @@ programMain:
info "Scheduling first slot action",
beaconTime = shortLog(vc.beaconClock.now()),
nextSlot = shortLog(nextSlot),
fromNow = shortLog(fromNow),
cat = "scheduling"
fromNow = shortLog(fromNow)
addTimer(fromNow) do (p: pointer) {.gcsafe.}:
asyncCheck vc.onSlotStart(curSlot, nextSlot)

View File

@ -145,8 +145,7 @@ proc createAndSendAttestation(node: BeaconNode,
info "Attestation sent",
attestation = shortLog(attestation),
validator = shortLog(validator),
indexInCommittee = indexInCommittee,
cat = "consensus"
indexInCommittee = indexInCommittee
type
ValidatorInfoForMakeBeaconBlockKind* = enum
@ -222,11 +221,10 @@ proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
proc proposeSignedBlock*(node: BeaconNode,
head: BlockRef,
validator: AttachedValidator,
newBlock: SignedBeaconBlock,
blockRoot: Eth2Digest): Future[BlockRef] {.async.} =
newBlock: SignedBeaconBlock): Future[BlockRef] {.async.} =
{.gcsafe.}: # TODO: fork choice and blockpool should sync via messages instead of callbacks
let newBlockRef = node.blockPool.addRawBlock(blockRoot, newBlock) do (validBlock: BlockRef):
let newBlockRef = node.blockPool.addRawBlock(newBlock) do (validBlock: BlockRef):
# Callback Add to fork choice
# node.attestationPool.addForkChoice_v2(validBlock)
discard "TODO: Deactivated"
@ -234,19 +232,17 @@ proc proposeSignedBlock*(node: BeaconNode,
if newBlockRef.isErr:
warn "Unable to add proposed block to block pool",
newBlock = shortLog(newBlock.message),
blockRoot = shortLog(blockRoot),
cat = "bug"
blockRoot = shortLog(newBlock.root)
return head
info "Block proposed",
blck = shortLog(newBlock.message),
blockRoot = shortLog(newBlockRef[].root),
validator = shortLog(validator),
cat = "consensus"
validator = shortLog(validator)
if node.config.dumpEnabled:
dump(node.config.dumpDirOutgoing, newBlock, newBlockRef[])
dump(node.config.dumpDirOutgoing, newBlock)
node.network.broadcast(node.topicBeaconBlocks, newBlock)
@ -267,8 +263,7 @@ proc proposeBlock(node: BeaconNode,
warn "Skipping proposal, have newer head already",
headSlot = shortLog(head.slot),
headBlockRoot = shortLog(head.root),
slot = shortLog(slot),
cat = "fastforward"
slot = shortLog(slot)
return head
let valInfo = ValidatorInfoForMakeBeaconBlock(kind: viValidator, validator: validator)
@ -280,17 +275,16 @@ proc proposeBlock(node: BeaconNode,
message: beaconBlockTuple.message.get()
)
let blockRoot = hash_tree_root(newBlock.message)
newBlock.root = hash_tree_root(newBlock.message)
newBlock.signature = await validator.signBlockProposal(
beaconBlockTuple.fork, beaconBlockTuple.genesis_validators_root, slot, blockRoot)
beaconBlockTuple.fork, beaconBlockTuple.genesis_validators_root, slot, newBlock.root)
return await node.proposeSignedBlock(head, validator, newBlock, blockRoot)
return await node.proposeSignedBlock(head, validator, newBlock)
proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
## Perform all attestations that the validators attached to this node should
## perform during the given slot
logScope: pcs = "on_attestation"
logScope: pcs = "handleAttestations"
if slot + SLOTS_PER_EPOCH < head.slot:
# The latest block we know about is a lot newer than the slot we're being
@ -316,8 +310,7 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
trace "Checking attestations",
attestationHeadRoot = shortLog(attestationHead.blck.root),
attestationSlot = shortLog(slot),
cat = "attestation"
attestationSlot = shortLog(slot)
# Collect data to send before node.stateCache grows stale
var attestations: seq[tuple[
@ -381,7 +374,6 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
slot = shortLog(slot),
proposer_index = proposer.get()[0],
proposer = shortLog(proposer.get()[1]),
cat = "consensus",
pcs = "wait_for_proposal"
return head
@ -455,8 +447,7 @@ proc handleValidatorDuties*(
notice "Catching up",
curSlot = shortLog(curSlot),
lastSlot = shortLog(lastSlot),
slot = shortLog(slot),
cat = "overload"
slot = shortLog(slot)
# For every slot we're catching up, we'll propose then send
# attestations - head should normally be advancing along the same branch

View File

@ -106,7 +106,7 @@ proc cmdBench(conf: DbConf) =
b.message.slot.compute_epoch_at_slot
withTimer(timers[if isEpoch: tApplyEpochBlock else: tApplyBlock]):
if not state_transition(defaultRuntimePreset, state[], b, {}, noRollback):
dump("./", b, hash_tree_root(b.message))
dump("./", b)
echo "State transition failed (!)"
quit 1
@ -137,7 +137,7 @@ proc cmdDumpBlock(conf: DbConf) =
try:
let root = Eth2Digest(data: hexToByteArray[32](blockRoot))
if (let blck = db.getBlock(root); blck.isSome):
dump("./", blck.get(), root)
dump("./", blck.get())
else:
echo "Couldn't load ", root
except CatchableError as e:

View File

@ -127,14 +127,14 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
let blockRoot = withTimerRet(timers[tHashBlock]):
hash_tree_root(newBlock.message)
newBlock.root = blockRoot
# Careful, state no longer valid after here because of the await..
newBlock.signature = withTimerRet(timers[tSignBlock]):
get_block_signature(
state.fork, state.genesis_validators_root, newBlock.message.slot,
blockRoot, privKey)
let added = blockPool.addRawBlock(blockRoot, newBlock) do (validBlock: BlockRef):
let added = blockPool.addRawBlock(newBlock) do (validBlock: BlockRef):
# Callback Add to fork choice
attPool.addForkChoice_v2(validBlock)
blck() = added[]

View File

@ -99,6 +99,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
flags = flags)
latest_block_root = withTimerRet(timers[tHashBlock]):
hash_tree_root(signedBlock.message)
signedBlock.root = latest_block_root
if attesterRatio > 0.0:
# attesterRatio is the fraction of attesters that actually do their

View File

@ -29,9 +29,10 @@ proc signMockBlockImpl(
signedBlock.message.body.randao_reveal = get_epoch_signature(
state.fork, state.genesis_validators_root, block_slot.compute_epoch_at_slot,
privkey)
signedBlock.root = hash_tree_root(signedBlock.message)
signedBlock.signature = get_block_signature(
state.fork, state.genesis_validators_root, block_slot,
hash_tree_root(signedBlock.message), privkey)
signedBlock.root, privkey)
proc signMockBlock*(state: BeaconState, signedBlock: var SignedBeaconBlock) =
signMockBlockImpl(state, signedBlock)

View File

@ -50,6 +50,7 @@ proc checkSSZ(T: type SignedBeaconBlock, dir: string, expectedHash: SSZHashTreeR
[hash_tree_root(deserialized.message),
hash_tree_root(deserialized.signature)]))
check deserialized.root == hash_tree_root(deserialized.message)
check SSZ.encode(deserialized[]) == encoded
check sszSize(deserialized[]) == encoded.len

View File

@ -166,8 +166,7 @@ suiteReport "Attestation pool processing" & preset():
var cache = StateCache()
let
b1 = addTestBlock(state.data, blockPool[].tail.root, cache)
b1Root = hash_tree_root(b1.message)
b1Add = blockpool[].addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b1Add = blockpool[].addRawBlock(b1) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -177,9 +176,8 @@ suiteReport "Attestation pool processing" & preset():
head == b1Add[]
let
b2 = addTestBlock(state.data, b1Root, cache)
b2Root = hash_tree_root(b2.message)
b2Add = blockpool[].addRawBlock(b2Root, b2) do (validBlock: BlockRef):
b2 = addTestBlock(state.data, b1.root, cache)
b2Add = blockpool[].addRawBlock(b2) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -192,8 +190,7 @@ suiteReport "Attestation pool processing" & preset():
var cache = StateCache()
let
b10 = makeTestBlock(state.data, blockPool[].tail.root, cache)
b10Root = hash_tree_root(b10.message)
b10Add = blockpool[].addRawBlock(b10Root, b10) do (validBlock: BlockRef):
b10Add = blockpool[].addRawBlock(b10) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -206,14 +203,13 @@ suiteReport "Attestation pool processing" & preset():
b11 = makeTestBlock(state.data, blockPool[].tail.root, cache,
graffiti = GraffitiBytes [1'u8, 0, 0, 0 ,0 ,0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
)
b11Root = hash_tree_root(b11.message)
b11Add = blockpool[].addRawBlock(b11Root, b11) do (validBlock: BlockRef):
b11Add = blockpool[].addRawBlock(b11) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
bc1 = get_beacon_committee(
state.data.data, state.data.data.slot, 1.CommitteeIndex, cache)
attestation0 = makeAttestation(state.data.data, b10Root, bc1[0], cache)
attestation0 = makeAttestation(state.data.data, b10.root, bc1[0], cache)
pool[].addAttestation(attestation0)
@ -224,13 +220,13 @@ suiteReport "Attestation pool processing" & preset():
head2 == b10Add[]
let
attestation1 = makeAttestation(state.data.data, b11Root, bc1[1], cache)
attestation2 = makeAttestation(state.data.data, b11Root, bc1[2], cache)
attestation1 = makeAttestation(state.data.data, b11.root, bc1[1], cache)
attestation2 = makeAttestation(state.data.data, b11.root, bc1[2], cache)
pool[].addAttestation(attestation1)
let head3 = pool[].selectHead()
# Warning - the tiebreak are incorrect and guaranteed consensus fork, it should be bigger
let smaller = if b10Root.data < b11Root.data: b10Add else: b11Add
let smaller = if b10.root.data < b11.root.data: b10Add else: b11Add
check:
# Ties broken lexicographically in spec -> ?
@ -251,8 +247,7 @@ suiteReport "Attestation pool processing" & preset():
var cache = StateCache()
let
b10 = makeTestBlock(state.data, blockPool[].tail.root, cache)
b10Root = hash_tree_root(b10.message)
b10Add = blockpool[].addRawBlock(b10Root, b10) do (validBlock: BlockRef):
b10Add = blockpool[].addRawBlock(b10) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -264,7 +259,7 @@ suiteReport "Attestation pool processing" & preset():
# -------------------------------------------------------------
# Add back the old block to ensure we have a duplicate error
let b10_clone = b10 # Assumes deep copy
let b10Add_clone = blockpool[].addRawBlock(b10Root, b10_clone) do (validBlock: BlockRef):
let b10Add_clone = blockpool[].addRawBlock(b10_clone) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
doAssert: b10Add_clone.error == Duplicate
@ -277,8 +272,7 @@ suiteReport "Attestation pool processing" & preset():
let
b10 = makeTestBlock(state.data, blockPool[].tail.root, cache)
b10Root = hash_tree_root(b10.message)
b10Add = blockpool[].addRawBlock(b10Root, b10) do (validBlock: BlockRef):
b10Add = blockpool[].addRawBlock(b10) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -294,7 +288,7 @@ suiteReport "Attestation pool processing" & preset():
# -------------------------------------------------------------
# Pass an epoch
var block_root = b10Root
var block_root = b10.root
var attestations: seq[Attestation]
@ -306,8 +300,8 @@ suiteReport "Attestation pool processing" & preset():
let block_ok = state_transition(defaultRuntimePreset, state.data, new_block, {skipBLSValidation}, noRollback)
doAssert: block_ok
block_root = hash_tree_root(new_block.message)
let blockRef = blockpool[].addRawBlock(block_root, new_block) do (validBlock: BlockRef):
block_root = new_block.root
let blockRef = blockpool[].addRawBlock(new_block) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
@ -344,10 +338,10 @@ suiteReport "Attestation pool processing" & preset():
doAssert: blockPool[].finalizedHead.slot != 0
pool[].pruneBefore(blockPool[].finalizedHead)
doAssert: b10Root notin pool.forkChoice_v2
doAssert: b10.root notin pool.forkChoice_v2
# Add back the old block to ensure we have a duplicate error
let b10Add_clone = blockpool[].addRawBlock(b10Root, b10_clone) do (validBlock: BlockRef):
let b10Add_clone = blockpool[].addRawBlock(b10_clone) do (validBlock: BlockRef):
# Callback Add to fork choice
pool[].addForkChoice_v2(validBlock)
doAssert: b10Add_clone.error == Duplicate

View File

@ -29,6 +29,12 @@ template wrappedTimedTest(name: string, body: untyped) =
body
wrappedTest()
func withDigest(blck: TrustedBeaconBlock): TrustedSignedBeaconBlock =
TrustedSignedBeaconBlock(
message: blck,
root: hash_tree_root(blck)
)
suiteReport "Beacon chain DB" & preset():
wrappedTimedTest "empty database" & preset():
var
@ -42,7 +48,7 @@ suiteReport "Beacon chain DB" & preset():
db = init(BeaconChainDB, kvStore MemStoreRef.init())
let
signedBlock = TrustedSignedBeaconBlock()
signedBlock = withDigest(TrustedBeaconBlock())
root = hash_tree_root(signedBlock.message)
db.putBlock(signedBlock)
@ -74,33 +80,31 @@ suiteReport "Beacon chain DB" & preset():
db = init(BeaconChainDB, kvStore MemStoreRef.init())
let
a0 = TrustedSignedBeaconBlock(message:
a0 = withDigest(
TrustedBeaconBlock(slot: GENESIS_SLOT + 0))
a0r = hash_tree_root(a0.message)
a1 = TrustedSignedBeaconBlock(message:
TrustedBeaconBlock(slot: GENESIS_SLOT + 1, parent_root: a0r))
a1r = hash_tree_root(a1.message)
a2 = TrustedSignedBeaconBlock(message:
TrustedBeaconBlock(slot: GENESIS_SLOT + 2, parent_root: a1r))
a1 = withDigest(
TrustedBeaconBlock(slot: GENESIS_SLOT + 1, parent_root: a0.root))
a2 = withDigest(
TrustedBeaconBlock(slot: GENESIS_SLOT + 2, parent_root: a1.root))
a2r = hash_tree_root(a2.message)
doAssert toSeq(db.getAncestors(a0r)) == []
doAssert toSeq(db.getAncestors(a2r)) == []
doAssert toSeq(db.getAncestors(a0.root)) == []
doAssert toSeq(db.getAncestors(a2.root)) == []
db.putBlock(a2)
doAssert toSeq(db.getAncestors(a0r)) == []
doAssert toSeq(db.getAncestors(a2r)) == [(a2r, a2)]
doAssert toSeq(db.getAncestors(a0.root)) == []
doAssert toSeq(db.getAncestors(a2.root)) == [a2]
db.putBlock(a1)
doAssert toSeq(db.getAncestors(a0r)) == []
doAssert toSeq(db.getAncestors(a2r)) == [(a2r, a2), (a1r, a1)]
doAssert toSeq(db.getAncestors(a0.root)) == []
doAssert toSeq(db.getAncestors(a2.root)) == [a2, a1]
db.putBlock(a0)
doAssert toSeq(db.getAncestors(a0r)) == [(a0r, a0)]
doAssert toSeq(db.getAncestors(a2r)) == [(a2r, a2), (a1r, a1), (a0r, a0)]
doAssert toSeq(db.getAncestors(a0.root)) == [a0]
doAssert toSeq(db.getAncestors(a2.root)) == [a2, a1, a0]
wrappedTimedTest "sanity check genesis roundtrip" & preset():
# This is a really dumb way of checking that we can roundtrip a genesis

View File

@ -110,9 +110,9 @@ suiteReport "Block pool processing" & preset():
timedTest "Simple block add&get" & preset():
let
b1Add = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b1Add = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
b1Get = pool.get(b1Root)
b1Get = pool.get(b1.root)
check:
b1Get.isSome()
@ -122,13 +122,13 @@ suiteReport "Block pool processing" & preset():
pool.heads[0].blck == b1Add[]
let
b2Add = pool.addRawBlock(b2Root, b2) do (validBlock: BlockRef):
b2Add = pool.addRawBlock(b2) do (validBlock: BlockRef):
discard
b2Get = pool.get(b2Root)
b2Get = pool.get(b2.root)
check:
b2Get.isSome()
b2Get.get().refs.root == b2Root
b2Get.get().refs.root == b2.root
b2Add[].root == b2Get.get().refs.root
pool.heads.len == 1
pool.heads[0].blck == b2Add[]
@ -138,9 +138,8 @@ suiteReport "Block pool processing" & preset():
process_slots(stateData.data, stateData.data.data.slot + 1)
let
b4 = addTestBlock(stateData.data, b2Root, cache)
b4Root = hash_tree_root(b4.message)
b4Add = pool.addRawBlock(b4Root, b4) do (validBlock: BlockRef):
b4 = addTestBlock(stateData.data, b2.root, cache)
b4Add = pool.addRawBlock(b4) do (validBlock: BlockRef):
discard
check:
@ -177,22 +176,22 @@ suiteReport "Block pool processing" & preset():
blocks[0..<2] == [BlockRef nil, nil] # block 3 is missing!
timedTest "Reverse order block add & get" & preset():
let missing = pool.addRawBlock(b2Root, b2) do (validBlock: BLockRef):
let missing = pool.addRawBlock(b2) do (validBlock: BLockRef):
discard
check: missing.error == MissingParent
check:
pool.get(b2Root).isNone() # Unresolved, shouldn't show up
FetchRecord(root: b1Root) in pool.checkMissing()
pool.get(b2.root).isNone() # Unresolved, shouldn't show up
FetchRecord(root: b1.root) in pool.checkMissing()
let status = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
let status = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
check: status.isOk
let
b1Get = pool.get(b1Root)
b2Get = pool.get(b2Root)
b1Get = pool.get(b1.root)
b2Get = pool.get(b2.root)
check:
b1Get.isSome()
@ -223,9 +222,9 @@ suiteReport "Block pool processing" & preset():
timedTest "Adding the same block twice returns a Duplicate error" & preset():
let
b10 = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b10 = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
b11 = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b11 = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
check:
@ -234,7 +233,7 @@ suiteReport "Block pool processing" & preset():
timedTest "updateHead updates head and headState" & preset():
let
b1Add = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b1Add = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
pool.updateHead(b1Add[])
@ -245,9 +244,9 @@ suiteReport "Block pool processing" & preset():
timedTest "updateStateData sanity" & preset():
let
b1Add = pool.addRawBlock(b1Root, b1) do (validBlock: BlockRef):
b1Add = pool.addRawBlock(b1) do (validBlock: BlockRef):
discard
b2Add = pool.addRawBlock(b2Root, b2) do (validBlock: BlockRef):
b2Add = pool.addRawBlock(b2) do (validBlock: BlockRef):
discard
bs1 = BlockSlot(blck: b1Add[], slot: b1.message.slot)
bs1_3 = b1Add[].atSlot(3.Slot)
@ -311,7 +310,7 @@ suiteReport "BlockPool finalization tests" & preset():
let lateBlock = makeTestBlock(tmpState[], pool.head.blck.root, cache)
block:
let status = pool.addRawBlock(hash_tree_root(blck.message), blck) do (validBlock: BlockRef):
let status = pool.addRawBlock(blck) do (validBlock: BlockRef):
discard
check: status.isOk()
@ -328,7 +327,7 @@ suiteReport "BlockPool finalization tests" & preset():
attestations = makeFullAttestations(
pool.headState.data.data, pool.head.blck.root,
pool.headState.data.data.slot, cache, {}))
let added = pool.addRawBlock(hash_tree_root(blck.message), blck) do (validBlock: BlockRef):
let added = pool.addRawBlock(blck) do (validBlock: BlockRef):
discard
check: added.isOk()
pool.updateHead(added[])
@ -341,7 +340,7 @@ suiteReport "BlockPool finalization tests" & preset():
block:
# The late block is a block whose parent was finalized long ago and thus
# is no longer a viable head candidate
let status = pool.addRawBlock(hash_tree_root(lateBlock.message), lateBlock) do (validBlock: BlockRef):
let status = pool.addRawBlock(lateBlock) do (validBlock: BlockRef):
discard
check: status.error == Unviable

View File

@ -36,7 +36,7 @@ suiteReport "Block processing" & preset():
timedTest "Passes from genesis state, empty block" & preset():
var
previous_block_root = hash_tree_root(genesisBlock.message)
previous_block_root = genesisBlock.root
cache = StateCache()
new_block = makeTestBlock(state[], previous_block_root, cache)
@ -65,7 +65,7 @@ suiteReport "Block processing" & preset():
check:
block_ok
previous_block_root = hash_tree_root(new_block.message)
previous_block_root = new_block.root
check:
state.data.slot == genesisState.data.slot + SLOTS_PER_EPOCH

View File

@ -73,13 +73,14 @@ proc makeInitialDeposits*(
func signBlock*(
fork: Fork, genesis_validators_root: Eth2Digest, blck: BeaconBlock,
privKey: ValidatorPrivKey, flags: UpdateFlags = {}): SignedBeaconBlock =
var root = hash_tree_root(blck)
SignedBeaconBlock(
message: blck,
root: root,
signature:
if skipBlsValidation notin flags:
get_block_signature(
fork, genesis_validators_root, blck.slot,
hash_tree_root(blck), privKey)
fork, genesis_validators_root, blck.slot, root, privKey)
else:
ValidatorSig()
)