spec version 0.4.0 update: shard_block_root -> crosslink_data_root; switch from validator.slashed_epoch -> validator.slashed approach; a couple assert -> doAssert; note fix for underflow-prone spec changes in checkAttestation; GENESIS_SLOT change from 2^63 to 2^32; refactor Proposer and ProposalSlashing structure; add signed_root; remove duplicate slashValidator (#159)
* spec version 0.4.0 update: shard_block_root -> crosslink_data_root; switch from validator.slashed_epoch -> validator.slashed approach; a couple assert -> doAssert; note fix for underflow-prone spec changes in checkAttestation; GENESIS_SLOT change from 2^63 to 2^32; refactor Proposer and ProposalSlashing structure; add signed_root; remove duplicate slashValidator * re-apply shard_block_root -> crosslink_data_root * remove incorrect humaneSlotNum * add (run-time only, alas) sanity check on signed_root
This commit is contained in:
parent
6bcefc0e42
commit
1afdcda62d
|
@ -274,7 +274,7 @@ proc makeAttestation(node: BeaconNode,
|
||||||
shard: shard,
|
shard: shard,
|
||||||
beacon_block_root: node.state.blck.root,
|
beacon_block_root: node.state.blck.root,
|
||||||
epoch_boundary_root: Eth2Digest(), # TODO
|
epoch_boundary_root: Eth2Digest(), # TODO
|
||||||
shard_block_root: Eth2Digest(), # TODO
|
crosslink_data_root: Eth2Digest(), # TODO
|
||||||
latest_crosslink: state.latest_crosslinks[shard],
|
latest_crosslink: state.latest_crosslinks[shard],
|
||||||
justified_epoch: state.justified_epoch,
|
justified_epoch: state.justified_epoch,
|
||||||
justified_block_root: justifiedBlockRoot)
|
justified_block_root: justifiedBlockRoot)
|
||||||
|
|
|
@ -16,43 +16,25 @@ func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
|
||||||
## validator with the given ``index``.
|
## validator with the given ``index``.
|
||||||
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validate_proof_of_possession
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#process_deposit
|
||||||
func validate_proof_of_possession(state: BeaconState,
|
func process_deposit(state: var BeaconState, deposit: Deposit) =
|
||||||
pubkey: ValidatorPubKey,
|
|
||||||
proof_of_possession: ValidatorSig,
|
|
||||||
withdrawal_credentials: Eth2Digest): bool =
|
|
||||||
let proof_of_possession_data = DepositInput(
|
|
||||||
pubkey: pubkey,
|
|
||||||
withdrawal_credentials: withdrawal_credentials,
|
|
||||||
proof_of_possession: ValidatorSig(),
|
|
||||||
)
|
|
||||||
|
|
||||||
bls_verify(
|
|
||||||
pubkey,
|
|
||||||
hash_tree_root_final(proof_of_possession_data).data,
|
|
||||||
proof_of_possession,
|
|
||||||
get_domain(
|
|
||||||
state.fork,
|
|
||||||
get_current_epoch(state),
|
|
||||||
DOMAIN_DEPOSIT,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#process_deposit
|
|
||||||
func process_deposit(state: var BeaconState,
|
|
||||||
pubkey: ValidatorPubKey,
|
|
||||||
amount: Gwei,
|
|
||||||
proof_of_possession: ValidatorSig,
|
|
||||||
withdrawal_credentials: Eth2Digest) =
|
|
||||||
## Process a deposit from Ethereum 1.0.
|
## Process a deposit from Ethereum 1.0.
|
||||||
|
## Note that this function mutates ``state``.
|
||||||
|
|
||||||
if false:
|
let deposit_input = deposit.deposit_data.deposit_input
|
||||||
# TODO return error; currently, just fails if ever called
|
|
||||||
# but hadn't been set up to run at all
|
|
||||||
doAssert validate_proof_of_possession(
|
|
||||||
state, pubkey, proof_of_possession, withdrawal_credentials)
|
|
||||||
|
|
||||||
let validator_pubkeys = state.validator_registry.mapIt(it.pubkey)
|
## if not validate_proof_of_possession(
|
||||||
|
## state, pubkey, proof_of_possession, withdrawal_credentials):
|
||||||
|
## return
|
||||||
|
## TODO re-enable (but it wasn't running to begin with, and
|
||||||
|
## PoP isn't really a phase 0 concern, so this isn't meaningful
|
||||||
|
## regardless.
|
||||||
|
|
||||||
|
let
|
||||||
|
validator_pubkeys = state.validator_registry.mapIt(it.pubkey)
|
||||||
|
pubkey = deposit_input.pubkey
|
||||||
|
amount = deposit.deposit_data.amount
|
||||||
|
withdrawal_credentials = deposit_input.withdrawal_credentials
|
||||||
|
|
||||||
if pubkey notin validator_pubkeys:
|
if pubkey notin validator_pubkeys:
|
||||||
# Add new validator
|
# Add new validator
|
||||||
|
@ -62,8 +44,8 @@ func process_deposit(state: var BeaconState,
|
||||||
activation_epoch: FAR_FUTURE_EPOCH,
|
activation_epoch: FAR_FUTURE_EPOCH,
|
||||||
exit_epoch: FAR_FUTURE_EPOCH,
|
exit_epoch: FAR_FUTURE_EPOCH,
|
||||||
withdrawable_epoch: FAR_FUTURE_EPOCH,
|
withdrawable_epoch: FAR_FUTURE_EPOCH,
|
||||||
slashed_epoch: FAR_FUTURE_EPOCH,
|
initiated_exit: false,
|
||||||
status_flags: 0,
|
slashed: false,
|
||||||
)
|
)
|
||||||
|
|
||||||
## Note: In phase 2 registry indices that have been withdrawn for a long
|
## Note: In phase 2 registry indices that have been withdrawn for a long
|
||||||
|
@ -74,7 +56,7 @@ func process_deposit(state: var BeaconState,
|
||||||
# Increase balance by deposit amount
|
# Increase balance by deposit amount
|
||||||
let index = validator_pubkeys.find(pubkey)
|
let index = validator_pubkeys.find(pubkey)
|
||||||
let validator = addr state.validator_registry[index]
|
let validator = addr state.validator_registry[index]
|
||||||
assert state.validator_registry[index].withdrawal_credentials ==
|
doAssert state.validator_registry[index].withdrawal_credentials ==
|
||||||
withdrawal_credentials
|
withdrawal_credentials
|
||||||
|
|
||||||
state.validator_balances[index] += amount
|
state.validator_balances[index] += amount
|
||||||
|
@ -99,13 +81,13 @@ func activate_validator(state: var BeaconState,
|
||||||
else:
|
else:
|
||||||
get_entry_exit_effect_epoch(get_current_epoch(state))
|
get_entry_exit_effect_epoch(get_current_epoch(state))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#initiate_validator_exit
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initiate_validator_exit
|
||||||
func initiate_validator_exit*(state: var BeaconState,
|
func initiate_validator_exit*(state: var BeaconState,
|
||||||
index: ValidatorIndex) =
|
index: ValidatorIndex) =
|
||||||
## Initiate exit for the validator with the given ``index``.
|
## Initiate exit for the validator with the given ``index``.
|
||||||
## Note that this function mutates ``state``.
|
## Note that this function mutates ``state``.
|
||||||
var validator = addr state.validator_registry[index]
|
var validator = addr state.validator_registry[index]
|
||||||
validator.status_flags = validator.status_flags or INITIATED_EXIT
|
validator.initiated_exit = true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#exit_validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#exit_validator
|
||||||
func exit_validator*(state: var BeaconState,
|
func exit_validator*(state: var BeaconState,
|
||||||
|
@ -125,6 +107,7 @@ func reduce_balance*(balance: var uint64, amount: uint64) =
|
||||||
# Not in spec, but useful to avoid underflow.
|
# Not in spec, but useful to avoid underflow.
|
||||||
balance -= min(amount, balance)
|
balance -= min(amount, balance)
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slash_validator
|
||||||
func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
||||||
## Slash the validator with index ``index``.
|
## Slash the validator with index ``index``.
|
||||||
## Note that this function mutates ``state``.
|
## Note that this function mutates ``state``.
|
||||||
|
@ -143,13 +126,14 @@ func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
|
||||||
whistleblower_reward = get_effective_balance(state, index) div
|
whistleblower_reward = get_effective_balance(state, index) div
|
||||||
WHISTLEBLOWER_REWARD_QUOTIENT
|
WHISTLEBLOWER_REWARD_QUOTIENT
|
||||||
|
|
||||||
|
## TODO here and elsewhere, if reduce_balance can't reduce balance by full
|
||||||
|
## whistleblower_reward (to prevent underflow) should increase be full? It
|
||||||
|
## seems wrong for the amounts to differ.
|
||||||
state.validator_balances[whistleblower_index] += whistleblower_reward
|
state.validator_balances[whistleblower_index] += whistleblower_reward
|
||||||
reduce_balance(state.validator_balances[index], whistleblower_reward)
|
reduce_balance(state.validator_balances[index], whistleblower_reward)
|
||||||
validator.slashed_epoch = get_current_epoch(state)
|
validator.slashed = true
|
||||||
|
validator.withdrawable_epoch =
|
||||||
# Spec bug in v0.3.0, fixed since: it has LATEST_PENALIZED_EXIT_LENGTH
|
get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
||||||
validator.withdrawable_epoch = get_current_epoch(state) +
|
|
||||||
LATEST_SLASHED_EXIT_LENGTH
|
|
||||||
|
|
||||||
func update_shuffling_cache*(state: var BeaconState) =
|
func update_shuffling_cache*(state: var BeaconState) =
|
||||||
let
|
let
|
||||||
|
@ -171,9 +155,9 @@ func update_shuffling_cache*(state: var BeaconState) =
|
||||||
state.shuffling_cache.shuffling_1 = shuffling_seq
|
state.shuffling_cache.shuffling_1 = shuffling_seq
|
||||||
state.shuffling_cache.index = 1 - state.shuffling_cache.index
|
state.shuffling_cache.index = 1 - state.shuffling_cache.index
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#on-genesis
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#on-genesis
|
||||||
func get_genesis_beacon_state*(
|
func get_genesis_beacon_state*(
|
||||||
initial_validator_deposits: openArray[Deposit],
|
genesis_validator_deposits: openArray[Deposit],
|
||||||
genesis_time: uint64,
|
genesis_time: uint64,
|
||||||
latest_eth1_data: Eth1Data,
|
latest_eth1_data: Eth1Data,
|
||||||
flags: UpdateFlags = {}): BeaconState =
|
flags: UpdateFlags = {}): BeaconState =
|
||||||
|
@ -191,7 +175,7 @@ func get_genesis_beacon_state*(
|
||||||
# validators - there needs to be at least one member in each committee -
|
# validators - there needs to be at least one member in each committee -
|
||||||
# good to know for testing, though arguably the system is not that useful at
|
# good to know for testing, though arguably the system is not that useful at
|
||||||
# at that point :)
|
# at that point :)
|
||||||
assert initial_validator_deposits.len >= SLOTS_PER_EPOCH
|
doAssert genesis_validator_deposits.len >= SLOTS_PER_EPOCH
|
||||||
|
|
||||||
var state = BeaconState(
|
var state = BeaconState(
|
||||||
# Misc
|
# Misc
|
||||||
|
@ -234,19 +218,13 @@ func get_genesis_beacon_state*(
|
||||||
|
|
||||||
for i in 0 ..< SHARD_COUNT:
|
for i in 0 ..< SHARD_COUNT:
|
||||||
state.latest_crosslinks[i] = Crosslink(
|
state.latest_crosslinks[i] = Crosslink(
|
||||||
epoch: GENESIS_EPOCH, shard_block_root: ZERO_HASH)
|
epoch: GENESIS_EPOCH, crosslink_data_root: ZERO_HASH)
|
||||||
|
|
||||||
# Process initial deposits
|
# Process genesis deposits
|
||||||
for deposit in initial_validator_deposits:
|
for deposit in genesis_validator_deposits:
|
||||||
process_deposit(
|
process_deposit(state, deposit)
|
||||||
state,
|
|
||||||
deposit.deposit_data.deposit_input.pubkey,
|
|
||||||
deposit.deposit_data.amount,
|
|
||||||
deposit.deposit_data.deposit_input.proof_of_possession,
|
|
||||||
deposit.deposit_data.deposit_input.withdrawal_credentials,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Process initial activations
|
# Process genesis activations
|
||||||
for validator_index in 0 ..< state.validator_registry.len:
|
for validator_index in 0 ..< state.validator_registry.len:
|
||||||
let vi = validator_index.ValidatorIndex
|
let vi = validator_index.ValidatorIndex
|
||||||
if get_effective_balance(state, vi) >= MAX_DEPOSIT_AMOUNT:
|
if get_effective_balance(state, vi) >= MAX_DEPOSIT_AMOUNT:
|
||||||
|
@ -258,6 +236,7 @@ func get_genesis_beacon_state*(
|
||||||
state.latest_active_index_roots[index] = genesis_active_index_root
|
state.latest_active_index_roots[index] = genesis_active_index_root
|
||||||
state.current_shuffling_seed = generate_seed(state, GENESIS_EPOCH)
|
state.current_shuffling_seed = generate_seed(state, GENESIS_EPOCH)
|
||||||
|
|
||||||
|
# Not in spec.
|
||||||
update_shuffling_cache(state)
|
update_shuffling_cache(state)
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -317,15 +296,13 @@ func get_attestation_participants*(state: BeaconState,
|
||||||
if aggregation_bit == 1:
|
if aggregation_bit == 1:
|
||||||
result.add(validator_index)
|
result.add(validator_index)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#ejections
|
||||||
func process_ejections*(state: var BeaconState, active_validator_indices: auto) =
|
func process_ejections*(state: var BeaconState) =
|
||||||
## Iterate through the validator registry and eject active validators with
|
## Iterate through the validator registry and eject active validators with
|
||||||
## balance below ``EJECTION_BALANCE``
|
## balance below ``EJECTION_BALANCE``
|
||||||
##
|
for index in get_active_validator_indices(
|
||||||
## `active_validator_indices` was already computed in `processEpoch`. Reuse.
|
# Spec bug in 0.4.0: is just current_epoch(state)
|
||||||
## Spec recomputes. This is called before validator reshuffling, so use that
|
state.validator_registry, get_current_epoch(state)):
|
||||||
## cached version from beginning of `processEpoch`.
|
|
||||||
for index in active_validator_indices:
|
|
||||||
if state.validator_balances[index] < EJECTION_BALANCE:
|
if state.validator_balances[index] < EJECTION_BALANCE:
|
||||||
exit_validator(state, index)
|
exit_validator(state, index)
|
||||||
|
|
||||||
|
@ -334,7 +311,7 @@ func get_total_balance*(state: BeaconState, validators: auto): Gwei =
|
||||||
# Return the combined effective balance of an array of validators.
|
# Return the combined effective balance of an array of validators.
|
||||||
foldl(validators, a + get_effective_balance(state, b), 0'u64)
|
foldl(validators, a + get_effective_balance(state, b), 0'u64)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||||
func update_validator_registry*(state: var BeaconState) =
|
func update_validator_registry*(state: var BeaconState) =
|
||||||
## Update validator registry.
|
## Update validator registry.
|
||||||
## Note that this function mutates ``state``.
|
## Note that this function mutates ``state``.
|
||||||
|
@ -355,7 +332,7 @@ func update_validator_registry*(state: var BeaconState) =
|
||||||
# Activate validators within the allowable balance churn
|
# Activate validators within the allowable balance churn
|
||||||
var balance_churn = 0'u64
|
var balance_churn = 0'u64
|
||||||
for index, validator in state.validator_registry:
|
for index, validator in state.validator_registry:
|
||||||
if validator.activation_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
if validator.activation_epoch == FAR_FUTURE_EPOCH and
|
||||||
state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
||||||
|
@ -368,8 +345,8 @@ func update_validator_registry*(state: var BeaconState) =
|
||||||
# Exit validators within the allowable balance churn
|
# Exit validators within the allowable balance churn
|
||||||
balance_churn = 0
|
balance_churn = 0
|
||||||
for index, validator in state.validator_registry:
|
for index, validator in state.validator_registry:
|
||||||
if validator.exit_epoch > get_entry_exit_effect_epoch(current_epoch) and
|
if validator.activation_epoch == FAR_FUTURE_EPOCH and
|
||||||
((validator.status_flags and INITIATED_EXIT) == INITIATED_EXIT):
|
validator.initiated_exit:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
balance_churn += get_effective_balance(state, index.ValidatorIndex)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
|
@ -380,25 +357,26 @@ func update_validator_registry*(state: var BeaconState) =
|
||||||
|
|
||||||
state.validator_registry_update_epoch = current_epoch
|
state.validator_registry_update_epoch = current_epoch
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestations-1
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestations-1
|
||||||
proc checkAttestation*(
|
proc checkAttestation*(
|
||||||
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
state: BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
||||||
## Check that an attestation follows the rules of being included in the state
|
## 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
|
## at the current slot. When acting as a proposer, the same rules need to
|
||||||
## be followed!
|
## be followed!
|
||||||
|
|
||||||
# Can't underflow, because GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
if not (attestation.data.slot >= GENESIS_SLOT):
|
||||||
doAssert GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
warn("Attestation predates genesis slot",
|
||||||
|
attestation_slot = attestation.data.slot,
|
||||||
|
state_slot = humaneSlotNum(state.slot))
|
||||||
|
return
|
||||||
|
|
||||||
if not (attestation.data.slot <= state.slot - MIN_ATTESTATION_INCLUSION_DELAY):
|
if not (attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot):
|
||||||
warn("Attestation too new",
|
warn("Attestation too new",
|
||||||
attestation_slot = humaneSlotNum(attestation.data.slot),
|
attestation_slot = humaneSlotNum(attestation.data.slot),
|
||||||
state_slot = humaneSlotNum(state.slot))
|
state_slot = humaneSlotNum(state.slot))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Can't underflow, because GENESIS_SLOT > MIN_ATTESTATION_INCLUSION_DELAY
|
if not (state.slot < attestation.data.slot + SLOTS_PER_EPOCH):
|
||||||
if not (state.slot - MIN_ATTESTATION_INCLUSION_DELAY <
|
|
||||||
attestation.data.slot + SLOTS_PER_EPOCH):
|
|
||||||
warn("Attestation too old",
|
warn("Attestation too old",
|
||||||
attestation_slot = humaneSlotNum(attestation.data.slot),
|
attestation_slot = humaneSlotNum(attestation.data.slot),
|
||||||
state_slot = humaneSlotNum(state.slot))
|
state_slot = humaneSlotNum(state.slot))
|
||||||
|
@ -428,14 +406,14 @@ proc checkAttestation*(
|
||||||
if not (state.latest_crosslinks[attestation.data.shard] in [
|
if not (state.latest_crosslinks[attestation.data.shard] in [
|
||||||
attestation.data.latest_crosslink,
|
attestation.data.latest_crosslink,
|
||||||
Crosslink(
|
Crosslink(
|
||||||
shard_block_root: attestation.data.shard_block_root,
|
crosslink_data_root: attestation.data.crosslink_data_root,
|
||||||
epoch: slot_to_epoch(attestation.data.slot))]):
|
epoch: slot_to_epoch(attestation.data.slot))]):
|
||||||
warn("Unexpected crosslink shard",
|
warn("Unexpected crosslink shard",
|
||||||
state_latest_crosslinks_attestation_data_shard =
|
state_latest_crosslinks_attestation_data_shard =
|
||||||
state.latest_crosslinks[attestation.data.shard],
|
state.latest_crosslinks[attestation.data.shard],
|
||||||
attestation_data_latest_crosslink = attestation.data.latest_crosslink,
|
attestation_data_latest_crosslink = attestation.data.latest_crosslink,
|
||||||
epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)),
|
epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)),
|
||||||
shard_block_root = attestation.data.shard_block_root)
|
crosslink_data_root = attestation.data.crosslink_data_root)
|
||||||
return
|
return
|
||||||
|
|
||||||
assert allIt(attestation.custody_bitfield, it == 0) #TO BE REMOVED IN PHASE 1
|
assert allIt(attestation.custody_bitfield, it == 0) #TO BE REMOVED IN PHASE 1
|
||||||
|
@ -478,9 +456,6 @@ proc checkAttestation*(
|
||||||
custody_bit_1_participants: seq[ValidatorIndex] = @[]
|
custody_bit_1_participants: seq[ValidatorIndex] = @[]
|
||||||
custody_bit_0_participants = participants
|
custody_bit_0_participants = participants
|
||||||
|
|
||||||
group_public_key = bls_aggregate_pubkeys(
|
|
||||||
participants.mapIt(state.validator_registry[it].pubkey))
|
|
||||||
|
|
||||||
if skipValidation notin flags:
|
if skipValidation notin flags:
|
||||||
# Verify that aggregate_signature verifies using the group pubkey.
|
# Verify that aggregate_signature verifies using the group pubkey.
|
||||||
assert bls_verify_multiple(
|
assert bls_verify_multiple(
|
||||||
|
@ -502,8 +477,8 @@ proc checkAttestation*(
|
||||||
)
|
)
|
||||||
|
|
||||||
# To be removed in Phase1:
|
# To be removed in Phase1:
|
||||||
if attestation.data.shard_block_root != ZERO_HASH:
|
if attestation.data.crosslink_data_root != ZERO_HASH:
|
||||||
warn("Invalid shard block root")
|
warn("Invalid crosslink data root")
|
||||||
return
|
return
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -517,4 +492,4 @@ func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorI
|
||||||
|
|
||||||
# Bug in 0.3.0 spec; constant got renamed. Use 0.3.0 name.
|
# Bug in 0.3.0 spec; constant got renamed. Use 0.3.0 name.
|
||||||
validator.withdrawable_epoch = get_current_epoch(state) +
|
validator.withdrawable_epoch = get_current_epoch(state) +
|
||||||
MIN_VALIDATOR_WITHDRAWAL_DELAY
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
|
|
|
@ -40,12 +40,12 @@ import
|
||||||
# TODO Many of these constants should go into a config object that can be used
|
# TODO Many of these constants should go into a config object that can be used
|
||||||
# to run.. well.. a chain with different constants!
|
# to run.. well.. a chain with different constants!
|
||||||
const
|
const
|
||||||
SPEC_VERSION* = "0.3.0" ## \
|
SPEC_VERSION* = "0.4.0" ## \
|
||||||
## Spec version we're aiming to be compatible with, right now
|
## Spec version we're aiming to be compatible with, right now
|
||||||
## TODO: improve this scheme once we can negotiate versions in protocol
|
## TODO: improve this scheme once we can negotiate versions in protocol
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#misc
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#misc
|
||||||
SHARD_COUNT* {.intdefine.} = 1024 ##\
|
SHARD_COUNT* {.intdefine.} = 1024 ##\
|
||||||
## Number of shards supported by the network - validators will jump around
|
## Number of shards supported by the network - validators will jump around
|
||||||
## between these shards and provide attestations to their state.
|
## between these shards and provide attestations to their state.
|
||||||
|
@ -71,18 +71,16 @@ const
|
||||||
MAX_INDICES_PER_SLASHABLE_VOTE* = 2^12 ##\
|
MAX_INDICES_PER_SLASHABLE_VOTE* = 2^12 ##\
|
||||||
## votes
|
## votes
|
||||||
|
|
||||||
MAX_WITHDRAWALS_PER_EPOCH* = 4 # withdrawals
|
|
||||||
|
|
||||||
MAX_EXIT_DEQUEUES_PER_EPOCH* = 4
|
MAX_EXIT_DEQUEUES_PER_EPOCH* = 4
|
||||||
|
|
||||||
SHUFFLE_ROUND_COUNT* = 90
|
SHUFFLE_ROUND_COUNT* = 90
|
||||||
|
|
||||||
# Deposit contract
|
# Deposit contract
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#deposit-contract
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#deposit-contract
|
||||||
DEPOSIT_CONTRACT_TREE_DEPTH* = 2^5
|
DEPOSIT_CONTRACT_TREE_DEPTH* = 2^5
|
||||||
|
|
||||||
# Gwei values
|
# Gwei values
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#gwei-values
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#gwei-values
|
||||||
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\
|
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\
|
||||||
## Minimum amounth of ETH that can be deposited in one call - deposits can
|
## Minimum amounth of ETH that can be deposited in one call - deposits can
|
||||||
## be used either to top up an existing validator or commit to a new one
|
## be used either to top up an existing validator or commit to a new one
|
||||||
|
@ -103,9 +101,9 @@ const
|
||||||
## Compile with -d:SLOTS_PER_EPOCH=4 for shorter epochs
|
## Compile with -d:SLOTS_PER_EPOCH=4 for shorter epochs
|
||||||
|
|
||||||
# Initial values
|
# Initial values
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#initial-values
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initial-values
|
||||||
GENESIS_FORK_VERSION* = 0'u64
|
GENESIS_FORK_VERSION* = 0'u64
|
||||||
GENESIS_SLOT* = 2'u64^63
|
GENESIS_SLOT* = 2'u64^32
|
||||||
GENESIS_EPOCH* = GENESIS_SLOT div SLOTS_PER_EPOCH # slot_to_epoch(GENESIS_SLOT)
|
GENESIS_EPOCH* = GENESIS_SLOT div SLOTS_PER_EPOCH # slot_to_epoch(GENESIS_SLOT)
|
||||||
GENESIS_START_SHARD* = 0'u64
|
GENESIS_START_SHARD* = 0'u64
|
||||||
FAR_FUTURE_EPOCH* = not 0'u64 # 2^64 - 1 in spec
|
FAR_FUTURE_EPOCH* = not 0'u64 # 2^64 - 1 in spec
|
||||||
|
@ -114,7 +112,7 @@ const
|
||||||
BLS_WITHDRAWAL_PREFIX_BYTE* = 0'u8
|
BLS_WITHDRAWAL_PREFIX_BYTE* = 0'u8
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#time-parameters
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#time-parameters
|
||||||
SECONDS_PER_SLOT*{.intdefine.} = 6'u64 # Compile with -d:SECONDS_PER_SLOT=1 for 6x faster slots
|
SECONDS_PER_SLOT*{.intdefine.} = 6'u64 # Compile with -d:SECONDS_PER_SLOT=1 for 6x faster slots
|
||||||
## TODO consistent time unit across projects, similar to C++ chrono?
|
## TODO consistent time unit across projects, similar to C++ chrono?
|
||||||
|
|
||||||
|
@ -130,6 +128,8 @@ const
|
||||||
## wait towards the end of the slot and still have time to publish the
|
## wait towards the end of the slot and still have time to publish the
|
||||||
## attestation.
|
## attestation.
|
||||||
|
|
||||||
|
# SLOTS_PER_EPOCH is defined above.
|
||||||
|
|
||||||
MIN_SEED_LOOKAHEAD* = 1 ##\
|
MIN_SEED_LOOKAHEAD* = 1 ##\
|
||||||
## epochs (~6.4 minutes)
|
## epochs (~6.4 minutes)
|
||||||
|
|
||||||
|
@ -139,18 +139,18 @@ const
|
||||||
EPOCHS_PER_ETH1_VOTING_PERIOD* = 2'u64^4 ##\
|
EPOCHS_PER_ETH1_VOTING_PERIOD* = 2'u64^4 ##\
|
||||||
## epochs (~1.7 hours)
|
## epochs (~1.7 hours)
|
||||||
|
|
||||||
MIN_VALIDATOR_WITHDRAWAL_DELAY* = 2'u64^8 ##\
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8 ##\
|
||||||
## epochs (~27 hours)
|
## epochs (~27 hours)
|
||||||
|
|
||||||
# State list lengths
|
# State list lengths
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#state-list-lengths
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#state-list-lengths
|
||||||
LATEST_BLOCK_ROOTS_LENGTH* = 2'u64^13
|
LATEST_BLOCK_ROOTS_LENGTH* = 2'u64^13
|
||||||
LATEST_RANDAO_MIXES_LENGTH* = 2'u64^13
|
LATEST_RANDAO_MIXES_LENGTH* = 2'u64^13
|
||||||
LATEST_ACTIVE_INDEX_ROOTS_LENGTH* = 8192 # 2'u64^13, epochs
|
LATEST_ACTIVE_INDEX_ROOTS_LENGTH* = 8192 # 2'u64^13, epochs
|
||||||
LATEST_SLASHED_EXIT_LENGTH* = 8192 # epochs
|
LATEST_SLASHED_EXIT_LENGTH* = 8192 # epochs
|
||||||
|
|
||||||
# Reward and penalty quotients
|
# Reward and penalty quotients
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
|
||||||
BASE_REWARD_QUOTIENT* = 2'u64^5 ##\
|
BASE_REWARD_QUOTIENT* = 2'u64^5 ##\
|
||||||
## The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It
|
## The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It
|
||||||
## corresponds to ~2.54% annual interest assuming 10 million participating
|
## corresponds to ~2.54% annual interest assuming 10 million participating
|
||||||
|
@ -160,12 +160,8 @@ const
|
||||||
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^24
|
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^24
|
||||||
MIN_PENALTY_QUOTIENT* = 32 # 2^5
|
MIN_PENALTY_QUOTIENT* = 32 # 2^5
|
||||||
|
|
||||||
# Status flags
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#status-flags
|
|
||||||
INITIATED_EXIT* = 1'u64
|
|
||||||
|
|
||||||
# Max transactions per block
|
# Max transactions per block
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#max-transactions-per-block
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#max-transactions-per-block
|
||||||
MAX_PROPOSER_SLASHINGS* = 2^4
|
MAX_PROPOSER_SLASHINGS* = 2^4
|
||||||
MAX_ATTESTER_SLASHINGS* = 2^0
|
MAX_ATTESTER_SLASHINGS* = 2^0
|
||||||
MAX_ATTESTATIONS* = 2^7
|
MAX_ATTESTATIONS* = 2^7
|
||||||
|
@ -184,15 +180,18 @@ type
|
||||||
Epoch* = uint64
|
Epoch* = uint64
|
||||||
Gwei* = uint64
|
Gwei* = uint64
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposerslashing
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposerslashing
|
||||||
ProposerSlashing* = object
|
ProposerSlashing* = object
|
||||||
proposer_index*: uint64
|
proposer_index*: uint64 ##\
|
||||||
proposal_data_1*: ProposalSignedData
|
## Proposer index
|
||||||
proposal_signature_1*: ValidatorSig
|
|
||||||
proposal_data_2*: ProposalSignedData
|
|
||||||
proposal_signature_2*: ValidatorSig
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attesterslashing
|
proposal_1*: Proposal ##\
|
||||||
|
# First proposal
|
||||||
|
|
||||||
|
proposal_2*: Proposal ##\
|
||||||
|
# Second proposal
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attesterslashing
|
||||||
AttesterSlashing* = object
|
AttesterSlashing* = object
|
||||||
slashable_attestation_1*: SlashableAttestation ## \
|
slashable_attestation_1*: SlashableAttestation ## \
|
||||||
## First slashable attestation
|
## First slashable attestation
|
||||||
|
@ -227,7 +226,7 @@ type
|
||||||
aggregate_signature*: ValidatorSig ##\
|
aggregate_signature*: ValidatorSig ##\
|
||||||
## BLS aggregate signature
|
## BLS aggregate signature
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestationdata
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdata
|
||||||
AttestationData* = object
|
AttestationData* = object
|
||||||
slot*: uint64 ##\
|
slot*: uint64 ##\
|
||||||
## Slot number
|
## Slot number
|
||||||
|
@ -241,8 +240,8 @@ type
|
||||||
epoch_boundary_root*: Eth2Digest ##\
|
epoch_boundary_root*: Eth2Digest ##\
|
||||||
## Hash of root of the ancestor at the epoch boundary
|
## Hash of root of the ancestor at the epoch boundary
|
||||||
|
|
||||||
shard_block_root*: Eth2Digest ##\
|
crosslink_data_root*: Eth2Digest ##\
|
||||||
## Shard block's hash of root
|
## Data from the shard since the last attestation
|
||||||
|
|
||||||
latest_crosslink*: Crosslink ##\
|
latest_crosslink*: Crosslink ##\
|
||||||
## Last crosslink
|
## Last crosslink
|
||||||
|
@ -253,7 +252,7 @@ type
|
||||||
justified_block_root*: Eth2Digest ##\
|
justified_block_root*: Eth2Digest ##\
|
||||||
## Hash of the last justified beacon block
|
## Hash of the last justified beacon block
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
|
||||||
AttestationDataAndCustodyBit* = object
|
AttestationDataAndCustodyBit* = object
|
||||||
data*: AttestationData
|
data*: AttestationData
|
||||||
custody_bit*: bool
|
custody_bit*: bool
|
||||||
|
@ -360,6 +359,20 @@ type
|
||||||
voluntary_exits*: seq[VoluntaryExit]
|
voluntary_exits*: seq[VoluntaryExit]
|
||||||
transfers*: seq[Transfer]
|
transfers*: seq[Transfer]
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposal
|
||||||
|
Proposal* = object
|
||||||
|
slot*: uint64 ##\
|
||||||
|
## Slot number
|
||||||
|
|
||||||
|
shard*: uint64 ##\
|
||||||
|
## Shard number (`BEACON_CHAIN_SHARD_NUMBER` for beacon chain)
|
||||||
|
|
||||||
|
block_root*: Eth2Digest ##\
|
||||||
|
## Block root
|
||||||
|
|
||||||
|
signature*: ValidatorSig ##\
|
||||||
|
## Signature
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposalsigneddata
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposalsigneddata
|
||||||
ProposalSignedData* = object
|
ProposalSignedData* = object
|
||||||
slot*: uint64
|
slot*: uint64
|
||||||
|
@ -420,7 +433,7 @@ type
|
||||||
# Not in spec. TODO: don't serialize or deserialize this.
|
# Not in spec. TODO: don't serialize or deserialize this.
|
||||||
shuffling_cache*: ShufflingCache
|
shuffling_cache*: ShufflingCache
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator
|
||||||
Validator* = object
|
Validator* = object
|
||||||
pubkey*: ValidatorPubKey ##\
|
pubkey*: ValidatorPubKey ##\
|
||||||
## BLS public key
|
## BLS public key
|
||||||
|
@ -437,18 +450,19 @@ type
|
||||||
withdrawable_epoch*: uint64 ##\
|
withdrawable_epoch*: uint64 ##\
|
||||||
## Epoch when validator is eligible to withdraw
|
## Epoch when validator is eligible to withdraw
|
||||||
|
|
||||||
slashed_epoch*: uint64 ##\
|
initiated_exit*: bool ##\
|
||||||
## Epoch when validator slashed
|
## Did the validator initiate an exit
|
||||||
|
|
||||||
status_flags*: uint64
|
slashed*: bool ##\
|
||||||
|
## Was the validator slashed
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#crosslink
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#crosslink
|
||||||
Crosslink* = object
|
Crosslink* = object
|
||||||
epoch*: uint64 ##\
|
epoch*: uint64 ##\
|
||||||
## Epoch number
|
## Epoch number
|
||||||
|
|
||||||
shard_block_root*: Eth2Digest ##\
|
crosslink_data_root*: Eth2Digest ##\
|
||||||
## Shard block root
|
## Shard data since the previous crosslink
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#pendingattestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#pendingattestation
|
||||||
PendingAttestation* = object
|
PendingAttestation* = object
|
||||||
|
@ -485,7 +499,7 @@ type
|
||||||
Activation = 0
|
Activation = 0
|
||||||
Exit = 1
|
Exit = 1
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#signature-domains
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#signature-domains
|
||||||
SignatureDomain* {.pure.} = enum
|
SignatureDomain* {.pure.} = enum
|
||||||
DOMAIN_DEPOSIT = 0
|
DOMAIN_DEPOSIT = 0
|
||||||
DOMAIN_ATTESTATION = 1
|
DOMAIN_ATTESTATION = 1
|
||||||
|
|
|
@ -138,7 +138,7 @@ func is_double_vote*(attestation_data_1: AttestationData,
|
||||||
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
|
||||||
target_epoch_1 == target_epoch_2
|
target_epoch_1 == target_epoch_2
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#is_surround_vote
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_surround_vote
|
||||||
func is_surround_vote*(attestation_data_1: AttestationData,
|
func is_surround_vote*(attestation_data_1: AttestationData,
|
||||||
attestation_data_2: AttestationData): bool =
|
attestation_data_2: AttestationData): bool =
|
||||||
## Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
## Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||||
|
|
|
@ -290,6 +290,21 @@ func hash_tree_root*[T: object|tuple](x: T): array[32, byte] =
|
||||||
for field in x.fields:
|
for field in x.fields:
|
||||||
h.update hash_tree_root(field)
|
h.update hash_tree_root(field)
|
||||||
|
|
||||||
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/simple-serialize.md#signed-roots
|
||||||
|
func signed_root*[T: object](x: T, field_name: string): array[32, byte] =
|
||||||
|
# TODO write tests for this (check vs hash_tree_root)
|
||||||
|
|
||||||
|
var found_field_name = false
|
||||||
|
|
||||||
|
withHash:
|
||||||
|
for name, field in x.fieldPairs:
|
||||||
|
if name == field_name:
|
||||||
|
found_field_name = true
|
||||||
|
break
|
||||||
|
h.update hash_tree_root(field)
|
||||||
|
|
||||||
|
doAssert found_field_name
|
||||||
|
|
||||||
# #################################
|
# #################################
|
||||||
# hash_tree_root not part of official spec
|
# hash_tree_root not part of official spec
|
||||||
func hash_tree_root*(x: enum): array[8, byte] =
|
func hash_tree_root*(x: enum): array[8, byte] =
|
||||||
|
|
|
@ -106,32 +106,7 @@ func processDepositRoot(state: var BeaconState, blck: BeaconBlock) =
|
||||||
vote_count: 1
|
vote_count: 1
|
||||||
)
|
)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#slashValidator
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposer-slashings-1
|
||||||
func slashValidator(state: var BeaconState, index: ValidatorIndex) =
|
|
||||||
## Slash the validator of the given ``index``.
|
|
||||||
## Note that this function mutates ``state``.
|
|
||||||
var validator = addr state.validator_registry[index]
|
|
||||||
|
|
||||||
doAssert state.slot < get_epoch_start_slot(validator.withdrawable_epoch) ##\
|
|
||||||
## [TO BE REMOVED IN PHASE 2]
|
|
||||||
|
|
||||||
exit_validator(state, index)
|
|
||||||
state.latest_slashed_balances[(get_current_epoch(state) mod
|
|
||||||
LATEST_SLASHED_EXIT_LENGTH).int] += get_effective_balance(state,
|
|
||||||
index.ValidatorIndex)
|
|
||||||
|
|
||||||
let
|
|
||||||
whistleblower_index = get_beacon_proposer_index(state, state.slot)
|
|
||||||
whistleblower_reward = get_effective_balance(state, index) div
|
|
||||||
WHISTLEBLOWER_REWARD_QUOTIENT
|
|
||||||
state.validator_balances[whistleblower_index] += whistleblower_reward
|
|
||||||
reduce_balance(state.validator_balances[index], whistleblower_reward)
|
|
||||||
validator.slashed_epoch = get_current_epoch(state)
|
|
||||||
|
|
||||||
# v0.3.0 spec bug, fixed later, involving renamed constants. Use v0.3.0 name.
|
|
||||||
validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#proposer-slashings-1
|
|
||||||
proc processProposerSlashings(
|
proc processProposerSlashings(
|
||||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||||
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
|
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
|
||||||
|
@ -141,48 +116,49 @@ proc processProposerSlashings(
|
||||||
|
|
||||||
for proposer_slashing in blck.body.proposer_slashings:
|
for proposer_slashing in blck.body.proposer_slashings:
|
||||||
let proposer = state.validator_registry[proposer_slashing.proposer_index.int]
|
let proposer = state.validator_registry[proposer_slashing.proposer_index.int]
|
||||||
|
|
||||||
|
if not (proposer_slashing.proposal_1.slot ==
|
||||||
|
proposer_slashing.proposal_2.slot):
|
||||||
|
notice "PropSlash: slot mismatch"
|
||||||
|
return false
|
||||||
|
|
||||||
|
if not (proposer_slashing.proposal_1.shard ==
|
||||||
|
proposer_slashing.proposal_2.shard):
|
||||||
|
notice "PropSlash: shard mismatch"
|
||||||
|
return false
|
||||||
|
|
||||||
|
if not (proposer_slashing.proposal_1.block_root !=
|
||||||
|
proposer_slashing.proposal_2.block_root):
|
||||||
|
notice "PropSlash: block root mismatch"
|
||||||
|
return false
|
||||||
|
|
||||||
|
if not (proposer.slashed == false):
|
||||||
|
notice "PropSlash: slashed proposer"
|
||||||
|
return false
|
||||||
|
|
||||||
if skipValidation notin flags:
|
if skipValidation notin flags:
|
||||||
if not bls_verify(
|
if not bls_verify(
|
||||||
proposer.pubkey,
|
proposer.pubkey,
|
||||||
hash_tree_root_final(proposer_slashing.proposal_data_1).data,
|
signed_root(proposer_slashing.proposal_1, "signature"),
|
||||||
proposer_slashing.proposal_signature_1,
|
proposer_slashing.proposal_1.signature,
|
||||||
get_domain(
|
get_domain(
|
||||||
state.fork, slot_to_epoch(proposer_slashing.proposal_data_1.slot),
|
state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot),
|
||||||
DOMAIN_PROPOSAL)):
|
DOMAIN_PROPOSAL)):
|
||||||
notice "PropSlash: invalid signature 1"
|
notice "PropSlash: invalid signature 1"
|
||||||
return false
|
return false
|
||||||
if not bls_verify(
|
if not bls_verify(
|
||||||
proposer.pubkey,
|
proposer.pubkey,
|
||||||
hash_tree_root_final(proposer_slashing.proposal_data_2).data,
|
signed_root(proposer_slashing.proposal_2, "signature"),
|
||||||
proposer_slashing.proposal_signature_2,
|
proposer_slashing.proposal_2.signature,
|
||||||
get_domain(
|
get_domain(
|
||||||
state.fork, slot_to_epoch(proposer_slashing.proposal_data_2.slot),
|
state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot),
|
||||||
DOMAIN_PROPOSAL)):
|
DOMAIN_PROPOSAL)):
|
||||||
notice "PropSlash: invalid signature 2"
|
notice "PropSlash: invalid signature 2"
|
||||||
return false
|
return false
|
||||||
|
|
||||||
if not (proposer_slashing.proposal_data_1.slot ==
|
|
||||||
proposer_slashing.proposal_data_2.slot):
|
|
||||||
notice "PropSlash: slot mismatch"
|
|
||||||
return false
|
|
||||||
|
|
||||||
if not (proposer_slashing.proposal_data_1.shard ==
|
|
||||||
proposer_slashing.proposal_data_2.shard):
|
|
||||||
notice "PropSlash: shard mismatch"
|
|
||||||
return false
|
|
||||||
|
|
||||||
if not (proposer_slashing.proposal_data_1.block_root ==
|
|
||||||
proposer_slashing.proposal_data_2.block_root):
|
|
||||||
notice "PropSlash: block root mismatch"
|
|
||||||
return false
|
|
||||||
|
|
||||||
if not (proposer.slashed_epoch > get_current_epoch(state)):
|
|
||||||
notice "PropSlash: penalized slot"
|
|
||||||
return false
|
|
||||||
|
|
||||||
slashValidator(state, proposer_slashing.proposer_index.ValidatorIndex)
|
slashValidator(state, proposer_slashing.proposer_index.ValidatorIndex)
|
||||||
|
|
||||||
return true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#verify_slashable_attestation
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/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 =
|
||||||
|
@ -233,7 +209,7 @@ func verify_slashable_attestation(state: BeaconState, slashable_attestation: Sla
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attester-slashings-1
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attester-slashings-1
|
||||||
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
if len(blck.body.attester_slashings) > MAX_ATTESTER_SLASHINGS:
|
if len(blck.body.attester_slashings) > MAX_ATTESTER_SLASHINGS:
|
||||||
notice "CaspSlash: too many!"
|
notice "CaspSlash: too many!"
|
||||||
|
@ -263,7 +239,7 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
return false
|
return false
|
||||||
|
|
||||||
let
|
let
|
||||||
indices2 = slashable_attestation_2.validator_indices
|
indices2 = toSet(slashable_attestation_2.validator_indices)
|
||||||
slashable_indices =
|
slashable_indices =
|
||||||
slashable_attestation_1.validator_indices.filterIt(it in indices2)
|
slashable_attestation_1.validator_indices.filterIt(it in indices2)
|
||||||
|
|
||||||
|
@ -272,7 +248,7 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
return false
|
return false
|
||||||
|
|
||||||
for index in slashable_indices:
|
for index in slashable_indices:
|
||||||
if state.validator_registry[index.int].slashed_epoch > get_current_epoch(state):
|
if state.validator_registry[index.int].slashed:
|
||||||
slash_validator(state, index.ValidatorIndex)
|
slash_validator(state, index.ValidatorIndex)
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -413,7 +389,7 @@ func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) =
|
||||||
## chain at that time. In case the proposer is missing, it may happen that
|
## chain at that time. In case the proposer is missing, it may happen that
|
||||||
## the no block is produced during the slot.
|
## the no block is produced during the slot.
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#slot
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slot
|
||||||
state.slot += 1
|
state.slot += 1
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#block-roots
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#block-roots
|
||||||
|
@ -503,13 +479,13 @@ func boundary_attestations(
|
||||||
|
|
||||||
func lowerThan(candidate, current: Eth2Digest): bool =
|
func lowerThan(candidate, current: Eth2Digest): bool =
|
||||||
# return true iff candidate is "lower" than current, per spec rule:
|
# return true iff candidate is "lower" than current, per spec rule:
|
||||||
# "ties broken by favoring lower `shard_block_root` values"
|
# "ties broken by favoring lower `crosslink_data_root` values"
|
||||||
# TODO spec - clarify hash ordering..
|
# TODO spec - clarify hash ordering..
|
||||||
for i, v in current.data:
|
for i, v in current.data:
|
||||||
if v > candidate.data[i]: return true
|
if v > candidate.data[i]: return true
|
||||||
false
|
false
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||||
func process_slashings(state: var BeaconState) =
|
func process_slashings(state: var BeaconState) =
|
||||||
## Process the slashings.
|
## Process the slashings.
|
||||||
## Note that this function mutates ``state``.
|
## Note that this function mutates ``state``.
|
||||||
|
@ -517,12 +493,12 @@ func process_slashings(state: var BeaconState) =
|
||||||
current_epoch = get_current_epoch(state)
|
current_epoch = get_current_epoch(state)
|
||||||
active_validator_indices = get_active_validator_indices(
|
active_validator_indices = get_active_validator_indices(
|
||||||
state.validator_registry, current_epoch)
|
state.validator_registry, current_epoch)
|
||||||
# TODO 0.3.0 spec doesn't use this helper function?
|
# 0.4.0 spec doesn't use this helper function?
|
||||||
total_balance = get_total_balance(state, active_validator_indices)
|
total_balance = get_total_balance(state, active_validator_indices)
|
||||||
|
|
||||||
for index, validator in state.validator_registry:
|
for index, validator in state.validator_registry:
|
||||||
if current_epoch ==
|
if validator.slashed and current_epoch == validator.withdrawable_epoch -
|
||||||
validator.slashed_epoch + LATEST_SLASHED_EXIT_LENGTH div 2:
|
LATEST_SLASHED_EXIT_LENGTH div 2:
|
||||||
let
|
let
|
||||||
epoch_index = current_epoch mod LATEST_SLASHED_EXIT_LENGTH
|
epoch_index = current_epoch mod LATEST_SLASHED_EXIT_LENGTH
|
||||||
total_at_start = state.latest_slashed_balances[
|
total_at_start = state.latest_slashed_balances[
|
||||||
|
@ -543,14 +519,12 @@ func process_exit_queue(state: var BeaconState) =
|
||||||
func eligible(index: ValidatorIndex): bool =
|
func eligible(index: ValidatorIndex): bool =
|
||||||
let validator = state.validator_registry[index]
|
let validator = state.validator_registry[index]
|
||||||
# Filter out dequeued validators
|
# Filter out dequeued validators
|
||||||
if validator.withdrawable_epoch < FAR_FUTURE_EPOCH:
|
if validator.withdrawable_epoch != FAR_FUTURE_EPOCH:
|
||||||
return false
|
return false
|
||||||
# Dequeue if the minimum amount of time has passed
|
# Dequeue if the minimum amount of time has passed
|
||||||
else:
|
else:
|
||||||
return get_current_epoch(state) >= validator.exit_epoch +
|
return get_current_epoch(state) >= validator.exit_epoch +
|
||||||
# TODO in future versions, remove workaround for 0.3.0 spec bug
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
# but for 0.3.0 use MIN_VALIDATOR_WITHDRAWAL_DELAY constant
|
|
||||||
MIN_VALIDATOR_WITHDRAWAL_DELAY
|
|
||||||
|
|
||||||
# TODO try again with filterIt
|
# TODO try again with filterIt
|
||||||
var eligible_indices: seq[ValidatorIndex]
|
var eligible_indices: seq[ValidatorIndex]
|
||||||
|
@ -661,22 +635,22 @@ func processEpoch(state: var BeaconState) =
|
||||||
# these closures outside this scope, but still..
|
# these closures outside this scope, but still..
|
||||||
let statePtr = state.addr
|
let statePtr = state.addr
|
||||||
func attesting_validator_indices(
|
func attesting_validator_indices(
|
||||||
crosslink_committee: CrosslinkCommittee, shard_block_root: Eth2Digest): seq[ValidatorIndex] =
|
crosslink_committee: CrosslinkCommittee, crosslink_data_root: Eth2Digest): seq[ValidatorIndex] =
|
||||||
let shard_block_attestations =
|
let shard_block_attestations =
|
||||||
concat(current_epoch_attestations, previous_epoch_attestations).
|
concat(current_epoch_attestations, previous_epoch_attestations).
|
||||||
filterIt(it.data.shard == crosslink_committee.shard and
|
filterIt(it.data.shard == crosslink_committee.shard and
|
||||||
it.data.shard_block_root == shard_block_root)
|
it.data.crosslink_data_root == crosslink_data_root)
|
||||||
get_attester_indices(statePtr[], shard_block_attestations)
|
get_attester_indices(statePtr[], shard_block_attestations)
|
||||||
|
|
||||||
func winning_root(crosslink_committee: CrosslinkCommittee): Eth2Digest =
|
func winning_root(crosslink_committee: CrosslinkCommittee): Eth2Digest =
|
||||||
# * Let `winning_root(crosslink_committee)` be equal to the value of
|
# * Let `winning_root(crosslink_committee)` be equal to the value of
|
||||||
# `shard_block_root` such that
|
# `crosslink_data_root` such that
|
||||||
# `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, shard_block_root)])`
|
# `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, crosslink_data_root)])`
|
||||||
# is maximized (ties broken by favoring lower `shard_block_root` values).
|
# is maximized (ties broken by favoring lower `crosslink_data_root` values).
|
||||||
let candidates =
|
let candidates =
|
||||||
concat(current_epoch_attestations, previous_epoch_attestations).
|
concat(current_epoch_attestations, previous_epoch_attestations).
|
||||||
filterIt(it.data.shard == crosslink_committee.shard).
|
filterIt(it.data.shard == crosslink_committee.shard).
|
||||||
mapIt(it.data.shard_block_root)
|
mapIt(it.data.crosslink_data_root)
|
||||||
|
|
||||||
# TODO not covered by spec!
|
# TODO not covered by spec!
|
||||||
if candidates.len == 0:
|
if candidates.len == 0:
|
||||||
|
@ -750,7 +724,7 @@ func processEpoch(state: var BeaconState) =
|
||||||
2'u64 * get_total_balance(state, crosslink_committee.committee):
|
2'u64 * get_total_balance(state, crosslink_committee.committee):
|
||||||
state.latest_crosslinks[crosslink_committee.shard] = Crosslink(
|
state.latest_crosslinks[crosslink_committee.shard] = Crosslink(
|
||||||
epoch: slot_to_epoch(slot),
|
epoch: slot_to_epoch(slot),
|
||||||
shard_block_root: winning_root(crosslink_committee))
|
crosslink_data_root: winning_root(crosslink_committee))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#rewards-and-penalties
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#rewards-and-penalties
|
||||||
## First, we define some additional helpers
|
## First, we define some additional helpers
|
||||||
|
@ -768,22 +742,7 @@ func processEpoch(state: var BeaconState) =
|
||||||
get_effective_balance(state, index) * epochs_since_finality div
|
get_effective_balance(state, index) * epochs_since_finality div
|
||||||
INACTIVITY_PENALTY_QUOTIENT div 2
|
INACTIVITY_PENALTY_QUOTIENT div 2
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#justification-and-finalization
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#justification-and-finalization
|
||||||
## TODO remove inclusion_{slot,distance} when fully replaced, but note
|
|
||||||
## intentional absence, for spec sync purposes. Both positively invite
|
|
||||||
## quadratic behavior.
|
|
||||||
func inclusion_slot(state: BeaconState, v: ValidatorIndex): uint64 =
|
|
||||||
for a in previous_epoch_attestations:
|
|
||||||
if v in get_attestation_participants(state, a.data, a.aggregation_bitfield):
|
|
||||||
return a.inclusion_slot
|
|
||||||
doAssert false
|
|
||||||
|
|
||||||
func inclusion_distance(state: BeaconState, v: ValidatorIndex): uint64 =
|
|
||||||
for a in previous_epoch_attestations:
|
|
||||||
if v in get_attestation_participants(state, a.data, a.aggregation_bitfield):
|
|
||||||
return a.inclusion_slot - a.data.slot
|
|
||||||
doAssert false
|
|
||||||
|
|
||||||
func inclusion_distances(state: BeaconState): auto =
|
func inclusion_distances(state: BeaconState): auto =
|
||||||
result = initTable[ValidatorIndex, uint64]()
|
result = initTable[ValidatorIndex, uint64]()
|
||||||
|
|
||||||
|
@ -797,6 +756,12 @@ func processEpoch(state: var BeaconState) =
|
||||||
let
|
let
|
||||||
epochs_since_finality = next_epoch - state.finalized_epoch
|
epochs_since_finality = next_epoch - state.finalized_epoch
|
||||||
|
|
||||||
|
## Note: Rewards and penalties are for participation in the previous
|
||||||
|
## epoch, so the "active validator" set is drawn from
|
||||||
|
## get_active_validator_indices(state.validator_registry, previous_epoch).
|
||||||
|
active_validator_indices =
|
||||||
|
get_active_validator_indices(state.validator_registry, previous_epoch)
|
||||||
|
|
||||||
proc update_balance(attesters: HashSet[ValidatorIndex], attesting_balance: uint64) =
|
proc update_balance(attesters: HashSet[ValidatorIndex], attesting_balance: uint64) =
|
||||||
# TODO Spec - add helper?
|
# TODO Spec - add helper?
|
||||||
for v in attesters:
|
for v in attesters:
|
||||||
|
@ -827,18 +792,17 @@ func processEpoch(state: var BeaconState) =
|
||||||
previous_epoch_head_attesting_balance)
|
previous_epoch_head_attesting_balance)
|
||||||
|
|
||||||
# Inclusion distance
|
# Inclusion distance
|
||||||
let distances = inclusion_distances(state)
|
# Strange plural (non)convention, but match spec name.
|
||||||
|
let inclusion_distance = inclusion_distances(state)
|
||||||
|
|
||||||
for v in previous_epoch_attester_indices:
|
for v in previous_epoch_attester_indices:
|
||||||
statePtr.validator_balances[v] +=
|
statePtr.validator_balances[v] +=
|
||||||
base_reward(state, v) *
|
base_reward(state, v) *
|
||||||
MIN_ATTESTATION_INCLUSION_DELAY div distances[v]
|
MIN_ATTESTATION_INCLUSION_DELAY div inclusion_distance[v]
|
||||||
when false:
|
|
||||||
doAssert inclusion_distance(state, v) == distances[v]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Case 2: epochs_since_finality > 4
|
# Case 2: epochs_since_finality > 4
|
||||||
let distances =
|
let inclusion_distance =
|
||||||
if previous_epoch_attester_indices.len > 0:
|
if previous_epoch_attester_indices.len > 0:
|
||||||
inclusion_distances(state)
|
inclusion_distances(state)
|
||||||
else:
|
else:
|
||||||
|
@ -858,7 +822,7 @@ func processEpoch(state: var BeaconState) =
|
||||||
if index notin previous_epoch_head_attester_indices:
|
if index notin previous_epoch_head_attester_indices:
|
||||||
reduce_balance(
|
reduce_balance(
|
||||||
state.validator_balances[index], base_reward(state, index))
|
state.validator_balances[index], base_reward(state, index))
|
||||||
if state.validator_registry[index].slashed_epoch <= current_epoch:
|
if state.validator_registry[index].slashed:
|
||||||
reduce_balance(
|
reduce_balance(
|
||||||
state.validator_balances[index],
|
state.validator_balances[index],
|
||||||
2'u64 * inactivity_penalty(
|
2'u64 * inactivity_penalty(
|
||||||
|
@ -866,11 +830,10 @@ func processEpoch(state: var BeaconState) =
|
||||||
if index in previous_epoch_attester_indices:
|
if index in previous_epoch_attester_indices:
|
||||||
reduce_balance(
|
reduce_balance(
|
||||||
state.validator_balances[index],
|
state.validator_balances[index],
|
||||||
|
# TODO spec issue? depends on left/right associativity of * and /
|
||||||
base_reward(state, index) -
|
base_reward(state, index) -
|
||||||
base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
|
base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY div
|
||||||
distances[index])
|
inclusion_distance[index])
|
||||||
when false:
|
|
||||||
doAssert inclusion_distance(state, index) == distances[index]
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestation-inclusion
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#attestation-inclusion
|
||||||
block:
|
block:
|
||||||
|
@ -935,8 +898,8 @@ func processEpoch(state: var BeaconState) =
|
||||||
reduce_balance(
|
reduce_balance(
|
||||||
state.validator_balances[index], base_reward(state, index))
|
state.validator_balances[index], base_reward(state, index))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#ejections
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#ejections
|
||||||
process_ejections(state, active_validator_indices)
|
process_ejections(state)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
|
||||||
block:
|
block:
|
||||||
|
|
|
@ -175,7 +175,7 @@ proc makeAttestation*(
|
||||||
beacon_block_root: beacon_block_root,
|
beacon_block_root: beacon_block_root,
|
||||||
epoch_boundary_root: Eth2Digest(), # TODO
|
epoch_boundary_root: Eth2Digest(), # TODO
|
||||||
latest_crosslink: state.latest_crosslinks[sac.shard],
|
latest_crosslink: state.latest_crosslinks[sac.shard],
|
||||||
shard_block_root: Eth2Digest(), # TODO
|
crosslink_data_root: Eth2Digest(), # TODO
|
||||||
justified_epoch: state.justified_epoch,
|
justified_epoch: state.justified_epoch,
|
||||||
justified_block_root: get_block_root(state, get_epoch_start_slot(state.justified_epoch)),
|
justified_block_root: get_block_root(state, get_epoch_start_slot(state.justified_epoch)),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue