clean up block creation
* consistently use state at new block slot to produce block * factor out signature funcs * fix missing block application test
This commit is contained in:
parent
ccace9a034
commit
689bcf71c4
|
@ -22,7 +22,8 @@
|
|||
|
||||
import
|
||||
options,
|
||||
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator],
|
||||
./spec/[beaconstate, datatypes, crypto, digest, helpers, validator,
|
||||
state_transition_block],
|
||||
./attestation_pool, ./beacon_node_types, ./ssz
|
||||
|
||||
# TODO gossipsub validation lives somewhere, maybe here
|
||||
|
@ -33,13 +34,6 @@ const
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/p2p-interface.md#configuration
|
||||
ATTESTATION_PROPAGATION_SLOT_RANGE = 32
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/validator/0_beacon-chain-validator.md#aggregation-selection
|
||||
func get_slot_signature(state: BeaconState, slot: Slot, privkey: ValidatorPrivKey):
|
||||
ValidatorSig =
|
||||
let domain =
|
||||
get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot))
|
||||
bls_sign(privkey, hash_tree_root(slot).data, domain)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#aggregation-selection
|
||||
func is_aggregator(state: BeaconState, slot: Slot, index: uint64,
|
||||
slot_signature: ValidatorSig): bool =
|
||||
|
@ -58,7 +52,7 @@ proc aggregate_attestations*(
|
|||
|
||||
let
|
||||
slot = state.slot - 2
|
||||
slot_signature = get_slot_signature(state, slot, privkey)
|
||||
slot_signature = get_slot_signature(state.fork, slot, privkey)
|
||||
|
||||
if slot < 0:
|
||||
return none(AggregateAndProof)
|
||||
|
|
|
@ -266,10 +266,12 @@ proc add*(pool: var AttestationPool, attestation: Attestation) =
|
|||
pool.addResolved(blck, attestation)
|
||||
|
||||
proc getAttestationsForBlock*(
|
||||
pool: AttestationPool, state: BeaconState,
|
||||
newBlockSlot: Slot): seq[Attestation] =
|
||||
pool: AttestationPool, state: BeaconState): seq[Attestation] =
|
||||
## Retrieve attestations that may be added to a new block at the slot of the
|
||||
## given state
|
||||
logScope: pcs = "retrieve_attestation"
|
||||
|
||||
let newBlockSlot = state.slot
|
||||
if newBlockSlot < (GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY):
|
||||
debug "Too early for attestations",
|
||||
newBlockSlot = shortLog(newBlockSlot),
|
||||
|
@ -327,8 +329,7 @@ proc getAttestationsForBlock*(
|
|||
# TODO we're checking signatures here every time which is very slow - this
|
||||
# is needed because validate does nothing for now and we don't want
|
||||
# to include a broken attestation
|
||||
if not check_attestation(
|
||||
state, attestation, {nextSlot}, cache):
|
||||
if not check_attestation(state, attestation, {}, cache):
|
||||
continue
|
||||
|
||||
for v in a.validations[1..^1]:
|
||||
|
|
|
@ -10,7 +10,8 @@ import
|
|||
eth/p2p/enode, eth/[keys, async_utils], eth/p2p/discoveryv5/enr,
|
||||
|
||||
# Local modules
|
||||
spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network],
|
||||
spec/[datatypes, digest, crypto, beaconstate, helpers, validator, network,
|
||||
state_transition_block],
|
||||
conf, time, state_transition, beacon_chain_db, validator_pool, extras,
|
||||
attestation_pool, block_pool, eth2_network, eth2_discovery,
|
||||
beacon_node_types, mainchain_monitor, version, ssz, ssz/dynamic_navigator,
|
||||
|
@ -381,8 +382,8 @@ proc proposeBlock(node: BeaconNode,
|
|||
cat = "fastforward"
|
||||
return head
|
||||
|
||||
# Advance state to the slot immediately preceding the one we're creating a
|
||||
# block for - potentially we will be processing empty slots along the way.
|
||||
# Advance state to the slot that we're proposing for - this is the equivalent
|
||||
# of running `process_slots` up to the slot of the new block.
|
||||
let (nroot, nblck) = node.blockPool.withState(
|
||||
node.blockPool.tmpState, head.atSlot(slot)):
|
||||
let (eth1data, deposits) =
|
||||
|
@ -394,45 +395,27 @@ proc proposeBlock(node: BeaconNode,
|
|||
(node.mainchainMonitor.eth1Data,
|
||||
node.mainchainMonitor.getPendingDeposits())
|
||||
|
||||
# To create a block, we'll first apply a partial block to the state, skipping
|
||||
# some validations.
|
||||
let
|
||||
fork = state.fork
|
||||
blockBody = BeaconBlockBody(
|
||||
randao_reveal: validator.genRandaoReveal(fork, slot),
|
||||
eth1_data: eth1data,
|
||||
attestations:
|
||||
node.attestationPool.getAttestationsForBlock(state, slot),
|
||||
deposits: deposits)
|
||||
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
let proposer_index = get_beacon_proposer_index(state, cache)
|
||||
if proposer_index.isNone:
|
||||
doAssert false, "proposeBlock: missing proposer index"
|
||||
let message = makeBeaconBlock(
|
||||
state,
|
||||
head.root,
|
||||
validator.genRandaoReveal(state.fork, slot),
|
||||
eth1data,
|
||||
Eth2Digest(),
|
||||
node.attestationPool.getAttestationsForBlock(state),
|
||||
deposits)
|
||||
|
||||
if not message.isSome():
|
||||
return head # already logged elsewhere!
|
||||
var
|
||||
newBlock = SignedBeaconBlock(
|
||||
message: BeaconBlock(
|
||||
slot: slot,
|
||||
proposer_index: proposer_index.get.uint64,
|
||||
parent_root: head.root,
|
||||
body: blockBody))
|
||||
tmpState = hashedState
|
||||
discard state_transition(tmpState, newBlock, {skipStateRootValidation})
|
||||
# TODO only enable in fast-fail debugging situations
|
||||
# otherwise, bad attestations can bring down network
|
||||
# doAssert ok # TODO: err, could this fail somehow?
|
||||
|
||||
newBlock.message.state_root = tmpState.root
|
||||
message: message.get()
|
||||
)
|
||||
|
||||
let blockRoot = hash_tree_root(newBlock.message)
|
||||
|
||||
# Careful, state no longer valid after here..
|
||||
# We use the fork from the pre-newBlock state which should be fine because
|
||||
# fork carries two epochs, so even if it's a fork block, the right thing
|
||||
# will happen here
|
||||
# Careful, state no longer valid after here because of the await..
|
||||
newBlock.signature =
|
||||
await validator.signBlockProposal(fork, slot, blockRoot)
|
||||
await validator.signBlockProposal(state.fork, slot, blockRoot)
|
||||
|
||||
(blockRoot, newBlock)
|
||||
|
||||
|
@ -454,10 +437,12 @@ proc proposeBlock(node: BeaconNode,
|
|||
SSZ.saveFile(
|
||||
node.config.dumpDir / "block-" & $newBlock.message.slot & "-" &
|
||||
shortLog(newBlockRef.root) & ".ssz", newBlock)
|
||||
SSZ.saveFile(
|
||||
node.config.dumpDir / "state-" & $tmpState.data.slot & "-" &
|
||||
shortLog(newBlockRef.root) & "-" & shortLog(tmpState.root) & ".ssz",
|
||||
tmpState.data)
|
||||
node.blockPool.withState(
|
||||
node.blockPool.tmpState, newBlockRef.atSlot(newBlockRef.slot)):
|
||||
SSZ.saveFile(
|
||||
node.config.dumpDir / "state-" & $state.slot & "-" &
|
||||
shortLog(newBlockRef.root) & "-" & shortLog(root()) & ".ssz",
|
||||
state())
|
||||
|
||||
node.network.broadcast(topicBeaconBlocks, newBlock)
|
||||
|
||||
|
|
|
@ -16,16 +16,8 @@
|
|||
# improved coverage, and to avoid unnecessary validation when replaying trusted
|
||||
# (previously validated) blocks.
|
||||
|
||||
|
||||
type
|
||||
UpdateFlag* = enum
|
||||
nextSlot ##\
|
||||
## Perform the operation as if the next slot was being processed - this is
|
||||
## useful when using the state to verify data that will go in the next slot,
|
||||
## for example when proposing
|
||||
## TODO need to be careful here, easy to assume that slot number change is
|
||||
## enough, vs advancing the state - however, making a full state copy
|
||||
## is expensive also :/
|
||||
skipMerkleValidation ##\
|
||||
## When processing deposits, skip verifying the Merkle proof trees of each
|
||||
## deposit. This is a holdover from both interop issues with the malformed
|
||||
|
|
|
@ -444,11 +444,9 @@ proc check_attestation*(
|
|||
## at the current slot. When acting as a proposer, the same rules need to
|
||||
## be followed!
|
||||
|
||||
let stateSlot =
|
||||
if nextSlot in flags: state.slot + 1
|
||||
else: state.slot
|
||||
|
||||
let data = attestation.data
|
||||
let
|
||||
stateSlot = state.slot
|
||||
data = attestation.data
|
||||
|
||||
trace "process_attestation: beginning",
|
||||
attestation=attestation
|
||||
|
|
|
@ -592,6 +592,7 @@ func shortLog*(e: Epoch): uint64 =
|
|||
func shortLog*(v: BeaconBlock): auto =
|
||||
(
|
||||
slot: shortLog(v.slot),
|
||||
proposer_index: v.proposer_index,
|
||||
parent_root: shortLog(v.parent_root),
|
||||
state_root: shortLog(v.state_root),
|
||||
proposer_slashings_len: v.body.proposer_slashings.len(),
|
||||
|
|
|
@ -436,3 +436,87 @@ proc process_block*(
|
|||
return false
|
||||
|
||||
true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md
|
||||
# TODO There's more to do here - the spec has helpers that deal set up some of
|
||||
# the fields in here!
|
||||
proc makeBeaconBlock*(
|
||||
state: BeaconState,
|
||||
parent_root: Eth2Digest,
|
||||
randao_reveal: ValidatorSig,
|
||||
eth1_data: Eth1Data,
|
||||
graffiti: Eth2Digest,
|
||||
attestations: seq[Attestation],
|
||||
deposits: seq[Deposit]): Option[BeaconBlock] =
|
||||
## Create a block for the given state. The last block applied to it must be
|
||||
## the one identified by parent_root and process_slots must be called up to
|
||||
## the slot for which a block is to be created.
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
let proposer_index = get_beacon_proposer_index(state, cache)
|
||||
doAssert proposer_index.isSome, "Unable to get proposer index when proposing!"
|
||||
|
||||
# To create a block, we'll first apply a partial block to the state, skipping
|
||||
# some validations.
|
||||
|
||||
var blck = BeaconBlock(
|
||||
slot: state.slot,
|
||||
proposer_index: proposer_index.get().uint64,
|
||||
parent_root: parent_root,
|
||||
body: BeaconBlockBody(
|
||||
randao_reveal: randao_reveal,
|
||||
eth1_data: eth1data,
|
||||
graffiti: graffiti,
|
||||
attestations: attestations,
|
||||
deposits: deposits)
|
||||
)
|
||||
|
||||
var tmpState = state
|
||||
let ok = process_block(tmpState, blck, {skipBlsValidation}, cache)
|
||||
|
||||
if not ok:
|
||||
warn "Unable to apply new block to state", blck = shortLog(blck)
|
||||
return
|
||||
|
||||
blck.state_root = hash_tree_root(tmpState)
|
||||
|
||||
some(blck)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md
|
||||
func get_slot_signature*(
|
||||
fork: Fork, slot: Slot, privkey: ValidatorPrivKey): ValidatorSig =
|
||||
let
|
||||
domain =
|
||||
get_domain(fork, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot))
|
||||
signing_root = compute_signing_root(slot, domain)
|
||||
|
||||
blsSign(privKey, signing_root.data)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md
|
||||
func get_epoch_signature*(
|
||||
fork: Fork, slot: Slot, privkey: ValidatorPrivKey): ValidatorSig =
|
||||
let
|
||||
domain =
|
||||
get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot))
|
||||
signing_root = compute_signing_root(compute_epoch_at_slot(slot), domain)
|
||||
|
||||
blsSign(privKey, signing_root.data)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md
|
||||
func get_block_signature*(
|
||||
fork: Fork, slot: Slot, root: Eth2Digest, privkey: ValidatorPrivKey): ValidatorSig =
|
||||
let
|
||||
domain =
|
||||
get_domain(fork, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(slot))
|
||||
signing_root = compute_signing_root(root, domain)
|
||||
|
||||
blsSign(privKey, signing_root.data)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.0/specs/phase0/validator.md
|
||||
func get_attestation_signature*(
|
||||
fork: Fork, attestation: AttestationData, privkey: ValidatorPrivKey): ValidatorSig =
|
||||
let
|
||||
attestationRoot = hash_tree_root(attestation)
|
||||
domain = get_domain(fork, DOMAIN_BEACON_ATTESTER, attestation.target.epoch)
|
||||
signing_root = compute_signing_root(attestationRoot, domain)
|
||||
|
||||
blsSign(privKey, signing_root.data)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import
|
||||
tables,
|
||||
chronos, chronicles,
|
||||
spec/[datatypes, crypto, digest, helpers], ssz,
|
||||
spec/[datatypes, crypto, digest, state_transition_block], ssz,
|
||||
beacon_node_types
|
||||
|
||||
func init*(T: type ValidatorPool): T =
|
||||
|
@ -29,18 +29,12 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork, slot: Slot,
|
|||
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
|
||||
|
||||
if v.kind == inProcess:
|
||||
# TODO state might become invalid after any async calls - it's fragile to
|
||||
# care about this in here
|
||||
let
|
||||
domain =
|
||||
get_domain(fork, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(slot))
|
||||
# TODO this is an ugly hack to fake a delay and subsequent async reordering
|
||||
# for the purpose of testing the external validator delay - to be
|
||||
# replaced by something more sensible
|
||||
await sleepAsync(chronos.milliseconds(1))
|
||||
|
||||
let signing_root = compute_signing_root(blockRoot, domain)
|
||||
result = blsSign(v.privKey, signing_root.data)
|
||||
result = get_block_signature(fork, slot, blockRoot, v.privKey)
|
||||
else:
|
||||
error "Unimplemented"
|
||||
quit 1
|
||||
|
@ -49,17 +43,12 @@ proc signAttestation*(v: AttachedValidator,
|
|||
attestation: AttestationData,
|
||||
fork: Fork): Future[ValidatorSig] {.async.} =
|
||||
if v.kind == inProcess:
|
||||
let
|
||||
attestationRoot = hash_tree_root(attestation)
|
||||
domain = get_domain(fork, DOMAIN_BEACON_ATTESTER, attestation.target.epoch)
|
||||
|
||||
# TODO this is an ugly hack to fake a delay and subsequent async reordering
|
||||
# for the purpose of testing the external validator delay - to be
|
||||
# replaced by something more sensible
|
||||
await sleepAsync(chronos.milliseconds(1))
|
||||
|
||||
let signing_root = compute_signing_root(attestationRoot, domain)
|
||||
result = blsSign(v.privKey, signing_root.data)
|
||||
result = get_attestation_signature(fork, attestation, v.privKey)
|
||||
else:
|
||||
error "Unimplemented"
|
||||
quit 1
|
||||
|
@ -67,11 +56,7 @@ proc signAttestation*(v: AttachedValidator,
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/validator.md#randao-reveal
|
||||
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork, slot: Slot):
|
||||
ValidatorSig =
|
||||
let
|
||||
domain = get_domain(fork, DOMAIN_RANDAO, compute_epoch_at_slot(slot))
|
||||
signing_root = compute_signing_root(compute_epoch_at_slot(slot).uint64, domain)
|
||||
|
||||
bls_sign(k, signing_root.data)
|
||||
get_epoch_signature(fork, slot, k)
|
||||
|
||||
func genRandaoReveal*(v: AttachedValidator, fork: Fork, slot: Slot):
|
||||
ValidatorSig =
|
||||
|
|
|
@ -121,8 +121,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
|
|||
|
||||
let
|
||||
attestations_idx = state.slot
|
||||
body = BeaconBlockBody(
|
||||
attestations: attestations.getOrDefault(attestations_idx))
|
||||
blockAttestations = attestations.getOrDefault(attestations_idx)
|
||||
|
||||
attestations.del attestations_idx
|
||||
doAssert len(attestations) <=
|
||||
|
@ -134,7 +133,8 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
|
|||
else: tBlock
|
||||
|
||||
withTimer(timers[t]):
|
||||
signedBlock = addBlock(state, latest_block_root, body, flags)
|
||||
signedBlock = addTestBlock(
|
||||
state, latest_block_root, attestations = blockAttestations, flags = flags)
|
||||
latest_block_root = withTimerRet(timers[tHashBlock]):
|
||||
hash_tree_root(signedBlock.message)
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ import
|
|||
# Standard library
|
||||
sets,
|
||||
# Specs
|
||||
../../beacon_chain/spec/[datatypes, beaconstate, helpers, validator, crypto],
|
||||
../../beacon_chain/spec/[datatypes, beaconstate, helpers, validator, crypto,
|
||||
state_transition_block],
|
||||
# Internals
|
||||
../../beacon_chain/[ssz, extras, state_transition],
|
||||
# Mocking procs
|
||||
|
@ -53,20 +54,6 @@ proc mockAttestationData(
|
|||
epoch: target_epoch, root: epoch_boundary_root
|
||||
)
|
||||
|
||||
proc get_attestation_signature(
|
||||
state: BeaconState,
|
||||
attestation_data: AttestationData,
|
||||
privkey: ValidatorPrivKey
|
||||
): ValidatorSig =
|
||||
let domain = get_domain(
|
||||
state = state,
|
||||
domain_type = DOMAIN_BEACON_ATTESTER,
|
||||
message_epoch = attestation_data.target.epoch
|
||||
)
|
||||
let signing_root = compute_signing_root(attestation_data, domain)
|
||||
|
||||
return blsSign(privkey, signing_root.data)
|
||||
|
||||
proc signMockAttestation*(state: BeaconState, attestation: var Attestation) =
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
let participants = get_attesting_indices(
|
||||
|
@ -79,7 +66,7 @@ proc signMockAttestation*(state: BeaconState, attestation: var Attestation) =
|
|||
var first_iter = true # Can't do while loop on hashset
|
||||
for validator_index in participants:
|
||||
let sig = get_attestation_signature(
|
||||
state, attestation.data, MockPrivKeys[validator_index]
|
||||
state.fork, attestation.data, MockPrivKeys[validator_index]
|
||||
)
|
||||
if first_iter:
|
||||
attestation.signature = sig
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import
|
||||
options,
|
||||
# Specs
|
||||
../../beacon_chain/spec/[datatypes, crypto, helpers, validator],
|
||||
../../beacon_chain/spec/[datatypes, crypto, validator, state_transition_block],
|
||||
# Internals
|
||||
../../beacon_chain/[ssz, extras, state_transition],
|
||||
# Mock helpers
|
||||
|
@ -27,27 +27,10 @@ proc signMockBlockImpl(
|
|||
|
||||
let privkey = MockPrivKeys[proposer_index]
|
||||
|
||||
|
||||
block:
|
||||
let domain = get_domain(
|
||||
state,
|
||||
DOMAIN_RANDAO,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
let signing_root = compute_signing_root(
|
||||
block_slot.compute_epoch_at_slot(),
|
||||
domain
|
||||
)
|
||||
signedBlock.message.body.randao_reveal = bls_sign(privkey, signing_root.data)
|
||||
|
||||
block:
|
||||
let domain = get_domain(
|
||||
state,
|
||||
DOMAIN_BEACON_PROPOSER,
|
||||
message_epoch = block_slot.compute_epoch_at_slot(),
|
||||
)
|
||||
let signing_root = compute_signing_root(signedBlock.message, domain)
|
||||
signedBlock.signature = bls_sign(privkey, signing_root.data)
|
||||
signedBlock.message.body.randao_reveal = get_epoch_signature(
|
||||
state.fork, block_slot, privkey)
|
||||
signedBlock.signature = get_block_signature(
|
||||
state.fork, block_slot, hash_tree_root(signedBlock.message), privkey)
|
||||
|
||||
proc signMockBlock*(
|
||||
state: BeaconState,
|
||||
|
|
|
@ -35,17 +35,16 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
var cache = get_empty_per_epoch_cache()
|
||||
let
|
||||
# Create an attestation for slot 1!
|
||||
beacon_committee = get_beacon_committee(state.data.data,
|
||||
state.data.data.slot, 0, cache)
|
||||
beacon_committee = get_beacon_committee(
|
||||
state.data.data, state.data.data.slot, 0, cache)
|
||||
attestation = makeAttestation(
|
||||
state.data.data, state.blck.root, beacon_committee[0], cache)
|
||||
|
||||
pool.add(attestation)
|
||||
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot) # minus 1?
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1)
|
||||
|
||||
let attestations = pool.getAttestationsForBlock(
|
||||
state.data.data, state.data.data.slot + 1)
|
||||
let attestations = pool.getAttestationsForBlock(state.data.data)
|
||||
|
||||
check:
|
||||
attestations.len == 1
|
||||
|
@ -54,8 +53,8 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
var cache = get_empty_per_epoch_cache()
|
||||
let
|
||||
# Create an attestation for slot 1!
|
||||
bc0 = get_beacon_committee(state.data.data,
|
||||
state.data.data.slot, 0, cache)
|
||||
bc0 = get_beacon_committee(
|
||||
state.data.data, state.data.data.slot, 0, cache)
|
||||
attestation0 = makeAttestation(
|
||||
state.data.data, state.blck.root, bc0[0], cache)
|
||||
|
||||
|
@ -71,10 +70,9 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
pool.add(attestation1)
|
||||
pool.add(attestation0)
|
||||
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot) # minus 1?
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1)
|
||||
|
||||
let attestations = pool.getAttestationsForBlock(
|
||||
state.data.data, state.data.data.slot + 1)
|
||||
let attestations = pool.getAttestationsForBlock(state.data.data)
|
||||
|
||||
check:
|
||||
attestations.len == 1
|
||||
|
@ -83,8 +81,8 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
var cache = get_empty_per_epoch_cache()
|
||||
let
|
||||
# Create an attestation for slot 1!
|
||||
bc0 = get_beacon_committee(state.data.data,
|
||||
state.data.data.slot, 0, cache)
|
||||
bc0 = get_beacon_committee(
|
||||
state.data.data, state.data.data.slot, 0, cache)
|
||||
attestation0 = makeAttestation(
|
||||
state.data.data, state.blck.root, bc0[0], cache)
|
||||
attestation1 = makeAttestation(
|
||||
|
@ -93,10 +91,9 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
pool.add(attestation0)
|
||||
pool.add(attestation1)
|
||||
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot) # minus 1?
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1)
|
||||
|
||||
let attestations = pool.getAttestationsForBlock(
|
||||
state.data.data, state.data.data.slot + 1)
|
||||
let attestations = pool.getAttestationsForBlock(state.data.data)
|
||||
|
||||
check:
|
||||
attestations.len == 1
|
||||
|
@ -106,8 +103,8 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
|
||||
var
|
||||
# Create an attestation for slot 1!
|
||||
bc0 = get_beacon_committee(state.data.data,
|
||||
state.data.data.slot, 0, cache)
|
||||
bc0 = get_beacon_committee(
|
||||
state.data.data, state.data.data.slot, 0, cache)
|
||||
attestation0 = makeAttestation(
|
||||
state.data.data, state.blck.root, bc0[0], cache)
|
||||
attestation1 = makeAttestation(
|
||||
|
@ -118,10 +115,9 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
pool.add(attestation0)
|
||||
pool.add(attestation1)
|
||||
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot) # minus 1?
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1)
|
||||
|
||||
let attestations = pool.getAttestationsForBlock(
|
||||
state.data.data, state.data.data.slot + 1)
|
||||
let attestations = pool.getAttestationsForBlock(state.data.data)
|
||||
|
||||
check:
|
||||
attestations.len == 1
|
||||
|
@ -142,17 +138,16 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
pool.add(attestation1)
|
||||
pool.add(attestation0)
|
||||
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot) # minus 1?
|
||||
process_slots(state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1)
|
||||
|
||||
let attestations = pool.getAttestationsForBlock(
|
||||
state.data.data, state.data.data.slot + 1)
|
||||
let attestations = pool.getAttestationsForBlock(state.data.data)
|
||||
|
||||
check:
|
||||
attestations.len == 1
|
||||
|
||||
timedTest "Fork choice returns latest block with no attestations":
|
||||
let
|
||||
b1 = addBlock(state.data.data, blockPool.tail.root, BeaconBlockBody())
|
||||
b1 = addTestBlock(state.data.data, blockPool.tail.root)
|
||||
b1Root = hash_tree_root(b1.message)
|
||||
b1Add = blockPool.add(b1Root, b1)
|
||||
head = pool.selectHead()
|
||||
|
@ -161,7 +156,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
head == b1Add
|
||||
|
||||
let
|
||||
b2 = addBlock(state.data.data, b1Root, BeaconBlockBody())
|
||||
b2 = addTestBlock(state.data.data, b1Root)
|
||||
b2Root = hash_tree_root(b2.message)
|
||||
b2Add = blockPool.add(b2Root, b2)
|
||||
head2 = pool.selectHead()
|
||||
|
@ -172,7 +167,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
timedTest "Fork choice returns block with attestation":
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
let
|
||||
b10 = makeBlock(state.data.data, blockPool.tail.root, BeaconBlockBody())
|
||||
b10 = makeTestBlock(state.data.data, blockPool.tail.root)
|
||||
b10Root = hash_tree_root(b10.message)
|
||||
b10Add = blockPool.add(b10Root, b10)
|
||||
head = pool.selectHead()
|
||||
|
@ -181,16 +176,15 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
head == b10Add
|
||||
|
||||
let
|
||||
b11 = makeBlock(state.data.data, blockPool.tail.root, BeaconBlockBody(
|
||||
graffiti: Eth2Digest(data: [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])
|
||||
))
|
||||
b11 = makeTestBlock(state.data.data, blockPool.tail.root,
|
||||
graffiti = Eth2Digest(data: [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.add(b11Root, b11)
|
||||
|
||||
bc1 = get_beacon_committee(state.data.data,
|
||||
state.data.data.slot, 1, cache)
|
||||
attestation0 = makeAttestation(
|
||||
state.data.data, b10Root, bc1[0], cache)
|
||||
bc1 = get_beacon_committee(
|
||||
state.data.data, state.data.data.slot, 1, cache)
|
||||
attestation0 = makeAttestation(state.data.data, b10Root, bc1[0], cache)
|
||||
|
||||
pool.add(attestation0)
|
||||
|
||||
|
@ -201,10 +195,8 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
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, b11Root, bc1[1], cache)
|
||||
attestation2 = makeAttestation(state.data.data, b11Root, bc1[2], cache)
|
||||
pool.add(attestation1)
|
||||
|
||||
let head3 = pool.selectHead()
|
||||
|
|
|
@ -89,9 +89,9 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
pool = BlockPool.init(db)
|
||||
state = pool.loadTailState().data.data
|
||||
b1 = addBlock(state, pool.tail.root, BeaconBlockBody())
|
||||
b1 = addTestBlock(state, pool.tail.root)
|
||||
b1Root = hash_tree_root(b1.message)
|
||||
b2 = addBlock(state, b1Root, BeaconBlockBody())
|
||||
b2 = addTestBlock(state, b1Root)
|
||||
b2Root {.used.} = hash_tree_root(b2.message)
|
||||
|
||||
timedTest "getRef returns nil for missing blocks":
|
||||
|
@ -246,8 +246,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
block:
|
||||
# Create a fork that will not be taken
|
||||
var
|
||||
blck = makeBlock(pool.headState.data.data, pool.head.blck.root,
|
||||
BeaconBlockBody())
|
||||
blck = makeTestBlock(pool.headState.data.data, pool.head.blck.root)
|
||||
discard pool.add(hash_tree_root(blck.message), blck)
|
||||
|
||||
for i in 0 ..< (SLOTS_PER_EPOCH * 6):
|
||||
|
@ -258,11 +257,11 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
|||
pool.heads.len == 2
|
||||
var
|
||||
cache = get_empty_per_epoch_cache()
|
||||
blck = makeBlock(pool.headState.data.data, pool.head.blck.root,
|
||||
BeaconBlockBody(
|
||||
attestations: makeFullAttestations(
|
||||
pool.headState.data.data, pool.head.blck.root,
|
||||
pool.headState.data.data.slot, cache, {})))
|
||||
blck = makeTestBlock(
|
||||
pool.headState.data.data, pool.head.blck.root,
|
||||
attestations = makeFullAttestations(
|
||||
pool.headState.data.data, pool.head.blck.root,
|
||||
pool.headState.data.data.slot, cache, {}))
|
||||
let added = pool.add(hash_tree_root(blck.message), blck)
|
||||
pool.updateHead(added)
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ suiteReport "Block processing" & preset():
|
|||
var
|
||||
state = genesisState
|
||||
previous_block_root = hash_tree_root(genesisBlock.message)
|
||||
new_block = makeBlock(state, previous_block_root, BeaconBlockBody())
|
||||
new_block = makeTestBlock(state, previous_block_root)
|
||||
|
||||
let block_ok = state_transition(state, new_block, {})
|
||||
|
||||
|
@ -62,7 +62,7 @@ suiteReport "Block processing" & preset():
|
|||
previous_block_root = genesisRoot
|
||||
|
||||
for i in 1..SLOTS_PER_EPOCH.int:
|
||||
var new_block = makeBlock(state, previous_block_root, BeaconBlockBody())
|
||||
let new_block = makeTestBlock(state, previous_block_root)
|
||||
|
||||
let block_ok = state_transition(state, new_block, {})
|
||||
|
||||
|
@ -95,9 +95,9 @@ suiteReport "Block processing" & preset():
|
|||
process_slots(state, GENESIS_SLOT + MIN_ATTESTATION_INCLUSION_DELAY + 1)
|
||||
|
||||
let
|
||||
new_block = makeBlock(state, previous_block_root, BeaconBlockBody(
|
||||
attestations: @[attestation]
|
||||
))
|
||||
new_block = makeTestBlock(state, previous_block_root,
|
||||
attestations = @[attestation]
|
||||
)
|
||||
discard state_transition(state, new_block, {})
|
||||
|
||||
check:
|
||||
|
|
|
@ -11,7 +11,7 @@ import
|
|||
../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, state_transition,
|
||||
validator_pool],
|
||||
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest,
|
||||
helpers, validator]
|
||||
helpers, validator, state_transition_block]
|
||||
|
||||
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
||||
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
||||
|
@ -62,81 +62,70 @@ func makeInitialDeposits*(
|
|||
for i in 0..<n.int:
|
||||
result.add makeDeposit(i, flags)
|
||||
|
||||
proc addBlock*(
|
||||
state: var BeaconState, previous_block_root: Eth2Digest,
|
||||
body: BeaconBlockBody, flags: UpdateFlags = {}): SignedBeaconBlock =
|
||||
proc addTestBlock*(
|
||||
state: var BeaconState,
|
||||
parent_root: Eth2Digest,
|
||||
eth1_data = Eth1Data(),
|
||||
attestations = newSeq[Attestation](),
|
||||
deposits = newSeq[Deposit](),
|
||||
graffiti = Eth2Digest(),
|
||||
flags: set[UpdateFlag] = {}): SignedBeaconBlock =
|
||||
# Create and add a block to state - state will advance by one slot!
|
||||
# This is the equivalent of running
|
||||
# updateState(state, prev_block, makeBlock(...), {skipBlsValidation})
|
||||
# but avoids some slow block copies
|
||||
# FIXME update comment - updateState no longer exists, could be `state_transition`
|
||||
# but different number of parameters
|
||||
|
||||
state.slot += 1
|
||||
process_slots(state, state.slot + 1)
|
||||
|
||||
var cache = get_empty_per_epoch_cache()
|
||||
let proposer_index = get_beacon_proposer_index(state, cache)
|
||||
state.slot -= 1
|
||||
|
||||
let
|
||||
# Index from the new state, but registry from the old state.. hmm...
|
||||
# In tests, let this throw
|
||||
proposer = state.validators[proposer_index.get]
|
||||
privKey = hackPrivKey(proposer)
|
||||
randao_reveal =
|
||||
if skipBlsValidation notin flags:
|
||||
privKey.genRandaoReveal(state.fork, state.slot)
|
||||
else:
|
||||
ValidatorSig()
|
||||
|
||||
# TODO ugly hack; API needs rethinking
|
||||
var new_body = body
|
||||
if skipBlsValidation notin flags:
|
||||
new_body.randao_reveal = privKey.genRandaoReveal(state.fork, state.slot + 1)
|
||||
let
|
||||
message = makeBeaconBlock(
|
||||
state,
|
||||
parent_root,
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
attestations,
|
||||
deposits)
|
||||
|
||||
new_body.eth1_data = Eth1Data()
|
||||
doAssert message.isSome(), "Should have created a valid block!"
|
||||
|
||||
var
|
||||
# In order to reuse the state transition function, we first create a dummy
|
||||
# block that has some fields set, and use that to generate the state as it
|
||||
# would look with the new block applied.
|
||||
new_block = SignedBeaconBlock(
|
||||
message: BeaconBlock(
|
||||
slot: state.slot + 1,
|
||||
proposer_index: proposer_index.get.uint64,
|
||||
parent_root: previous_block_root,
|
||||
state_root: Eth2Digest(), # we need the new state first
|
||||
body: new_body
|
||||
)
|
||||
message: message.get()
|
||||
)
|
||||
|
||||
let block_ok = state_transition(state, new_block, {skipBlsValidation, skipStateRootValidation})
|
||||
doAssert block_ok
|
||||
|
||||
# Ok, we have the new state as it would look with the block applied - now we
|
||||
# can set the state root in order to be able to create a valid signature
|
||||
new_block.message.state_root = hash_tree_root(state)
|
||||
|
||||
doAssert privKey.pubKey() == proposer.pubkey,
|
||||
"signature key should be derived from private key! - wrong privkey?"
|
||||
|
||||
if skipBLSValidation notin flags:
|
||||
let domain = get_domain(state, DOMAIN_BEACON_PROPOSER,
|
||||
compute_epoch_at_slot(new_block.message.slot))
|
||||
let signing_root = compute_signing_root(new_block.message, domain)
|
||||
# We have a signature - put it in the block and we should be done!
|
||||
new_block.signature = bls_sign(privKey, signing_root.data)
|
||||
|
||||
doAssert bls_verify(
|
||||
proposer.pubkey,
|
||||
signing_root.data, new_block.signature),
|
||||
"we just signed this message - it should pass verification!"
|
||||
let ok = process_block(state, new_block.message, flags, cache)
|
||||
|
||||
doAssert ok, "adding block after producing it should work"
|
||||
new_block
|
||||
|
||||
proc makeBlock*(
|
||||
state: BeaconState, previous_block_root: Eth2Digest,
|
||||
body: BeaconBlockBody): SignedBeaconBlock =
|
||||
proc makeTestBlock*(
|
||||
state: BeaconState,
|
||||
parent_root: Eth2Digest,
|
||||
eth1_data = Eth1Data(),
|
||||
attestations = newSeq[Attestation](),
|
||||
deposits = newSeq[Deposit](),
|
||||
graffiti = Eth2Digest(),
|
||||
flags: set[UpdateFlag] = {}): SignedBeaconBlock =
|
||||
# Create a block for `state.slot + 1` - like a block proposer would do!
|
||||
# It's a bit awkward - in order to produce a block for N+1, we need to
|
||||
# calculate what the state will look like after that block has been applied,
|
||||
# because the block includes the state root.
|
||||
var next_state = state
|
||||
addBlock(next_state, previous_block_root, body)
|
||||
var tmpState = state
|
||||
addTestBlock(
|
||||
tmpState, parent_root, eth1_data, attestations, deposits, graffiti, flags)
|
||||
|
||||
proc makeAttestation*(
|
||||
state: BeaconState, beacon_block_root: Eth2Digest,
|
||||
|
@ -158,11 +147,9 @@ proc makeAttestation*(
|
|||
aggregation_bits.setBit sac_index
|
||||
|
||||
let
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch)
|
||||
signing_root = compute_signing_root(data, domain)
|
||||
sig =
|
||||
if skipBLSValidation notin flags:
|
||||
bls_sign(hackPrivKey(validator), signing_root.data)
|
||||
get_attestation_signature(state.fork, data, hackPrivKey(validator))
|
||||
else:
|
||||
ValidatorSig()
|
||||
|
||||
|
@ -209,27 +196,24 @@ proc makeFullAttestations*(
|
|||
let
|
||||
committee = get_beacon_committee(state, slot, index, cache)
|
||||
data = makeAttestationData(state, slot, index, beacon_block_root)
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, data.target.epoch)
|
||||
signing_root = compute_signing_root(data, domain)
|
||||
|
||||
doAssert committee.len() >= 1
|
||||
# Initial attestation
|
||||
var attestation = Attestation(
|
||||
aggregation_bits: CommitteeValidatorsBits.init(committee.len),
|
||||
data: data,
|
||||
signature: bls_sign(
|
||||
hackPrivKey(state.validators[committee[0]]),
|
||||
signing_root.data
|
||||
)
|
||||
signature: get_attestation_signature(
|
||||
state.fork, data,
|
||||
hackPrivKey(state.validators[committee[0]]))
|
||||
)
|
||||
# Aggregate the remainder
|
||||
attestation.aggregation_bits.setBit 0
|
||||
for j in 1 ..< committee.len():
|
||||
attestation.aggregation_bits.setBit j
|
||||
if skipBLSValidation notin flags:
|
||||
attestation.signature.aggregate(bls_sign(
|
||||
hackPrivKey(state.validators[committee[j]]),
|
||||
signing_root.data
|
||||
attestation.signature.aggregate(get_attestation_signature(
|
||||
state.fork, data,
|
||||
hackPrivKey(state.validators[committee[j]])
|
||||
))
|
||||
|
||||
result.add attestation
|
||||
|
|
Loading…
Reference in New Issue