more checking that various functions match v0.1; some variable/etc renaming; fix is_double_vote to check epoch, not slot equivalence; finish verify_slashable_attestation; adjust is_surround_vote logic (#100)
This commit is contained in:
parent
c567bc410f
commit
4747477160
|
@ -10,11 +10,10 @@ import
|
|||
../extras, ../ssz,
|
||||
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_effective_balance
|
||||
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
|
||||
# Validators collect rewards which increases their balance but not their
|
||||
# influence. Validators may also lose balance if they fail to do their duty
|
||||
# in which case their influence decreases. Once they drop below a certain
|
||||
# balance, they're removed from the validator registry.
|
||||
## Return the effective balance (also known as "balance at stake") for a
|
||||
## validator with the given ``index``.
|
||||
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||
|
||||
func sum_effective_balances*(
|
||||
|
@ -82,6 +81,7 @@ func process_deposit(state: var BeaconState,
|
|||
|
||||
state.validator_balances[index] += amount
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_entry_exit_effect_epoch
|
||||
func get_entry_exit_effect_epoch*(epoch: EpochNumber): EpochNumber =
|
||||
## An entry or exit triggered in the ``epoch`` given by the input takes effect at
|
||||
## the epoch given by the output.
|
||||
|
@ -222,13 +222,15 @@ func get_block_root*(state: BeaconState,
|
|||
doAssert slot < state.slot
|
||||
state.latest_block_roots[slot mod LATEST_BLOCK_ROOTS_LENGTH]
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_attestation_participants
|
||||
func get_attestation_participants*(state: BeaconState,
|
||||
attestation_data: AttestationData,
|
||||
aggregation_bitfield: seq[byte]): seq[ValidatorIndex] =
|
||||
bitfield: seq[byte]): seq[ValidatorIndex] =
|
||||
## Attestation participants in the attestation data are called out in a
|
||||
## bit field that corresponds to the committee of the shard at the time - this
|
||||
## function converts it to list of indices in to BeaconState.validators
|
||||
## Returns empty list if the shard is not found
|
||||
## Return the participant indices at for the ``attestation_data`` and ``bitfield``.
|
||||
# TODO Linear search through shard list? borderline ok, it's a small list
|
||||
# TODO bitfield type needed, once bit order settles down
|
||||
# TODO iterator candidate
|
||||
|
@ -243,12 +245,13 @@ func get_attestation_participants*(state: BeaconState,
|
|||
let crosslink_committee = mapIt(
|
||||
filterIt(crosslink_committees, it.shard == attestation_data.shard),
|
||||
it.committee)[0]
|
||||
assert len(aggregation_bitfield) == (len(crosslink_committee) + 7) div 8
|
||||
|
||||
assert verify_bitfield(bitfield, len(crosslink_committee))
|
||||
|
||||
# Find the participating attesters in the committee
|
||||
result = @[]
|
||||
for i, validator_index in crosslink_committee:
|
||||
let aggregation_bit = (aggregation_bitfield[i div 8] shr (7 - (i mod 8))) mod 2
|
||||
let aggregation_bit = get_bitfield_bit(bitfield, i)
|
||||
if aggregation_bit == 1:
|
||||
result.add(validator_index)
|
||||
|
||||
|
|
|
@ -73,14 +73,25 @@ func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
|
|||
else:
|
||||
result.combine(key)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/bls_signature.md#bls_verify
|
||||
func bls_verify*(
|
||||
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
||||
domain: uint64): bool =
|
||||
# name from spec!
|
||||
sig.verify(msg, domain, pubkey)
|
||||
|
||||
func bls_sign*(key: ValidatorPrivKey,
|
||||
msg: openarray[byte], domain: uint64): ValidatorSig =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/bls_signature.md#bls_verify_multiple
|
||||
func bls_verify_multiple*(
|
||||
pubkeys: seq[ValidatorPubKey], messages: seq[array[0..31, byte]],
|
||||
sig: ValidatorSig, domain: uint64): bool =
|
||||
let L = len(pubkeys)
|
||||
assert L == len(messages)
|
||||
|
||||
# TODO calculate product of ate pairings; check how sig.verify works
|
||||
true
|
||||
|
||||
func bls_sign*(key: ValidatorPrivKey, msg: openarray[byte],
|
||||
domain: uint64): ValidatorSig =
|
||||
# name from spec!
|
||||
key.sign(domain, msg)
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ type
|
|||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#attestationdata
|
||||
AttestationDataAndCustodyBit* = object
|
||||
data*: AttestationData
|
||||
custody_bit: bool
|
||||
custody_bit*: bool
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#deposit
|
||||
Deposit* = object
|
||||
|
|
|
@ -14,13 +14,13 @@ import ./datatypes, ./digest, sequtils, math
|
|||
func bitSet*(bitfield: var openArray[byte], index: int) =
|
||||
bitfield[index div 8] = bitfield[index div 8] or 1'u8 shl (7 - (index mod 8))
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_bitfield_bit
|
||||
func get_bitfield_bit*(bitfield: openarray[byte], i: int): byte =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#get_bitfield_bit
|
||||
# Extract the bit in ``bitfield`` at position ``i``.
|
||||
(bitfield[i div 8] shr (7 - (i mod 8))) mod 2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#verify_bitfield
|
||||
func verify_bitfield*(bitfield: openarray[byte], committee_size: int): bool =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#verify_bitfield
|
||||
# Verify ``bitfield`` against the ``committee_size``.
|
||||
if len(bitfield) != (committee_size + 7) div 8:
|
||||
return false
|
||||
|
@ -113,6 +113,7 @@ func repeat_hash*(v: Eth2Digest, n: SomeInteger): Eth2Digest =
|
|||
result = eth2hash(result.data)
|
||||
dec n
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#integer_squareroot
|
||||
func integer_squareroot*(n: SomeInteger): SomeInteger =
|
||||
## The largest integer ``x`` such that ``x**2`` is less than ``n``.
|
||||
var
|
||||
|
@ -123,12 +124,15 @@ func integer_squareroot*(n: SomeInteger): SomeInteger =
|
|||
y = (x + n div x) div 2
|
||||
x
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_fork_version
|
||||
func get_fork_version*(fork: Fork, epoch: EpochNumber): uint64 =
|
||||
## Return the fork version of the given ``epoch``.
|
||||
if epoch < fork.epoch:
|
||||
fork.previous_version
|
||||
else:
|
||||
fork.current_version
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_domain
|
||||
func get_domain*(
|
||||
fork: Fork, epoch: EpochNumber, domain_type: SignatureDomain): uint64 =
|
||||
# TODO Slot overflow? Or is slot 32 bits for all intents and purposes?
|
||||
|
@ -151,37 +155,31 @@ func merkle_root*(values: openArray[Eth2Digest]): Eth2Digest =
|
|||
#TODO
|
||||
discard
|
||||
|
||||
proc is_double_vote*(attestation_data_1: AttestationData,
|
||||
attestation_data_2: AttestationData): bool =
|
||||
## Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``.
|
||||
## Returns True if the provided ``AttestationData`` are slashable
|
||||
## due to a 'double vote'.
|
||||
## A double vote is when a validator votes for two attestations within the
|
||||
## same slot - doing so means risking getting slashed.
|
||||
attestation_data_1.slot == attestation_data_2.slot
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#slot_to_epoch
|
||||
func slot_to_epoch*(slot: SlotNumber): EpochNumber =
|
||||
slot div EPOCH_LENGTH
|
||||
|
||||
proc is_surround_vote*(attestation_data_1: AttestationData,
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#is_double_vote
|
||||
func is_double_vote*(attestation_data_1: AttestationData,
|
||||
attestation_data_2: AttestationData): bool =
|
||||
## Check if ``attestation_data_1`` and ``attestation_data_2`` have the same
|
||||
## target.
|
||||
let
|
||||
target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
||||
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||
target_epoch_1 == target_epoch_2
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#is_surround_vote
|
||||
func is_surround_vote*(attestation_data_1: AttestationData,
|
||||
attestation_data_2: AttestationData): bool =
|
||||
## Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``.
|
||||
## Returns True if the provided ``AttestationData`` are slashable
|
||||
## due to a 'surround vote'.
|
||||
## Note: parameter order matters as this function only checks
|
||||
## that ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
## Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
let
|
||||
source_epoch_1 = attestation_data_1.justified_epoch
|
||||
source_epoch_2 = attestation_data_2.justified_epoch
|
||||
target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
||||
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||
|
||||
(
|
||||
(source_epoch_1 < source_epoch_2) and
|
||||
(source_epoch_2 + 1 == target_epoch_2) and
|
||||
(target_epoch_2 < target_epoch_1)
|
||||
)
|
||||
source_epoch_1 < source_epoch_2 and target_epoch_2 < target_epoch_1
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#is_active_validator
|
||||
func is_active_validator*(validator: Validator, epoch: EpochNumber): bool =
|
||||
|
|
|
@ -184,8 +184,8 @@ proc processProposerSlashings(
|
|||
|
||||
return true
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#verify_slashable_attestation
|
||||
func verify_slashable_attestation(state: BeaconState, slashable_attestation: SlashableAttestation): bool =
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#verify_slashable_attestation
|
||||
# Verify validity of ``slashable_attestation`` fields.
|
||||
|
||||
if anyIt(slashable_attestation.custody_bitfield, it != 0): # [TO BE REMOVED IN PHASE 1]
|
||||
|
@ -208,7 +208,31 @@ func verify_slashable_attestation(state: BeaconState, slashable_attestation: Sla
|
|||
custody_bit_0_indices: seq[uint64] = @[]
|
||||
custody_bit_1_indices: seq[uint64] = @[]
|
||||
|
||||
return true
|
||||
for i, validator_index in slashable_attestation.validator_indices:
|
||||
if get_bitfield_bit(slashable_attestation.custody_bitfield, i) == 0b0:
|
||||
custody_bit_0_indices.add(validator_index)
|
||||
else:
|
||||
custody_bit_1_indices.add(validator_index)
|
||||
|
||||
# bug in 0.1 version of spec, fixed later; bls_verify is what works
|
||||
bls_verify_multiple(
|
||||
@[
|
||||
bls_aggregate_pubkeys(mapIt(custody_bit_0_indices, state.validator_registry[it.int].pubkey)),
|
||||
bls_aggregate_pubkeys(mapIt(custody_bit_1_indices, state.validator_registry[it.int].pubkey)),
|
||||
],
|
||||
@[
|
||||
hash_tree_root(AttestationDataAndCustodyBit(
|
||||
data: slashable_attestation.data, custody_bit: false)),
|
||||
hash_tree_root(AttestationDataAndCustodyBit(
|
||||
data: slashable_attestation.data, custody_bit: true)),
|
||||
],
|
||||
slashable_attestation.aggregate_signature,
|
||||
get_domain(
|
||||
state.fork,
|
||||
slot_to_epoch(slashable_attestation.data.slot),
|
||||
DOMAIN_ATTESTATION,
|
||||
),
|
||||
)
|
||||
|
||||
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||
## https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#attester-slashings-1
|
||||
|
|
Loading…
Reference in New Issue