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,
|
../extras, ../ssz,
|
||||||
./crypto, ./datatypes, ./digest, ./helpers, ./validator
|
./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 =
|
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
|
||||||
# Validators collect rewards which increases their balance but not their
|
## Return the effective balance (also known as "balance at stake") for a
|
||||||
# influence. Validators may also lose balance if they fail to do their duty
|
## validator with the given ``index``.
|
||||||
# in which case their influence decreases. Once they drop below a certain
|
|
||||||
# balance, they're removed from the validator registry.
|
|
||||||
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||||
|
|
||||||
func sum_effective_balances*(
|
func sum_effective_balances*(
|
||||||
|
@ -82,6 +81,7 @@ func process_deposit(state: var BeaconState,
|
||||||
|
|
||||||
state.validator_balances[index] += amount
|
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 =
|
func get_entry_exit_effect_epoch*(epoch: EpochNumber): EpochNumber =
|
||||||
## An entry or exit triggered in the ``epoch`` given by the input takes effect at
|
## An entry or exit triggered in the ``epoch`` given by the input takes effect at
|
||||||
## the epoch given by the output.
|
## the epoch given by the output.
|
||||||
|
@ -222,13 +222,15 @@ func get_block_root*(state: BeaconState,
|
||||||
doAssert slot < state.slot
|
doAssert slot < state.slot
|
||||||
state.latest_block_roots[slot mod LATEST_BLOCK_ROOTS_LENGTH]
|
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,
|
func get_attestation_participants*(state: BeaconState,
|
||||||
attestation_data: AttestationData,
|
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
|
## 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
|
## 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
|
## function converts it to list of indices in to BeaconState.validators
|
||||||
## Returns empty list if the shard is not found
|
## 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 Linear search through shard list? borderline ok, it's a small list
|
||||||
# TODO bitfield type needed, once bit order settles down
|
# TODO bitfield type needed, once bit order settles down
|
||||||
# TODO iterator candidate
|
# TODO iterator candidate
|
||||||
|
@ -243,12 +245,13 @@ func get_attestation_participants*(state: BeaconState,
|
||||||
let crosslink_committee = mapIt(
|
let crosslink_committee = mapIt(
|
||||||
filterIt(crosslink_committees, it.shard == attestation_data.shard),
|
filterIt(crosslink_committees, it.shard == attestation_data.shard),
|
||||||
it.committee)[0]
|
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
|
# Find the participating attesters in the committee
|
||||||
result = @[]
|
result = @[]
|
||||||
for i, validator_index in crosslink_committee:
|
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:
|
if aggregation_bit == 1:
|
||||||
result.add(validator_index)
|
result.add(validator_index)
|
||||||
|
|
||||||
|
|
|
@ -73,14 +73,25 @@ func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
|
||||||
else:
|
else:
|
||||||
result.combine(key)
|
result.combine(key)
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/bls_signature.md#bls_verify
|
||||||
func bls_verify*(
|
func bls_verify*(
|
||||||
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
|
||||||
domain: uint64): bool =
|
domain: uint64): bool =
|
||||||
# name from spec!
|
# name from spec!
|
||||||
sig.verify(msg, domain, pubkey)
|
sig.verify(msg, domain, pubkey)
|
||||||
|
|
||||||
func bls_sign*(key: ValidatorPrivKey,
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/bls_signature.md#bls_verify_multiple
|
||||||
msg: openarray[byte], domain: uint64): ValidatorSig =
|
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!
|
# name from spec!
|
||||||
key.sign(domain, msg)
|
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
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#attestationdata
|
||||||
AttestationDataAndCustodyBit* = object
|
AttestationDataAndCustodyBit* = object
|
||||||
data*: AttestationData
|
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
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#deposit
|
||||||
Deposit* = object
|
Deposit* = object
|
||||||
|
|
|
@ -14,13 +14,13 @@ import ./datatypes, ./digest, sequtils, math
|
||||||
func bitSet*(bitfield: var openArray[byte], index: int) =
|
func bitSet*(bitfield: var openArray[byte], index: int) =
|
||||||
bitfield[index div 8] = bitfield[index div 8] or 1'u8 shl (7 - (index mod 8))
|
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 =
|
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``.
|
# Extract the bit in ``bitfield`` at position ``i``.
|
||||||
(bitfield[i div 8] shr (7 - (i mod 8))) mod 2
|
(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 =
|
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``.
|
# Verify ``bitfield`` against the ``committee_size``.
|
||||||
if len(bitfield) != (committee_size + 7) div 8:
|
if len(bitfield) != (committee_size + 7) div 8:
|
||||||
return false
|
return false
|
||||||
|
@ -113,6 +113,7 @@ func repeat_hash*(v: Eth2Digest, n: SomeInteger): Eth2Digest =
|
||||||
result = eth2hash(result.data)
|
result = eth2hash(result.data)
|
||||||
dec n
|
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 =
|
func integer_squareroot*(n: SomeInteger): SomeInteger =
|
||||||
## The largest integer ``x`` such that ``x**2`` is less than ``n``.
|
## The largest integer ``x`` such that ``x**2`` is less than ``n``.
|
||||||
var
|
var
|
||||||
|
@ -123,12 +124,15 @@ func integer_squareroot*(n: SomeInteger): SomeInteger =
|
||||||
y = (x + n div x) div 2
|
y = (x + n div x) div 2
|
||||||
x
|
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 =
|
func get_fork_version*(fork: Fork, epoch: EpochNumber): uint64 =
|
||||||
|
## Return the fork version of the given ``epoch``.
|
||||||
if epoch < fork.epoch:
|
if epoch < fork.epoch:
|
||||||
fork.previous_version
|
fork.previous_version
|
||||||
else:
|
else:
|
||||||
fork.current_version
|
fork.current_version
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.1/specs/core/0_beacon-chain.md#get_domain
|
||||||
func get_domain*(
|
func get_domain*(
|
||||||
fork: Fork, epoch: EpochNumber, domain_type: SignatureDomain): uint64 =
|
fork: Fork, epoch: EpochNumber, domain_type: SignatureDomain): uint64 =
|
||||||
# TODO Slot overflow? Or is slot 32 bits for all intents and purposes?
|
# 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
|
#TODO
|
||||||
discard
|
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
|
# 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 =
|
func slot_to_epoch*(slot: SlotNumber): EpochNumber =
|
||||||
slot div EPOCH_LENGTH
|
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 =
|
attestation_data_2: AttestationData): bool =
|
||||||
## Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``.
|
## Check if ``attestation_data_1`` surrounds ``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``.
|
|
||||||
let
|
let
|
||||||
source_epoch_1 = attestation_data_1.justified_epoch
|
source_epoch_1 = attestation_data_1.justified_epoch
|
||||||
source_epoch_2 = attestation_data_2.justified_epoch
|
source_epoch_2 = attestation_data_2.justified_epoch
|
||||||
target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
target_epoch_1 = slot_to_epoch(attestation_data_1.slot)
|
||||||
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||||
|
|
||||||
(
|
source_epoch_1 < source_epoch_2 and target_epoch_2 < target_epoch_1
|
||||||
(source_epoch_1 < source_epoch_2) and
|
|
||||||
(source_epoch_2 + 1 == target_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
|
# 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 =
|
func is_active_validator*(validator: Validator, epoch: EpochNumber): bool =
|
||||||
|
|
|
@ -184,8 +184,8 @@ proc processProposerSlashings(
|
||||||
|
|
||||||
return true
|
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 =
|
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.
|
# Verify validity of ``slashable_attestation`` fields.
|
||||||
|
|
||||||
if anyIt(slashable_attestation.custody_bitfield, it != 0): # [TO BE REMOVED IN PHASE 1]
|
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_0_indices: seq[uint64] = @[]
|
||||||
custody_bit_1_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 =
|
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
|
## https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#attester-slashings-1
|
||||||
|
|
Loading…
Reference in New Issue