Remove get_crosslink_committees_at_slot and fix research/state_sim (#291)

* migrate attestation pool tests from get_crosslink_committees_at_slot(...) to get_crosslink_committee(...)

* rm obsolete, unused get_crosslink_committees_at_slot_cached(...) and migrate tests/test_state_transition from get_crosslink_committees_at_slot(...) to get_crosslink_committee(...)

* migrate tests/testutil from get_crosslink_committees_at_slot(...) to get_crosslink_committee(...)

* use more pervasive caching infrastructure, initially of compute_committee; remove buggy (and per-index) shuffling to fix research/state_sim, which was noticing validators on multiple shard committees; rm now-unused specific get_attesting_balance_cached

* add some get_active_validator_index caching

* rm obsolete/unused get_attesting_indices_cached

* rm get_crosslink_committees_at_slot(...)

* some more 0.7 changes -- some of which can't be completed pending some data structure updates -- and shard handling changes to offset with epoch start shards
This commit is contained in:
Dustin Brody 2019-06-24 09:21:56 +00:00 committed by GitHub
parent c751285112
commit c7e06374f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 282 additions and 246 deletions

View File

@ -260,6 +260,7 @@ proc getAttestationsForBlock*(
newBlockSlot = humaneSlotNum(newBlockSlot)
return
var cache = get_empty_per_epoch_cache()
let
# TODO in theory we could include attestations from other slots also, but
# we're currently not tracking which attestations have already been included
@ -296,7 +297,8 @@ proc getAttestationsForBlock*(
# attestations into the pool in general is an open question that needs
# revisiting - for example, when attestations are added, against which
# state should they be validated, if at all?
if not checkAttestation(state, attestation, {skipValidation, nextSlot}):
if not checkAttestation(
state, attestation, {skipValidation, nextSlot}, cache):
continue
for v in a.validations[1..^1]:

View File

@ -468,13 +468,20 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
# In case blocks went missing, this means advancing past the latest block
# using empty slots as fillers.
node.blockPool.withState(node.stateCache, attestationHead):
for crosslink_committee in get_crosslink_committees_at_slot(state, slot):
for i, validatorIdx in crosslink_committee.committee:
var cache = get_empty_per_epoch_cache()
let epoch = slot_to_epoch(slot)
for committee_index in 0'u64 ..< get_epoch_committee_count(state, epoch):
## TODO verify that this is the correct mapping; it's consistent with
## other code
let
shard = committee_index mod SHARD_COUNT
committee = get_crosslink_committee(state, epoch, shard, cache)
for i, validatorIdx in committee:
let validator = node.getAttachedValidator(state, validatorIdx)
if validator != nil:
attestations.add (
makeAttestationData(state, crosslink_committee.shard, blck.root),
crosslink_committee.committee.len, i, validator)
makeAttestationData(state, shard, blck.root),
committee.len, i, validator)
for a in attestations:
traceAsyncErrors sendAttestation(
@ -489,9 +496,10 @@ proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
# proposing for it - basically, we're selecting proposer based on an
# empty slot.. wait for the committee selection to settle, then
# revisit this - we should be able to advance behind
var cache = get_empty_per_epoch_cache()
node.blockPool.withState(node.stateCache, BlockSlot(blck: head, slot: slot)):
let
proposerIdx = get_beacon_proposer_index(state)
proposerIdx = get_beacon_proposer_index(state, cache)
validator = node.getAttachedValidator(state, proposerIdx)
if validator != nil:

View File

@ -206,10 +206,9 @@ type
StateCache* = object
crosslink_committee_cache*:
Table[tuple[a: uint64, b: bool], seq[CrosslinkCommittee]]
winning_root_participants_cache*:
Table[Shard, HashSet[ValidatorIndex]]
Table[tuple[a: int, b: Eth2Digest], seq[ValidatorIndex]]
active_validator_indices_cache*:
Table[Epoch, seq[ValidatorIndex]]
BlockSlot* = object
## Unique identifier for a particular fork in the block chain - normally,

View File

@ -148,7 +148,8 @@ func initiate_validator_exit*(state: var BeaconState,
validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#slash_validator
func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex) =
func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex,
stateCache: var StateCache) =
# Slash the validator with index ``index``.
let current_epoch = get_current_epoch(state)
initiate_validator_exit(state, slashed_index)
@ -161,7 +162,7 @@ func slash_validator*(state: var BeaconState, slashed_index: ValidatorIndex) =
slashed_balance
let
proposer_index = get_beacon_proposer_index(state)
proposer_index = get_beacon_proposer_index(state, stateCache)
# Spec has whistleblower_index as optional param, but it's never used.
whistleblower_index = proposer_index
whistleblowing_reward = slashed_balance div WHISTLEBLOWING_REWARD_QUOTIENT
@ -321,7 +322,9 @@ func get_total_balance*(state: BeaconState, validators: auto): Gwei =
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#registry-updates
func process_registry_updates*(state: var BeaconState) =
# Process activation eligibility and ejections
## Process activation eligibility and ejections
## Try to avoid caching here, since this could easily become undefined
for index, validator in state.validator_registry:
if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and
validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
@ -411,7 +414,9 @@ func validate_indexed_attestation*(
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_attesting_indices
func get_attesting_indices*(state: BeaconState,
attestation_data: AttestationData,
bitfield: BitField): HashSet[ValidatorIndex] =
bitfield: BitField,
stateCache: var StateCache):
HashSet[ValidatorIndex] =
## Return the sorted attesting indices corresponding to ``attestation_data``
## and ``bitfield``.
## The spec goes through a lot of hoops to sort things, and sometimes
@ -421,7 +426,7 @@ func get_attesting_indices*(state: BeaconState,
result = initSet[ValidatorIndex]()
let committee =
get_crosslink_committee(state, attestation_data.target_epoch,
attestation_data.shard)
attestation_data.shard, stateCache)
doAssert verify_bitfield(bitfield, len(committee))
for i, index in committee:
if get_bitfield_bit(bitfield, i):
@ -430,25 +435,29 @@ func get_attesting_indices*(state: BeaconState,
func get_attesting_indices_seq*(
state: BeaconState, attestation_data: AttestationData, bitfield: BitField):
seq[ValidatorIndex] =
toSeq(items(get_attesting_indices(state, attestation_data, bitfield)))
var cache = get_empty_per_epoch_cache()
toSeq(items(get_attesting_indices(
state, attestation_data, bitfield, cache)))
# TODO legacy function name; rename, reimplement caching if useful, blob/v0.6.2
iterator get_attestation_participants_cached*(
state: BeaconState, attestation_data: AttestationData, bitfield: BitField,
cache: var StateCache): ValidatorIndex =
for participant in get_attesting_indices(state, attestation_data, bitfield):
for participant in get_attesting_indices(
state, attestation_data, bitfield, cache):
yield participant
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#convert_to_indexed
func convert_to_indexed(state: BeaconState, attestation: Attestation): IndexedAttestation =
func convert_to_indexed(state: BeaconState, attestation: Attestation,
stateCache: var StateCache): IndexedAttestation =
# Convert ``attestation`` to (almost) indexed-verifiable form.
let
attesting_indices =
get_attesting_indices(
state, attestation.data, attestation.aggregation_bitfield)
state, attestation.data, attestation.aggregation_bitfield, stateCache)
custody_bit_1_indices =
get_attesting_indices(
state, attestation.data, attestation.custody_bitfield)
state, attestation.data, attestation.custody_bitfield, stateCache)
## TODO quadratic, .items, but first-class iterators, etc
## filterIt can't work on HashSets directly because it is
@ -486,7 +495,8 @@ func convert_to_indexed(state: BeaconState, attestation: Attestation): IndexedAt
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#attestations
proc checkAttestation*(
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
state: BeaconState, attestation: Attestation, flags: UpdateFlags,
stateCache: var StateCache): bool =
## Process ``Attestation`` operation.
## Check that an attestation follows the rules of being included in the state
## at the current slot. When acting as a proposer, the same rules need to
@ -496,7 +506,10 @@ proc checkAttestation*(
if nextSlot in flags: state.slot + 1
else: state.slot
let attestation_slot = get_attestation_slot(state, attestation)
let
data = attestation.data
attestation_slot = get_attestation_slot(state, attestation)
if not (attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= stateSlot):
warn("Attestation too new",
attestation_slot = humaneSlotNum(attestation_slot),
@ -509,29 +522,66 @@ proc checkAttestation*(
state_slot = humaneSlotNum(stateSlot))
return
let pending_attestation = PendingAttestation(
data: data,
aggregation_bitfield: attestation.aggregation_bitfield,
inclusion_delay: state.slot - attestation_slot,
proposer_index: get_beacon_proposer_index(state, stateCache),
)
# Check target epoch, source epoch, source root, and source crosslink
let data = attestation.data
if not (
(data.target_epoch, data.source_epoch, data.source_root, data.previous_crosslink_root) ==
(get_current_epoch(state), state.current_justified_epoch,
state.current_justified_root,
hash_tree_root(state.current_crosslinks[data.shard])) or
(data.target_epoch, data.source_epoch, data.source_root, data.previous_crosslink_root) ==
(get_previous_epoch(state), state.previous_justified_epoch,
state.previous_justified_root,
hash_tree_root(state.previous_crosslinks[data.shard]))):
warn("checkAttestation: target epoch, source epoch, source root, or source crosslink invalid")
if not (data.target_epoch == get_previous_epoch(state) or
data.target_epoch == get_current_epoch(state)):
warn("Target epoch not current or previous epoch")
return
## Check crosslink data root
## [to be removed in phase 1]
if attestation.data.crosslink_data_root != ZERO_HASH:
warn("Invalid crosslink data root")
return
# Check FFG data, crosslink data, and signature
let ffg_check_data = (data.source_epoch, data.source_root, data.target_epoch)
if data.target_epoch == get_current_epoch(state):
if not (ffg_check_data == (state.current_justified_epoch,
state.current_justified_root, get_current_epoch(state))):
warn("FFG data not matching current justified epoch")
return
#if not (data.crosslink.parent_root ==
# hash_tree_root(state.current_crosslinks[data.crosslink.shard])):
# warn("Crosslink shard's current crosslinks not matching crosslink parent root")
# return
#state.current_epoch_attestations.add(pending_attestation)
else:
if not (ffg_check_data == (state.previous_justified_epoch,
state.previous_justified_root, get_previous_epoch(state))):
warn("FFG data not matching current justified epoch")
return
#if not (data.crosslink.parent_root ==
# hash_tree_root(state.previous_crosslinks[data.crosslink.shard])):
# warn("Crosslink shard's previous crosslinks not matching crosslink parent root")
# return
#state.previous_epoch_attestations.add(pending_attestation)
# TODO un-comment when changed Crosslink to 0.7 structure
#if not (data.crosslink.start_epoch == parent_crosslink.end_epoch):
# warn("Crosslink start and end epochs not the same")
# return
#if not (data.crosslink.end_epoch == min(data.target_epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)):
# warn("Crosslink end epoch incorrect")
# return
# Simlarly, these depend on 0.7 data structures
#assert data.crosslink.parent_root == hash_tree_root(parent_crosslink)
#if not (data.crosslink.data_root == ZERO_HASH): # [to be removed in phase 1]
# warn("Crosslink data root not zero")
# return
# Check signature and bitfields
if not validate_indexed_attestation(
state, convert_to_indexed(state, attestation)):
state, convert_to_indexed(state, attestation, stateCache)):
warn("checkAttestation: signature or bitfields incorrect")
return
@ -552,7 +602,8 @@ proc makeAttestationData*(
AttestationData(
slot: state.slot,
shard: shard,
# Alternative is to put this offset into all callers
shard: shard + get_epoch_start_shard(state, slot_to_epoch(state.slot)),
beacon_block_root: beacon_block_root,
target_root: target_root,
crosslink_data_root: Eth2Digest(), # Stub in phase0

View File

@ -363,9 +363,6 @@ type
Activation = 0
Exit = 1
# TODO: not in spec
CrosslinkCommittee* = tuple[committee: seq[ValidatorIndex], shard: uint64]
# TODO to be replaced with some magic hash caching
HashedBeaconState* = object
data*: BeaconState

View File

@ -7,8 +7,7 @@
# Helpers and functions pertaining to managing the validator set
import
options, nimcrypto, sequtils, math, chronicles,
eth/common,
options, nimcrypto, sequtils, math, tables, chronicles,
../ssz, ../beacon_node_types,
./crypto, ./datatypes, ./digest, ./helpers
@ -80,44 +79,6 @@ func get_shuffled_seq*(seed: Eth2Digest,
result = shuffled_active_validator_indices
func get_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Eth2Digest): uint64 =
## Return the shuffled validator index corresponding to ``seed`` (and
## ``index_count``).
## https://github.com/status-im/nim-beacon-chain/blob/f77016af6818ad2c853f6c9e2751b17548e0222e/beacon_chain/spec/validator.nim#L15
doAssert index.uint64 < index_count
doAssert index_count <= 2'u64^40
result = index
var pivot_buffer: array[(32+1), byte]
var source_buffer: array[(32+1+4), byte]
# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
# See the 'generalized domain' algorithm on page 3
for round in 0 ..< SHUFFLE_ROUND_COUNT:
pivot_buffer[0..31] = seed.data
let round_bytes1 = int_to_bytes1(round)[0]
pivot_buffer[32] = round_bytes1
let
pivot = bytes_to_int(eth2hash(pivot_buffer).data[0..7]) mod index_count
flip = (pivot - index) mod index_count
position = max(index.uint64, flip)
## Tradeoff between slicing (if reusing one larger buffer) and additional
## copies here of seed and `int_to_bytes1(round)`.
source_buffer[0..31] = seed.data
source_buffer[32] = round_bytes1
source_buffer[33..36] = int_to_bytes4(position div 256)
let
source = eth2hash(source_buffer).data
byte_value = source[(position mod 256) div 8]
bit = (byte_value shr (position mod 8)) mod 2
if bit != 0:
result = flip
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_previous_epoch
func get_previous_epoch*(state: BeaconState): Epoch =
## Return the previous epoch of the given ``state``.
@ -151,69 +112,63 @@ func get_epoch_start_shard*(state: BeaconState, epoch: Epoch): Shard =
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#compute_committee
func compute_committee(indices: seq[ValidatorIndex], seed: Eth2Digest,
index: uint64, count: uint64): seq[ValidatorIndex] =
index: uint64, count: uint64, stateCache: var StateCache): seq[ValidatorIndex] =
let
start = (len(indices).uint64 * index) div count
endIdx = (len(indices).uint64 * (index + 1)) div count
key = (indices.len, seed)
doAssert endIdx.int - start.int > 0
if key notin stateCache.crosslink_committee_cache:
stateCache.crosslink_committee_cache[key] =
get_shuffled_seq(seed, len(indices).uint64)
# These assertions from get_shuffled_index(...)
let index_count = indices.len().uint64
doAssert endIdx <= index_count
doAssert index_count <= 2'u64^40
# In spec, this calls get_shuffled_index() every time, but that's wasteful
mapIt(
start.int .. (endIdx.int-1),
indices[
get_shuffled_index(it.ValidatorIndex, len(indices).uint64, seed).int])
stateCache.crosslink_committee_cache[key][it]])
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_crosslink_committee
func get_crosslink_committee*(state: BeaconState, epoch: Epoch, shard: Shard):
seq[ValidatorIndex] =
func get_crosslink_committee*(state: BeaconState, epoch: Epoch, shard: Shard,
stateCache: var StateCache): seq[ValidatorIndex] =
doAssert shard >= 0'u64
# This seems to be required, basically, to be true? But I'm not entirely sure
#doAssert shard >= get_epoch_start_shard(state, epoch)
doAssert shard < SHARD_COUNT
## This is a somewhat more fragile, but high-ROI, caching setup --
## get_active_validator_indices() is slow to run in a loop and only
## changes once per epoch.
if epoch notin stateCache.active_validator_indices_cache:
stateCache.active_validator_indices_cache[epoch] =
get_active_validator_indices(state, epoch)
compute_committee(
get_active_validator_indices(state, epoch),
stateCache.active_validator_indices_cache[epoch],
generate_seed(state, epoch),
(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) mod SHARD_COUNT,
get_epoch_committee_count(state, epoch),
stateCache
)
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_crosslink_committees_at_slot
func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot|uint64):
seq[CrosslinkCommittee] =
## Returns the list of ``(committee, shard)`` tuples for the ``slot``.
let
epoch = slot_to_epoch(slot) # TODO, enforce slot to be a Slot
current_epoch = get_current_epoch(state)
previous_epoch = get_previous_epoch(state)
next_epoch = current_epoch + 1
doAssert previous_epoch <= epoch,
"Previous epoch: " & $humaneEpochNum(previous_epoch) &
", epoch: " & $humaneEpochNum(epoch) &
" (slot: " & $humaneSlotNum(slot.Slot) & ")" &
", Next epoch: " & $humaneEpochNum(next_epoch)
doAssert epoch <= next_epoch,
"Previous epoch: " & $humaneEpochNum(previous_epoch) &
", epoch: " & $humaneEpochNum(epoch) &
" (slot: " & $humaneSlotNum(slot.Slot) & ")" &
", Next epoch: " & $humaneEpochNum(next_epoch)
for i in 0'u64 ..< get_epoch_committee_count(state, epoch):
let shard = i mod SHARD_COUNT
result.add (
get_crosslink_committee(state, epoch, shard),
shard
)
iterator get_crosslink_committees_at_slot_cached*(
state: BeaconState, slot: Slot|uint64, cache: var StateCache):
CrosslinkCommittee =
let key = (slot_to_epoch(slot).uint64, false)
if key in cache.crosslink_committee_cache:
for v in cache.crosslink_committee_cache[key]: yield v
#debugEcho "get_crosslink_committees_at_slot_cached: MISS"
let result = get_crosslink_committees_at_slot(state, slot)
cache.crosslink_committee_cache[key] = result
for v in result: yield v
# Not from spec
func get_empty_per_epoch_cache*(): StateCache =
result.crosslink_committee_cache =
initTable[tuple[a: int, b: Eth2Digest], seq[ValidatorIndex]]()
result.active_validator_indices_cache =
initTable[Epoch, seq[ValidatorIndex]]()
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(state: BeaconState): ValidatorIndex =
func get_beacon_proposer_index*(state: BeaconState, stateCache: var StateCache):
ValidatorIndex =
# Return the current beacon proposer index.
const
MAX_RANDOM_BYTE = 255
@ -224,7 +179,7 @@ func get_beacon_proposer_index*(state: BeaconState): ValidatorIndex =
get_epoch_committee_count(state, epoch) div SLOTS_PER_EPOCH
offset = committees_per_slot * (state.slot mod SLOTS_PER_EPOCH)
shard = (get_epoch_start_shard(state, epoch) + offset) mod SHARD_COUNT
first_committee = get_crosslink_committee(state, epoch, shard)
first_committee = get_crosslink_committee(state, epoch, shard, stateCache)
seed = generate_seed(state, epoch)
var

View File

@ -37,7 +37,8 @@ import
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#block-header
proc processBlockHeader(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
# Verify that the slots match
if not (blck.slot == state.slot):
notice "Block header: slot mismatch",
@ -62,7 +63,8 @@ proc processBlockHeader(
)
# Verify proposer is not slashed
let proposer = state.validator_registry[get_beacon_proposer_index(state)]
let proposer =
state.validator_registry[get_beacon_proposer_index(state, stateCache)]
if proposer.slashed:
notice "Block header: proposer slashed"
return false
@ -83,9 +85,10 @@ proc processBlockHeader(
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#randao
proc processRandao(
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags): bool =
state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
stateCache: var StateCache): bool =
let
proposer_index = get_beacon_proposer_index(state)
proposer_index = get_beacon_proposer_index(state, stateCache)
proposer = addr state.validator_registry[proposer_index]
# Verify that the provided randao value is valid
@ -128,7 +131,8 @@ func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#proposer-slashings
proc processProposerSlashings(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
notice "PropSlash: too many!",
proposer_slashings = len(blck.body.proposer_slashings)
@ -166,7 +170,8 @@ proc processProposerSlashings(
signature_index = i
return false
slashValidator(state, proposer_slashing.proposer_index.ValidatorIndex)
slashValidator(
state, proposer_slashing.proposer_index.ValidatorIndex, stateCache)
true
@ -183,7 +188,8 @@ func is_slashable_attestation_data(
data_2.target_epoch < data_1.target_epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#attester-slashings
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock,
stateCache: var StateCache): bool =
# Process ``AttesterSlashing`` operation.
if len(blck.body.attester_slashings) > MAX_ATTESTER_SLASHINGS:
notice "CaspSlash: too many!"
@ -221,13 +227,14 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
toSet(attesting_indices_2)).items), system.cmp):
if is_slashable_validator(state.validator_registry[index.int],
get_current_epoch(state)):
slash_validator(state, index.ValidatorIndex)
slash_validator(state, index.ValidatorIndex, stateCache)
slashed_any = true
result = result and slashed_any
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#attestations
proc processAttestations(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
## Each block includes a number of attestations that the proposer chose. Each
## attestation represents an update to a specific shard and is signed by a
## committee of validators.
@ -238,7 +245,7 @@ proc processAttestations(
notice "Attestation: too many!", attestations = blck.body.attestations.len
return false
if not blck.body.attestations.allIt(checkAttestation(state, it, flags)):
if not blck.body.attestations.allIt(checkAttestation(state, it, flags, stateCache)):
return false
# All checks passed - update state
@ -262,7 +269,7 @@ proc processAttestations(
data: attestation.data,
aggregation_bitfield: attestation.aggregation_bitfield,
inclusion_delay: state.slot - attestation_slot,
proposer_index: get_beacon_proposer_index(state),
proposer_index: get_beacon_proposer_index(state, stateCache),
)
if attestation.data.target_epoch == get_current_epoch(state):
@ -334,7 +341,7 @@ proc processVoluntaryExits(
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#transfers
proc processTransfers(state: var BeaconState, blck: BeaconBlock,
flags: UpdateFlags): bool =
flags: UpdateFlags, stateCache: var StateCache): bool =
if not (len(blck.body.transfers) <= MAX_TRANSFERS):
notice "Transfer: too many transfers"
return false
@ -387,7 +394,8 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
state, transfer.sender.ValidatorIndex, transfer.amount + transfer.fee)
increase_balance(
state, transfer.recipient.ValidatorIndex, transfer.amount)
increase_balance(state, get_beacon_proposer_index(state), transfer.fee)
increase_balance(
state, get_beacon_proposer_index(state, stateCache), transfer.fee)
# Verify balances are not dust
if not (
@ -429,32 +437,33 @@ func process_slot(state: var BeaconState) =
signing_root(state.latest_block_header)
proc processBlock(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool =
## When there's a new block, we need to verify that the block is sane and
## update the state accordingly
# TODO when there's a failure, we should reset the state!
# TODO probably better to do all verification first, then apply state changes
if not processBlockHeader(state, blck, flags):
if not processBlockHeader(state, blck, flags, stateCache):
notice "Block header not valid", slot = humaneSlotNum(state.slot)
return false
if not processRandao(state, blck.body, flags):
if not processRandao(state, blck.body, flags, stateCache):
debug "[Block processing] Randao failure", slot = humaneSlotNum(state.slot)
return false
processEth1Data(state, blck.body)
if not processProposerSlashings(state, blck, flags):
if not processProposerSlashings(state, blck, flags, stateCache):
debug "[Block processing] Proposer slashing failure", slot = humaneSlotNum(state.slot)
return false
if not processAttesterSlashings(state, blck):
if not processAttesterSlashings(state, blck, stateCache):
debug "[Block processing] Attester slashing failure", slot = humaneSlotNum(state.slot)
return false
if not processAttestations(state, blck, flags):
if not processAttestations(state, blck, flags, stateCache):
debug "[Block processing] Attestation processing failure", slot = humaneSlotNum(state.slot)
return false
@ -466,26 +475,12 @@ proc processBlock(
debug "[Block processing] Exit processing failure", slot = humaneSlotNum(state.slot)
return false
if not processTransfers(state, blck, flags):
if not processTransfers(state, blck, flags, stateCache):
debug "[Block processing] Transfer processing failure", slot = humaneSlotNum(state.slot)
return false
true
# TODO this cached version corresponds to the blob/v0.5.1ish get_attesting_indices
# rm/make consistent with 0.6 version above
func get_attesting_indices_cached(
state: BeaconState,
attestations: openArray[PendingAttestation], cache: var StateCache):
HashSet[ValidatorIndex] =
# Union of attesters that participated in some attestations
result = initSet[ValidatorIndex]()
for attestation in attestations:
for validator_index in get_attestation_participants_cached(
state, attestation.data, attestation.aggregation_bitfield,
cache):
result.incl validator_index
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#helper-functions-1
func get_total_active_balance(state: BeaconState): Gwei =
return get_total_balance(
@ -516,26 +511,22 @@ func get_matching_head_attestations(state: BeaconState, epoch: Epoch):
)
func get_unslashed_attesting_indices(
state: BeaconState, attestations: seq[PendingAttestation]):
HashSet[ValidatorIndex] =
state: BeaconState, attestations: seq[PendingAttestation],
stateCache: var StateCache): HashSet[ValidatorIndex] =
result = initSet[ValidatorIndex]()
for a in attestations:
result = result.union(get_attesting_indices(
state, a.data, a.aggregation_bitfield))
state, a.data, a.aggregation_bitfield, stateCache))
for index in result:
if state.validator_registry[index].slashed:
result.excl index
func get_attesting_balance(
state: BeaconState, attestations: seq[PendingAttestation]): Gwei =
get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
func get_attesting_balance_cached(
state: BeaconState, attestations: seq[PendingAttestation],
cache: var StateCache): Gwei =
get_total_balance(state, get_attesting_indices_cached(
state, attestations, cache))
stateCache: var StateCache): Gwei =
get_total_balance(state, get_unslashed_attesting_indices(
state, attestations, stateCache))
func get_crosslink_from_attestation_data(
state: BeaconState, data: AttestationData): Crosslink =
@ -554,9 +545,9 @@ func lowerThan(candidate, current: Eth2Digest): bool =
if v > candidate.data[i]: return true
false
# TODO check/profile if should add cache: var StateCache param
func get_winning_crosslink_and_attesting_indices(
state: BeaconState, epoch: Epoch, shard: Shard): tuple[a: Crosslink, b: HashSet[ValidatorIndex]] =
state: BeaconState, epoch: Epoch, shard: Shard,
stateCache: var StateCache): tuple[a: Crosslink, b: HashSet[ValidatorIndex]] =
let
## TODO Z-F could help here
## TODO get_winning_crosslink_and_attesting_indices was profiling hotspot
@ -602,7 +593,8 @@ func get_winning_crosslink_and_attesting_indices(
## let root_balance = get_attesting_balance_cached(
## state, attestations_for.getOrDefault(r), cache)
let crosslink_balance =
get_attesting_balance(state, get_attestations_for(candidate_crosslink))
get_attesting_balance(
state, get_attestations_for(candidate_crosslink), stateCache)
if (crosslink_balance > winning_crosslink_balance or
(winning_crosslink_balance == crosslink_balance and
lowerThan(winning_crosslink.crosslink_data_root,
@ -612,10 +604,11 @@ func get_winning_crosslink_and_attesting_indices(
(winning_crosslink,
get_unslashed_attesting_indices(state,
get_attestations_for(winning_crosslink)))
get_attestations_for(winning_crosslink), stateCache))
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#justification-and-finalization
func process_justification_and_finalization(state: var BeaconState) =
func process_justification_and_finalization(
state: var BeaconState, stateCache: var StateCache) =
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
return
@ -631,7 +624,7 @@ func process_justification_and_finalization(state: var BeaconState) =
state.justification_bitfield = (state.justification_bitfield shl 1)
let previous_epoch_matching_target_balance =
get_attesting_balance(state,
get_matching_target_attestations(state, previous_epoch))
get_matching_target_attestations(state, previous_epoch), stateCache)
if previous_epoch_matching_target_balance * 3 >=
get_total_active_balance(state) * 2:
state.current_justified_epoch = previous_epoch
@ -640,7 +633,8 @@ func process_justification_and_finalization(state: var BeaconState) =
state.justification_bitfield = state.justification_bitfield or (1 shl 1)
let current_epoch_matching_target_balance =
get_attesting_balance(state,
get_matching_target_attestations(state, current_epoch))
get_matching_target_attestations(state, current_epoch),
stateCache)
if current_epoch_matching_target_balance * 3 >=
get_total_active_balance(state) * 2:
state.current_justified_epoch = current_epoch
@ -680,7 +674,7 @@ func process_justification_and_finalization(state: var BeaconState) =
state.finalized_root = get_block_root(state, state.finalized_epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#crosslinks
func process_crosslinks(state: var BeaconState, per_epoch_cache: var StateCache) =
func process_crosslinks(state: var BeaconState, stateCache: var StateCache) =
## TODO is there a semantic reason for this, or is this just a way to force
## copying? If so, why not just `list(foo)` or similar? This is strange. In
## this case, for type reasons, don't do weird
@ -695,13 +689,15 @@ func process_crosslinks(state: var BeaconState, per_epoch_cache: var StateCache)
for offset in 0'u64 ..< get_epoch_committee_count(state, epoch):
let
shard = (get_epoch_start_shard(state, epoch) + offset) mod SHARD_COUNT
crosslink_committee = get_crosslink_committee(state, epoch, shard)
crosslink_committee =
get_crosslink_committee(state, epoch, shard, stateCache)
# In general, it'll loop over the same shards twice, and
# get_winning_root_and_participants is defined to return
# the same results from the previous epoch as current.
# TODO cache like before, in 0.5 version of this function
(winning_crosslink, attesting_indices) =
get_winning_crosslink_and_attesting_indices(state, epoch, shard)
get_winning_crosslink_and_attesting_indices(
state, epoch, shard, stateCache)
if 3'u64 * get_total_balance(state, attesting_indices) >=
2'u64 * get_total_balance(state, crosslink_committee):
state.current_crosslinks[shard] = winning_crosslink
@ -715,7 +711,7 @@ func get_base_reward(state: BeaconState, index: ValidatorIndex): Gwei =
integer_squareroot(total_balance) div BASE_REWARDS_PER_EPOCH
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#rewards-and-penalties
func get_attestation_deltas(state: BeaconState):
func get_attestation_deltas(state: BeaconState, stateCache: var StateCache):
tuple[a: seq[Gwei], b: seq[Gwei]] =
let
previous_epoch = get_previous_epoch(state)
@ -743,8 +739,8 @@ func get_attestation_deltas(state: BeaconState):
matching_head_attestations]:
let
unslashed_attesting_indices =
get_unslashed_attesting_indices(state, attestations)
attesting_balance = get_attesting_balance(state, attestations)
get_unslashed_attesting_indices(state, attestations, stateCache)
attesting_balance = get_attesting_balance(state, attestations, stateCache)
for index in eligible_validator_indices:
if index in unslashed_attesting_indices:
rewards[index] +=
@ -756,11 +752,13 @@ func get_attestation_deltas(state: BeaconState):
return (rewards, penalties)
# Proposer and inclusion delay micro-rewards
for index in get_unslashed_attesting_indices(state, matching_source_attestations):
for index in get_unslashed_attesting_indices(
state, matching_source_attestations, stateCache):
doAssert matching_source_attestations.len > 0
var attestation = matching_source_attestations[0]
for a in matching_source_attestations:
if index notin get_attesting_indices(state, a.data, a.aggregation_bitfield):
if index notin get_attesting_indices(
state, a.data, a.aggregation_bitfield, stateCache):
continue
if a.inclusion_delay < attestation.inclusion_delay:
attestation = a
@ -774,7 +772,8 @@ func get_attestation_deltas(state: BeaconState):
let finality_delay = previous_epoch - state.finalized_epoch
if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY:
let matching_target_attesting_indices =
get_unslashed_attesting_indices(state, matching_target_attestations)
get_unslashed_attesting_indices(
state, matching_target_attestations, stateCache)
for index in eligible_validator_indices:
penalties[index] +=
BASE_REWARDS_PER_EPOCH.uint64 * get_base_reward(state, index)
@ -796,9 +795,11 @@ func get_crosslink_deltas(state: BeaconState, cache: var StateCache):
for offset in 0'u64 ..< get_epoch_committee_count(state, epoch):
let
shard = (get_epoch_start_shard(state, epoch) + offset) mod SHARD_COUNT
crosslink_committee = get_crosslink_committee(state, epoch, shard)
crosslink_committee =
get_crosslink_committee(state, epoch, shard, cache)
(winning_crosslink, attesting_indices) =
get_winning_crosslink_and_attesting_indices(state, epoch, shard)
get_winning_crosslink_and_attesting_indices(
state, epoch, shard, cache)
attesting_balance = get_total_balance(state, attesting_indices)
committee_balance = get_total_balance(state, crosslink_committee)
for index in crosslink_committee:
@ -819,7 +820,7 @@ func process_rewards_and_penalties(
return
let
(rewards1, penalties1) = get_attestation_deltas(state)
(rewards1, penalties1) = get_attestation_deltas(state, cache)
(rewards2, penalties2) = get_crosslink_deltas(state, cache)
for i in 0 ..< len(state.validator_registry):
increase_balance(state, i.ValidatorIndex, rewards1[i] + rewards2[i])
@ -897,22 +898,16 @@ func process_final_updates(state: var BeaconState) =
state.current_epoch_attestations = @[]
# https://github.com/ethereum/eth2.0-specs/blob/v0.6.3/specs/core/0_beacon-chain.md#per-epoch-processing
func get_empty_per_epoch_cache(): StateCache =
result.crosslink_committee_cache =
initTable[tuple[a: uint64, b: bool], seq[CrosslinkCommittee]]()
result.winning_root_participants_cache =
initTable[Shard, HashSet[ValidatorIndex]]()
func processEpoch(state: var BeaconState) =
if not (state.slot > GENESIS_SLOT and
(state.slot + 1) mod SLOTS_PER_EPOCH == 0):
return
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#justification-and-finalization
process_justification_and_finalization(state)
var per_epoch_cache = get_empty_per_epoch_cache()
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#justification-and-finalization
process_justification_and_finalization(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#crosslinks
process_crosslinks(state, per_epoch_cache)
@ -920,8 +915,13 @@ func processEpoch(state: var BeaconState) =
process_rewards_and_penalties(state, per_epoch_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#registry-updates
# Don't rely on caching here.
process_registry_updates(state)
## Caching here for get_crosslink_committee(...) can break otherwise, since
## get_active_validator_indices(...) usually changes.
clear(per_epoch_cache.crosslink_committee_cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#slashings
process_slashings(state)
@ -1006,7 +1006,9 @@ proc updateState*(
# that the block is sane.
# TODO what should happen if block processing fails?
# https://github.com/ethereum/eth2.0-specs/issues/293
if processBlock(state, new_block, flags):
var per_epoch_cache = get_empty_per_epoch_cache()
if processBlock(state, new_block, flags, per_epoch_cache):
# This is a bit awkward - at the end of processing we verify that the
# state we arrive at is what the block producer thought it would be -
# meaning that potentially, it could fail verification
@ -1059,7 +1061,8 @@ proc updateState*(
var old_state = state
advanceState(state)
if processBlock(state.data, blck, flags):
var per_epoch_cache = get_empty_per_epoch_cache()
if processBlock(state.data, blck, flags, per_epoch_cache):
if skipValidation in flags or verifyStateRoot(state.data, blck):
# State root is what it should be - we're done!

View File

@ -15,7 +15,7 @@ type Timers = enum
tBlock = "Process non-epoch slot with block"
tEpoch = "Process epoch slot with block"
tHashBlock = "Tree-hash block"
tShuffle = "Retrieve committee once using get_crosslink_committees_at_slot"
tShuffle = "Retrieve committee once using get_crosslink_committee"
tAttest = "Combine committee attestations"
template withTimer(stats: var RunningStat, body: untyped) =
@ -65,6 +65,7 @@ cli do(slots = 1945,
attesters: RunningStat
r: Rand
blck: BeaconBlock
cache = get_empty_per_epoch_cache()
proc maybeWrite() =
if state.slot mod json_interval.uint64 == 0:
@ -96,18 +97,24 @@ cli do(slots = 1945,
# attesterRatio is the fraction of attesters that actually do their
# work for every slot - we'll randomize it deterministically to give
# some variation
let scass = withTimerRet(timers[tShuffle]):
get_crosslink_committees_at_slot(state, state.slot)
let
epoch = slot_to_epoch(state.slot)
scass = withTimerRet(timers[tShuffle]):
mapIt(
0'u64 .. (get_epoch_committee_count(state, epoch) - 1),
get_crosslink_committee(state, epoch,
(it + get_epoch_start_shard(state, epoch)) mod SHARD_COUNT,
cache))
for scas in scass:
var
attestation: Attestation
first = true
attesters.push scas.committee.len()
attesters.push scas.len()
withTimer(timers[tAttest]):
for v in scas.committee:
for v in scas:
if (rand(r, high(int)).float * attesterRatio).int <= high(int):
if first:
attestation = makeAttestation(state, latest_block_root, v, flags)

View File

@ -35,13 +35,14 @@ suite "Attestation pool processing" & preset():
genBlock = get_initial_beacon_block(genState)
test "Can add and retrieve simple attestation" & preset():
var cache = get_empty_per_epoch_cache()
withPool:
let
# Create an attestation for slot 1!
crosslink_committees =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
crosslink_committee = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation = makeAttestation(
state.data.data, state.blck.root, crosslink_committees[0].committee[0])
state.data.data, state.blck.root, crosslink_committee[0])
pool.add(state.data.data, attestation)
@ -55,21 +56,22 @@ suite "Attestation pool processing" & preset():
attestations.len == 1
test "Attestations may arrive in any order" & preset():
var cache = get_empty_per_epoch_cache()
withPool:
let
# Create an attestation for slot 1!
cc0 =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
cc0 = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation0 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[0])
state.data.data, state.blck.root, cc0[0])
advanceState(state.data)
let
cc1 =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
cc1 = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation1 = makeAttestation(
state.data.data, state.blck.root, cc1[0].committee[0])
state.data.data, state.blck.root, cc1[0])
# test reverse order
pool.add(state.data.data, attestation1)
@ -84,15 +86,16 @@ suite "Attestation pool processing" & preset():
attestations.len == 1
test "Attestations should be combined" & preset():
var cache = get_empty_per_epoch_cache()
withPool:
let
# Create an attestation for slot 1!
cc0 =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
cc0 = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation0 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[0])
state.data.data, state.blck.root, cc0[0])
attestation1 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[1])
state.data.data, state.blck.root, cc0[1])
pool.add(state.data.data, attestation0)
pool.add(state.data.data, attestation1)
@ -106,16 +109,17 @@ suite "Attestation pool processing" & preset():
attestations.len == 1
test "Attestations may overlap, bigger first" & preset():
var cache = get_empty_per_epoch_cache()
withPool:
var
# Create an attestation for slot 1!
cc0 =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
cc0 = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation0 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[0])
state.data.data, state.blck.root, cc0[0])
attestation1 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[1])
state.data.data, state.blck.root, cc0[1])
attestation0.combine(attestation1, {skipValidation})
@ -131,15 +135,16 @@ suite "Attestation pool processing" & preset():
attestations.len == 1
test "Attestations may overlap, smaller first" & preset():
var cache = get_empty_per_epoch_cache()
withPool:
var
# Create an attestation for slot 1!
cc0 =
get_crosslink_committees_at_slot(state.data.data, state.data.data.slot)
cc0 = get_crosslink_committee(state.data.data,
slot_to_epoch(state.data.data.slot), 0, cache)
attestation0 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[0])
state.data.data, state.blck.root, cc0[0])
attestation1 = makeAttestation(
state.data.data, state.blck.root, cc0[0].committee[1])
state.data.data, state.blck.root, cc0[1])
attestation0.combine(attestation1, {skipValidation})

View File

@ -76,16 +76,17 @@ suite "Block processing" & preset():
var
state = genesisState
previous_block_root = genesisRoot
cache = get_empty_per_epoch_cache()
# Slot 0 is a finalized slot - won't be making attestations for it..
advanceState(state)
let
# Create an attestation for slot 1 signed by the only attester we have!
crosslink_committees = get_crosslink_committees_at_slot(state, state.slot)
crosslink_committee =
get_crosslink_committee(state, slot_to_epoch(state.slot), 0, cache)
attestation = makeAttestation(
state, previous_block_root,
crosslink_committees[0].committee[0])
state, previous_block_root, crosslink_committee[0])
# Some time needs to pass before attestations are included - this is
# to let the attestation propagate properly to interested participants

View File

@ -63,9 +63,12 @@ func getNextBeaconProposerIndex*(state: BeaconState): ValidatorIndex =
# TODO: This is a special version of get_beacon_proposer_index that takes into
# account the partial update done at the start of slot processing -
# see get_shard_committees_index
var next_state = state
var
next_state = state
cache = get_empty_per_epoch_cache()
next_state.slot += 1
get_beacon_proposer_index(next_state)
get_beacon_proposer_index(next_state, cache)
proc addBlock*(
state: var BeaconState, previous_block_root: Eth2Digest,
@ -76,7 +79,8 @@ proc addBlock*(
# but avoids some slow block copies
state.slot += 1
let proposer_index = get_beacon_proposer_index(state)
var cache = get_empty_per_epoch_cache()
let proposer_index = get_beacon_proposer_index(state, cache)
state.slot -= 1
let
@ -138,25 +142,29 @@ proc makeBlock*(
addBlock(next_state, previous_block_root, body)
proc find_shard_committee(
sacs: openArray[CrosslinkCommittee], validator_index: ValidatorIndex): CrosslinkCommittee =
for sac in sacs:
if validator_index in sac.committee: return sac
state: BeaconState, validator_index: ValidatorIndex): auto =
let epoch = slot_to_epoch(state.slot)
var cache = get_empty_per_epoch_cache()
for shard in 0'u64 ..< get_epoch_committee_count(state, epoch):
let committee = get_crosslink_committee(state, epoch,
(shard + get_epoch_start_shard(state, epoch)) mod SHARD_COUNT, cache)
if validator_index in committee:
return (committee, shard)
doAssert false
proc makeAttestation*(
state: BeaconState, beacon_block_root: Eth2Digest,
validator_index: ValidatorIndex, flags: UpdateFlags = {}): Attestation =
let
sac = find_shard_committee(
get_crosslink_committees_at_slot(state, state.slot), validator_index)
(committee, shard) = find_shard_committee(state, validator_index)
validator = state.validator_registry[validator_index]
sac_index = sac.committee.find(validator_index)
data = makeAttestationData(state, sac.shard, beacon_block_root)
sac_index = committee.find(validator_index)
data = makeAttestationData(state, shard, beacon_block_root)
doAssert sac_index != -1, "find_shard_committe should guarantee this"
doAssert sac_index != -1, "find_shard_committee should guarantee this"
var
aggregation_bitfield = BitField.init(sac.committee.len)
aggregation_bitfield = BitField.init(committee.len)
set_bitfield_bit(aggregation_bitfield, sac_index)
let
@ -177,7 +185,7 @@ proc makeAttestation*(
data: data,
aggregation_bitfield: aggregation_bitfield,
signature: sig,
custody_bitfield: BitField.init(sac.committee.len)
custody_bitfield: BitField.init(committee.len)
)
proc makeTestDB*(tailState: BeaconState, tailBlock: BeaconBlock): BeaconChainDB =