diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index 0186c3f559..dd73eb860c 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -265,31 +265,23 @@ proc makeAttestation(node: BeaconNode, var state = node.state.data skipSlots(state, node.state.blck.root, slot) - let - justifiedBlockRoot = - get_block_root(state, get_epoch_start_slot(state.justified_epoch)) - - attestationData = AttestationData( - slot: slot, - shard: shard, - beacon_block_root: node.state.blck.root, - epoch_boundary_root: Eth2Digest(), # TODO - crosslink_data_root: Eth2Digest(), # TODO - latest_crosslink: state.latest_crosslinks[shard], - justified_epoch: state.justified_epoch, - justified_block_root: justifiedBlockRoot) + # If we call makeAttestation too late, we must advance head only to `slot` + doAssert state.slot == slot, + "Corner case: head advanced beyond sheduled attestation slot" + let + attestationData = makeAttestationData(state, shard, node.state.blck.root) validatorSignature = await validator.signAttestation(attestationData) - var participationBitfield = repeat(0'u8, ceil_div8(committeeLen)) - bitSet(participationBitfield, indexInCommittee) + var aggregationBitfield = repeat(0'u8, ceil_div8(committeeLen)) + bitSet(aggregationBitfield, indexInCommittee) var attestation = Attestation( data: attestationData, aggregate_signature: validatorSignature, - aggregation_bitfield: participationBitfield, + aggregation_bitfield: aggregationBitfield, # Stub in phase0 - custody_bitfield: newSeq[byte](participationBitfield.len) + custody_bitfield: newSeq[byte](aggregationBitfield.len) ) # TODO what are we waiting for here? broadcast should never block, and never diff --git a/beacon_chain/block_pool.nim b/beacon_chain/block_pool.nim index afb169a3ff..1ae68b5c0f 100644 --- a/beacon_chain/block_pool.nim +++ b/beacon_chain/block_pool.nim @@ -247,6 +247,15 @@ proc add*( return true # This is an unresolved block - put it on the unresolved list for now... + # TODO if we receive spam blocks, one heurestic to implement might be to wait + # for a couple of attestations to appear before fetching parents - this + # would help prevent using up network resources for spam - this serves + # two purposes: one is that attestations are likely to appear for the + # block only if it's valid / not spam - the other is that malicious + # validators that are not proposers can sign invalid blocks and send + # them out without penalty - but signing invalid attestations carries + # a risk of being slashed, making attestations a more valuable spam + # filter. debug "Unresolved block", slot = humaneSlotNum(blck.slot), stateRoot = shortLog(blck.state_root), @@ -322,7 +331,7 @@ proc maybePutState(pool: BlockPool, state: BeaconState) = if state.slot mod SLOTS_PER_EPOCH == 0: info "Storing state", stateSlot = humaneSlotNum(state.slot), - stateRoot = hash_tree_root_final(state) # TODO cache? + stateRoot = shortLog(hash_tree_root_final(state)) # TODO cache? pool.db.putState(state) proc updateState*( diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 90d990712d..414d0cb711 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -279,14 +279,15 @@ func get_attestation_participants*(state: BeaconState, ## ``bitfield``. let crosslink_committees = get_crosslink_committees_at_slot( state, attestation_data.slot) - - assert anyIt( + doAssert anyIt( crosslink_committees, it[1] == attestation_data.shard) let crosslink_committee = mapIt( filterIt(crosslink_committees, it.shard == attestation_data.shard), it.committee)[0] + # TODO this and other attestation-based fields need validation so we don't + # crash on a malicious attestation! doAssert verify_bitfield(bitfield, len(crosslink_committee)) # Find the participating attesters in the committee @@ -493,3 +494,31 @@ func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorI # Bug in 0.3.0 spec; constant got renamed. Use 0.3.0 name. validator.withdrawable_epoch = get_current_epoch(state) + MIN_VALIDATOR_WITHDRAWABILITY_DELAY + +# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/validator/0_beacon-chain-validator.md#attestations-1 +proc makeAttestationData*( + state: BeaconState, shard: uint64, + beacon_block_root: Eth2Digest): AttestationData = + ## Fine points: + ## Head must be the head state during the slot that validator is + ## part of committee - notably, it can't be a newer or older state (!) + + # TODO update when https://github.com/ethereum/eth2.0-specs/issues/742 + let + epoch_start_slot = get_epoch_start_slot(slot_to_epoch(state.slot)) + epoch_boundary_root = + if epoch_start_slot == state.slot: beacon_block_root + else: get_block_root(state, epoch_start_slot) + justified_slot = get_epoch_start_slot(state.justified_epoch) + justified_block_root = get_block_root(state, justified_slot) + + AttestationData( + slot: state.slot, + shard: shard, + beacon_block_root: beacon_block_root, + epoch_boundary_root: epoch_boundary_root, + crosslink_data_root: Eth2Digest(), # Stub in phase0 + latest_crosslink: state.latest_crosslinks[shard], + justified_epoch: state.justified_epoch, + justified_block_root: justified_block_root, + ) diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 6223167cd8..752793e796 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -180,7 +180,7 @@ func get_current_epoch_committee_count*(state: BeaconState): uint64 = # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#get_current_epoch func get_current_epoch*(state: BeaconState): Epoch = # Return the current epoch of the given ``state``. - doAssert state.slot >= GENESIS_SLOT, $state.slot + doAssert state.slot >= GENESIS_SLOT, $state.slot slot_to_epoch(state.slot) # https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#get_randao_mix diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index b85ba25c82..5c0f5b9da2 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -134,17 +134,20 @@ func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot, ## ``slot`` in the next epoch -- with and without a `registry_change` let - epoch = slot_to_epoch(slot) + # TODO: the + 1 here works around a bug, remove when upgrading to + # some more recent version: + # https://github.com/ethereum/eth2.0-specs/pull/732 + epoch = slot_to_epoch(slot + 1) current_epoch = get_current_epoch(state) previous_epoch = get_previous_epoch(state) next_epoch = current_epoch + 1 - assert previous_epoch <= epoch, + doAssert previous_epoch <= epoch, "Previous epoch: " & $humaneEpochNum(previous_epoch) & ", epoch: " & $humaneEpochNum(epoch) & ", Next epoch: " & $humaneEpochNum(next_epoch) - assert epoch <= next_epoch, + doAssert epoch <= next_epoch, "Previous epoch: " & $humaneEpochNum(previous_epoch) & ", epoch: " & $humaneEpochNum(epoch) & ", Next epoch: " & $humaneEpochNum(next_epoch) @@ -170,7 +173,7 @@ func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot, shuffling_start_shard = state.current_shuffling_start_shard (committees_per_epoch, seed, shuffling_epoch, shuffling_start_shard) else: - assert epoch == next_epoch + doAssert epoch == next_epoch let current_committees_per_epoch = get_current_epoch_committee_count(state) diff --git a/beacon_chain/time.nim b/beacon_chain/time.nim index 76b34c55df..a5b7257394 100644 --- a/beacon_chain/time.nim +++ b/beacon_chain/time.nim @@ -21,7 +21,7 @@ proc getSlotFromTime*(s: BeaconState, t = now()): Slot = int64(SECONDS_PER_SLOT * 1000)) func slotStart*(s: BeaconState, slot: Slot): Timestamp = - (s.genesis_time + (slot * SECONDS_PER_SLOT)) * 1000 + (s.genesis_time + ((slot - GENESIS_SLOT) * SECONDS_PER_SLOT)) * 1000 func slotMiddle*(s: BeaconState, slot: Slot): Timestamp = s.slotStart(slot) + SECONDS_PER_SLOT * 500 diff --git a/tests/simulation/start.sh b/tests/simulation/start.sh index 4a7da023be..d67a9a2de4 100755 --- a/tests/simulation/start.sh +++ b/tests/simulation/start.sh @@ -37,7 +37,7 @@ if [ ! -f $LAST_VALIDATOR ]; then fi if [[ -z "$SKIP_BUILDS" ]]; then - nim c -o:"$BEACON_NODE_BIN" $DEFS --opt:speed beacon_chain/beacon_node + nim c -o:"$BEACON_NODE_BIN" $DEFS --opt:speed --debuginfo beacon_chain/beacon_node fi if [ ! -f $SNAPSHOT_FILE ]; then diff --git a/tests/testutil.nim b/tests/testutil.nim index fc84c3714a..36b8395c97 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -168,17 +168,7 @@ proc makeAttestation*( get_crosslink_committees_at_slot(state, state.slot), validator_index) validator = state.validator_registry[validator_index] sac_index = sac.committee.find(validator_index) - - data = AttestationData( - slot: state.slot, - shard: sac.shard, - beacon_block_root: beacon_block_root, - epoch_boundary_root: Eth2Digest(), # TODO - latest_crosslink: state.latest_crosslinks[sac.shard], - crosslink_data_root: Eth2Digest(), # TODO - justified_epoch: state.justified_epoch, - justified_block_root: get_block_root(state, get_epoch_start_slot(state.justified_epoch)), - ) + data = makeAttestationData(state, sac.shard, beacon_block_root) assert sac_index != -1, "find_shard_committe should guarantee this" @@ -187,7 +177,8 @@ proc makeAttestation*( bitSet(aggregation_bitfield, sac_index) let - msg = hash_tree_root_final(AttestationDataAndCustodyBit(data: data, custody_bit: false)) + msg = hash_tree_root_final( + AttestationDataAndCustodyBit(data: data, custody_bit: false)) sig = if skipValidation notin flags: bls_sign( @@ -203,7 +194,7 @@ proc makeAttestation*( data: data, aggregation_bitfield: aggregation_bitfield, aggregate_signature: sig, - custody_bitfield: repeat(0'u8, ceil_div8(sac.committee.len)) + custody_bitfield: repeat(0'u8, aggregation_bitfield.len) ) proc makeTestDB*(tailState: BeaconState, tailBlock: BeaconBlock): BeaconChainDB =