2018-11-29 22:11:05 +00:00
|
|
|
# beacon_chain
|
2019-02-27 13:58:07 +00:00
|
|
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
2018-11-29 22:11:05 +00:00
|
|
|
# Licensed and distributed under either of
|
2019-11-25 15:30:02 +00:00
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
2018-11-29 22:11:05 +00:00
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
import
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
options, stew/endians2,
|
2019-03-28 12:00:21 +00:00
|
|
|
chronicles, eth/trie/[db],
|
2019-03-28 06:10:48 +00:00
|
|
|
../beacon_chain/[beacon_chain_db, block_pool, extras, ssz, state_transition,
|
|
|
|
validator_pool, beacon_node_types],
|
2019-07-03 07:35:05 +00:00
|
|
|
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest,
|
2019-03-28 06:10:48 +00:00
|
|
|
helpers, validator]
|
2018-11-29 22:11:05 +00:00
|
|
|
|
2019-05-27 12:48:13 +00:00
|
|
|
func preset*(): string =
|
|
|
|
" [Preset: " & const_preset & ']'
|
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
when ValidatorPrivKey is BlsValue:
|
2019-11-25 11:46:47 +00:00
|
|
|
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
2019-07-03 07:35:05 +00:00
|
|
|
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
|
|
|
# lighthouse.
|
|
|
|
# TODO: switch to https://github.com/ethereum/eth2.0-pm/issues/60
|
|
|
|
result.kind = BlsValueType.Real
|
|
|
|
var bytes = uint64(i + 1000).toBytesLE()
|
|
|
|
copyMem(addr result.blsValue.x[0], addr bytes[0], sizeof(bytes))
|
|
|
|
else:
|
2019-11-25 11:46:47 +00:00
|
|
|
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
|
2019-07-03 07:35:05 +00:00
|
|
|
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
|
|
|
|
# lighthouse.
|
|
|
|
# TODO: switch to https://github.com/ethereum/eth2.0-pm/issues/60
|
|
|
|
var bytes = uint64(i + 1000).toBytesLE()
|
|
|
|
copyMem(addr result.x[0], addr bytes[0], sizeof(bytes))
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-11-25 11:46:47 +00:00
|
|
|
func makeFakeHash(i: int): Eth2Digest =
|
2019-07-24 06:19:52 +00:00
|
|
|
var bytes = uint64(i).toBytesLE()
|
|
|
|
static: doAssert sizeof(bytes) <= sizeof(result.data)
|
|
|
|
copyMem(addr result.data[0], addr bytes[0], sizeof(bytes))
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-01-17 18:27:11 +00:00
|
|
|
func hackPrivKey(v: Validator): ValidatorPrivKey =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Extract private key, per above hack
|
2019-07-24 06:19:52 +00:00
|
|
|
var bytes: array[8, byte]
|
|
|
|
static: doAssert sizeof(bytes) <= sizeof(v.withdrawal_credentials.data)
|
|
|
|
|
2018-12-13 16:00:55 +00:00
|
|
|
copyMem(
|
2019-07-24 06:19:52 +00:00
|
|
|
addr bytes, unsafeAddr v.withdrawal_credentials.data[0], sizeof(bytes))
|
|
|
|
let i = int(uint64.fromBytesLE(bytes))
|
2019-03-07 13:59:28 +00:00
|
|
|
makeFakeValidatorPrivKey(i)
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
func makeDeposit(i: int, flags: UpdateFlags): Deposit =
|
2018-12-13 16:00:55 +00:00
|
|
|
## Ugly hack for now: we stick the private key in withdrawal_credentials
|
|
|
|
## which means we can repro private key and randao reveal from this data,
|
|
|
|
## for testing :)
|
|
|
|
let
|
2019-03-07 13:59:28 +00:00
|
|
|
privkey = makeFakeValidatorPrivKey(i)
|
2019-02-05 16:13:29 +00:00
|
|
|
pubkey = privkey.pubKey()
|
2018-12-13 16:00:55 +00:00
|
|
|
withdrawal_credentials = makeFakeHash(i)
|
2019-09-25 17:07:08 +00:00
|
|
|
domain = compute_domain(DOMAIN_DEPOSIT)
|
2018-12-27 23:40:22 +00:00
|
|
|
|
2019-05-09 12:27:37 +00:00
|
|
|
result = Deposit(
|
|
|
|
data: DepositData(
|
|
|
|
pubkey: pubkey,
|
|
|
|
withdrawal_credentials: withdrawal_credentials,
|
2019-04-29 16:48:30 +00:00
|
|
|
amount: MAX_EFFECTIVE_BALANCE,
|
2018-12-13 16:00:55 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2019-05-09 12:27:37 +00:00
|
|
|
if skipValidation notin flags:
|
|
|
|
result.data.signature =
|
|
|
|
bls_sign(privkey, signing_root(result.data).data,
|
|
|
|
domain)
|
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
func makeInitialDeposits*(
|
2019-02-20 01:33:58 +00:00
|
|
|
n = SLOTS_PER_EPOCH, flags: UpdateFlags = {}): seq[Deposit] =
|
2018-12-11 17:55:45 +00:00
|
|
|
for i in 0..<n.int:
|
2019-05-09 12:27:37 +00:00
|
|
|
result.add makeDeposit(i, flags)
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2018-12-21 22:37:46 +00:00
|
|
|
proc addBlock*(
|
|
|
|
state: var BeaconState, previous_block_root: Eth2Digest,
|
2018-12-27 23:40:22 +00:00
|
|
|
body: BeaconBlockBody, flags: UpdateFlags = {}): BeaconBlock =
|
2018-12-21 22:37:46 +00:00
|
|
|
# Create and add a block to state - state will advance by one slot!
|
|
|
|
# This is the equivalent of running
|
|
|
|
# updateState(state, prev_block, makeBlock(...), {skipValidation})
|
|
|
|
# but avoids some slow block copies
|
|
|
|
|
|
|
|
state.slot += 1
|
2019-06-24 09:21:56 +00:00
|
|
|
var cache = get_empty_per_epoch_cache()
|
|
|
|
let proposer_index = get_beacon_proposer_index(state, cache)
|
2018-12-21 22:37:46 +00:00
|
|
|
state.slot -= 1
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2018-12-19 04:36:10 +00:00
|
|
|
let
|
|
|
|
# Index from the new state, but registry from the old state.. hmm...
|
2019-07-01 09:13:14 +00:00
|
|
|
proposer = state.validators[proposer_index]
|
2019-02-07 20:13:10 +00:00
|
|
|
privKey = hackPrivKey(proposer)
|
2018-12-19 04:36:10 +00:00
|
|
|
|
2019-03-16 19:52:37 +00:00
|
|
|
# TODO ugly hack; API needs rethinking
|
|
|
|
var new_body = body
|
2019-11-21 09:57:59 +00:00
|
|
|
new_body.randao_reveal = privKey.genRandaoReveal(state.fork, state.slot + 1)
|
2019-03-16 19:52:37 +00:00
|
|
|
new_body.eth1_data = Eth1Data()
|
|
|
|
|
2018-12-19 04:36:10 +00:00
|
|
|
var
|
|
|
|
# In order to reuse the state transition function, we first create a dummy
|
|
|
|
# block that has some fields set, and use that to generate the state as it
|
|
|
|
# would look with the new block applied.
|
|
|
|
new_block = BeaconBlock(
|
|
|
|
slot: state.slot + 1,
|
2019-06-14 13:50:47 +00:00
|
|
|
parent_root: previous_block_root,
|
2018-12-19 04:36:10 +00:00
|
|
|
state_root: Eth2Digest(), # we need the new state first
|
2019-03-27 01:32:35 +00:00
|
|
|
body: new_body,
|
2018-12-19 04:36:10 +00:00
|
|
|
signature: ValidatorSig(), # we need the rest of the block first!
|
2018-12-13 16:00:55 +00:00
|
|
|
)
|
|
|
|
|
2019-07-15 21:10:40 +00:00
|
|
|
let block_ok = state_transition(state, new_block, {skipValidation})
|
2019-03-13 23:04:43 +00:00
|
|
|
doAssert block_ok
|
2018-12-19 04:36:10 +00:00
|
|
|
|
|
|
|
# Ok, we have the new state as it would look with the block applied - now we
|
|
|
|
# can set the state root in order to be able to create a valid signature
|
2019-03-25 16:46:31 +00:00
|
|
|
new_block.state_root = hash_tree_root(state)
|
2018-12-19 04:36:10 +00:00
|
|
|
|
2019-11-21 09:57:59 +00:00
|
|
|
doAssert privKey.pubKey() == proposer.pubkey,
|
2018-12-19 04:36:10 +00:00
|
|
|
"signature key should be derived from private key! - wrong privkey?"
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2018-12-27 23:40:22 +00:00
|
|
|
if skipValidation notin flags:
|
2019-05-09 12:27:37 +00:00
|
|
|
let block_root = signing_root(new_block)
|
2018-12-27 23:40:22 +00:00
|
|
|
# We have a signature - put it in the block and we should be done!
|
|
|
|
new_block.signature =
|
2019-11-21 09:57:59 +00:00
|
|
|
bls_sign(privKey, block_root.data,
|
|
|
|
get_domain(state, DOMAIN_BEACON_PROPOSER,
|
|
|
|
compute_epoch_at_slot(new_block.slot)))
|
2018-12-13 16:00:55 +00:00
|
|
|
|
2019-03-13 23:04:43 +00:00
|
|
|
doAssert bls_verify(
|
2018-12-27 23:40:22 +00:00
|
|
|
proposer.pubkey,
|
2019-03-27 01:32:35 +00:00
|
|
|
block_root.data, new_block.signature,
|
2019-11-21 09:57:59 +00:00
|
|
|
get_domain(
|
|
|
|
state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(new_block.slot))),
|
2018-12-27 23:40:22 +00:00
|
|
|
"we just signed this message - it should pass verification!"
|
2018-12-13 16:00:55 +00:00
|
|
|
|
|
|
|
new_block
|
2018-12-21 22:37:46 +00:00
|
|
|
|
|
|
|
proc makeBlock*(
|
|
|
|
state: BeaconState, previous_block_root: Eth2Digest,
|
|
|
|
body: BeaconBlockBody): BeaconBlock =
|
|
|
|
# Create a block for `state.slot + 1` - like a block proposer would do!
|
|
|
|
# It's a bit awkward - in order to produce a block for N+1, we need to
|
|
|
|
# calculate what the state will look like after that block has been applied,
|
|
|
|
# because the block includes the state root.
|
|
|
|
var next_state = state
|
|
|
|
addBlock(next_state, previous_block_root, body)
|
2018-12-21 23:47:55 +00:00
|
|
|
|
2019-11-14 17:37:51 +00:00
|
|
|
proc find_beacon_committee(
|
2019-11-15 22:37:39 +00:00
|
|
|
state: BeaconState, validator_index: ValidatorIndex,
|
|
|
|
cache: var StateCache): auto =
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
let epoch = compute_epoch_at_slot(state.slot)
|
2019-11-14 17:37:51 +00:00
|
|
|
for epoch_committee_index in 0'u64 ..< get_committee_count_at_slot(
|
2019-11-11 08:11:46 +00:00
|
|
|
state, epoch.compute_start_slot_at_epoch) * SLOTS_PER_EPOCH:
|
2019-11-14 17:37:51 +00:00
|
|
|
let
|
|
|
|
slot = ((epoch_committee_index mod SLOTS_PER_EPOCH) +
|
|
|
|
epoch.compute_start_slot_at_epoch.uint64).Slot
|
|
|
|
index = epoch_committee_index div SLOTS_PER_EPOCH
|
|
|
|
committee = get_beacon_committee(state, slot, index, cache)
|
2019-06-24 09:21:56 +00:00
|
|
|
if validator_index in committee:
|
2019-11-14 17:37:51 +00:00
|
|
|
return (committee, slot, index)
|
2018-12-21 23:47:55 +00:00
|
|
|
doAssert false
|
|
|
|
|
|
|
|
proc makeAttestation*(
|
|
|
|
state: BeaconState, beacon_block_root: Eth2Digest,
|
2019-11-27 22:48:12 +00:00
|
|
|
committee: seq[ValidatorIndex], slot: Slot, index: uint64,
|
|
|
|
validator_index: auto, cache: var StateCache,
|
2019-11-15 22:37:39 +00:00
|
|
|
flags: UpdateFlags = {}): Attestation =
|
2019-11-27 22:48:12 +00:00
|
|
|
# Avoids state_sim silliness; as it's responsible for all validators,
|
|
|
|
# transforming, from monotonic enumerable index -> committee index ->
|
|
|
|
# montonoic enumerable index, is wasteful and slow. Most test callers
|
|
|
|
# want ValidatorIndex, so that's supported too.
|
2018-12-21 23:47:55 +00:00
|
|
|
let
|
2019-07-01 09:13:14 +00:00
|
|
|
validator = state.validators[validator_index]
|
2019-06-24 09:21:56 +00:00
|
|
|
sac_index = committee.find(validator_index)
|
2019-11-14 17:37:51 +00:00
|
|
|
data = makeAttestationData(state, slot, index, beacon_block_root)
|
2018-12-21 23:47:55 +00:00
|
|
|
|
2019-11-15 22:37:39 +00:00
|
|
|
doAssert sac_index != -1, "find_beacon_committee should guarantee this"
|
2018-12-21 23:47:55 +00:00
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
var aggregation_bits = CommitteeValidatorsBits.init(committee.len)
|
|
|
|
aggregation_bits.raiseBit sac_index
|
2018-12-21 23:47:55 +00:00
|
|
|
|
|
|
|
let
|
2019-11-13 11:30:11 +00:00
|
|
|
msg = hash_tree_root(data)
|
2018-12-27 23:40:22 +00:00
|
|
|
sig =
|
|
|
|
if skipValidation notin flags:
|
2019-02-28 21:24:43 +00:00
|
|
|
bls_sign(
|
|
|
|
hackPrivKey(validator), @(msg.data),
|
|
|
|
get_domain(
|
2019-04-29 16:48:30 +00:00
|
|
|
state,
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
DOMAIN_BEACON_ATTESTER,
|
2019-11-13 11:30:11 +00:00
|
|
|
data.target.epoch))
|
2018-12-27 23:40:22 +00:00
|
|
|
else:
|
|
|
|
ValidatorSig()
|
2018-12-21 23:47:55 +00:00
|
|
|
|
|
|
|
Attestation(
|
|
|
|
data: data,
|
2019-07-01 07:53:42 +00:00
|
|
|
aggregation_bits: aggregation_bits,
|
2019-11-13 11:30:11 +00:00
|
|
|
signature: sig
|
2018-12-21 23:47:55 +00:00
|
|
|
)
|
2019-02-28 21:21:29 +00:00
|
|
|
|
2019-11-27 22:48:12 +00:00
|
|
|
proc makeAttestation*(
|
|
|
|
state: BeaconState, beacon_block_root: Eth2Digest,
|
|
|
|
validator_index: ValidatorIndex, cache: var StateCache,
|
|
|
|
flags: UpdateFlags = {}): Attestation =
|
|
|
|
let (committee, slot, index) =
|
|
|
|
find_beacon_committee(state, validator_index, cache)
|
|
|
|
makeAttestation(state, beacon_block_root, committee, slot, index,
|
|
|
|
validator_index, cache, flags)
|
|
|
|
|
2019-02-28 21:21:29 +00:00
|
|
|
proc makeTestDB*(tailState: BeaconState, tailBlock: BeaconBlock): BeaconChainDB =
|
|
|
|
result = init(BeaconChainDB, newMemoryDB())
|
2019-03-28 06:10:48 +00:00
|
|
|
BlockPool.preInit(result, tailState, tailBlock)
|