state_sim: clean up attestation production (#3274)

* use same naming as everywhere
* avoid iterator bug that leads to state copy
This commit is contained in:
Jacek Sieka 2022-01-12 21:42:03 +01:00 committed by GitHub
parent 14aab2c13f
commit e9486f5e5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 93 deletions

View File

@ -459,7 +459,9 @@ func init(
template update_attestation_pool_cache(
epoch: Epoch, participation_bitmap: untyped) =
for committee_index in get_committee_indices(state.data, epoch, cache):
let committees_per_slot = get_committee_count_per_slot(
state.data, epoch, cache)
for committee_index in get_committee_indices(committees_per_slot):
for slot in epoch.slots():
let committee = get_beacon_committee(
state.data, slot, committee_index, cache)

View File

@ -572,17 +572,15 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
proc forSlot(slot: Slot, cindex: Option[CommitteeIndex],
res: var seq[RestBeaconStatesCommittees]) =
let committees_per_slot = get_committee_count_per_slot(
stateData.data, slot.epoch, cache)
if cindex.isNone:
for committee_index in
get_committee_indices(stateData.data, slot.epoch, cache):
for committee_index in get_committee_indices(committees_per_slot):
res.add(getCommittee(slot, committee_index))
else:
let
idx = cindex.get()
committees_per_slot = get_committee_count_per_slot(
stateData.data, slot.epoch, cache)
if idx < committees_per_slot:
res.add(getCommittee(slot, idx))

View File

@ -184,15 +184,6 @@ iterator get_committee_indices*(committee_count_per_slot: uint64): CommitteeInde
let committee_index = CommitteeIndex.init(idx).expect("value clamped")
yield committee_index
iterator get_committee_indices*(state: ForkyBeaconState | ForkedHashedBeaconState,
epoch: Epoch,
cache: var StateCache): CommitteeIndex =
let committee_count_per_slot =
get_committee_count_per_slot(state, epoch, cache)
for committee_index in get_committee_indices(committee_count_per_slot):
yield committee_index
func get_previous_epoch*(state: ForkyBeaconState): Epoch =
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).

View File

@ -9,20 +9,18 @@
# and attesting to them as if the network was running as a whole.
import
confutils, stats, times,
strformat,
options, sequtils, random, tables,
std/[stats, times, strformat, random, tables],
confutils,
../tests/testblockutil,
../beacon_chain/spec/datatypes/phase0,
../beacon_chain/spec/eth2_apis/eth2_rest_serialization,
../beacon_chain/spec/[beaconstate, forks, helpers],
../beacon_chain/spec/[beaconstate, forks, helpers, signatures],
./simutils
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_beacon_committee"
tAttest = "Combine committee attestations"
func jsonName(prefix, slot: auto): string =
@ -44,6 +42,7 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
flags = if validate: {} else: {skipBlsValidation}
(state, _) = loadGenesis(validators, validate)
genesisBlock = get_initial_beacon_block(state[])
genesis_validators_root = getStateField(state[], genesis_validators_root)
echo "Starting simulation..."
@ -105,56 +104,44 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
# attesterRatio is the fraction of attesters that actually do their
# work for every slot - we'll randomize it deterministically to give
# some variation
let
target_slot = getStateField(state[], slot) + MIN_ATTESTATION_INCLUSION_DELAY - 1
committees_per_slot =
get_committee_count_per_slot(state[], target_slot.epoch, cache)
let
scass = withTimerRet(timers[tShuffle]):
mapIt(
0 ..< committees_per_slot.int,
get_beacon_committee(state[], target_slot, it.CommitteeIndex, cache))
withState(state[]):
let
slot = state.data.slot
epoch = slot.epoch
committees_per_slot =
get_committee_count_per_slot(state.data, epoch, cache)
for committee_index in get_committee_indices(committees_per_slot):
let committee = get_beacon_committee(
state.data, slot, committee_index, cache)
var
attestation = Attestation(
aggregation_bits: CommitteeValidatorsBits.init(committee.len),
data: makeAttestationData(
state.data, slot, committee_index, latest_block_root),
)
first = true
for i, scas in scass:
var
attestation: Attestation
first = true
attesters.push committee.len()
attesters.push scas.len()
withTimer(timers[tAttest]):
for index_in_committee, validator_index in committee:
if (rand(r, high(int)).float * attesterRatio).int <= high(int):
attestation.aggregation_bits.setBit index_in_committee
withTimer(timers[tAttest]):
var agg {.noInit.}: AggregateSignature
for v in scas:
if (rand(r, high(int)).float * attesterRatio).int <= high(int):
if first:
attestation =
makeAttestation(state[], latest_block_root, scas, target_slot,
i.CommitteeIndex, v, cache, flags)
agg.init(attestation.signature.load.get())
first = false
else:
let att2 =
makeAttestation(state[], latest_block_root, scas, target_slot,
i.CommitteeIndex, v, cache, flags)
if not att2.aggregation_bits.overlaps(attestation.aggregation_bits):
attestation.aggregation_bits.incl(att2.aggregation_bits)
if skipBlsValidation notin flags:
agg.aggregate(att2.signature.load.get())
attestation.signature = agg.finish().toValidatorSig()
if attestation.aggregation_bits.countOnes() > 0:
if validate:
attestation.signature = makeAttestationSig(
state.data.fork, genesis_validators_root, attestation.data,
committee, attestation.aggregation_bits)
if not first:
# add the attestation if any of the validators attested, as given
# by the randomness. We have to delay when the attestation is
# actually added to the block per the attestation delay rule!
let target_slot =
attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY - 1
doAssert target_slot > attestations_idx
var target_slot_attestations =
getOrDefault(attestations, target_slot)
target_slot_attestations.add attestation
attestations[target_slot] = target_slot_attestations
# add the attestation if any of the validators attested, as given
# by the randomness. We have to delay when the attestation is
# actually added to the block per the attestation delay rule!
let
target_slot = slot + MIN_ATTESTATION_INCLUSION_DELAY - 1
attestations.mGetOrPut(target_slot, default(seq[Attestation])).add(
attestation)
flushFile(stdout)
@ -167,4 +154,4 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
echo "Done!"
printTimers(state[], attesters, validate, timers)
printTimers(state[], attesters, true, timers)

View File

@ -178,6 +178,32 @@ func makeAttestationData*(
)
)
func makeAttestationSig*(
fork: Fork, genesis_validators_root: Eth2Digest, data: AttestationData,
committee: openArray[ValidatorIndex],
bits: CommitteeValidatorsBits): ValidatorSig =
let signing_root = compute_attestation_signing_root(
fork, genesis_validators_root, data)
var
agg {.noInit.}: AggregateSignature
first = true
for i in 0..<bits.len():
if not bits[i]: continue
let sig = blsSign(MockPrivKeys[committee[i]], signing_root.data)
if first:
agg.init(sig)
first = false
else:
agg.aggregate(sig)
if first:
ValidatorSig.infinity()
else:
agg.finish().toValidatorSig()
func makeAttestationData*(
state: ForkedHashedBeaconState, slot: Slot, committee_index: CommitteeIndex,
beacon_block_root: Eth2Digest): AttestationData =
@ -206,15 +232,13 @@ func makeAttestation*(
var aggregation_bits = CommitteeValidatorsBits.init(committee.len)
aggregation_bits.setBit sac_index
let
sig =
if skipBLSValidation notin flags:
get_attestation_signature(
getStateField(state, fork),
getStateField(state, genesis_validators_root),
data, MockPrivKeys[validator_index]).toValidatorSig()
else:
ValidatorSig()
let sig = if skipBLSValidation in flags:
ValidatorSig()
else:
makeAttestationSig(
getStateField(state, fork),
getStateField(state, genesis_validators_root),
data, committee, aggregation_bits)
Attestation(
data: data,
@ -251,35 +275,25 @@ func makeFullAttestations*(
flags: UpdateFlags = {}): seq[Attestation] =
# Create attestations in which the full committee participates for each shard
# that should be attested to during a particular slot
for committee_index in get_committee_indices(state, slot.epoch, cache):
let committees_per_slot = get_committee_count_per_slot(
state, slot.epoch, cache)
for committee_index in get_committee_indices(committees_per_slot):
let
committee = get_beacon_committee(state, slot, committee_index, cache)
data = makeAttestationData(state, slot, committee_index, beacon_block_root)
doAssert committee.len() >= 1
# Initial attestation
var attestation = Attestation(
aggregation_bits: CommitteeValidatorsBits.init(committee.len),
data: data)
for i in 0..<committee.len:
attestation.aggregation_bits.setBit(i)
var agg {.noInit.}: AggregateSignature
agg.init(get_attestation_signature(
attestation.signature = makeAttestationSig(
getStateField(state, fork),
getStateField(state, genesis_validators_root), data,
MockPrivKeys[committee[0]]))
getStateField(state, genesis_validators_root), data, committee,
attestation.aggregation_bits)
# Aggregate the remainder
attestation.aggregation_bits.setBit 0
for j in 1 ..< committee.len():
attestation.aggregation_bits.setBit j
if skipBLSValidation notin flags:
agg.aggregate(get_attestation_signature(
getStateField(state, fork),
getStateField(state, genesis_validators_root), data,
MockPrivKeys[committee[j]]
))
attestation.signature = agg.finish().toValidatorSig()
result.add attestation
proc makeSyncAggregate(