mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-10 22:36:01 +00:00
assorted fixes; some of algorithms aren't 100% updated yet, but want to get data structures in place
This commit is contained in:
parent
548b6922ba
commit
e63b452181
@ -9,7 +9,7 @@
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/master/specs/beacon-chain.md
|
||||
#
|
||||
# How wrong the code is:
|
||||
# https://github.com/ethereum/eth2.0-specs/compare/98312f40b5742de6aa73f24e6225ee68277c4614...master
|
||||
# https://github.com/ethereum/eth2.0-specs/compare/126a7abfa86448091a0e037f52966b6a9531a857...master
|
||||
|
||||
import
|
||||
intsets, eth_common, math, stint, digest
|
||||
@ -24,32 +24,35 @@ import milagro_crypto
|
||||
const
|
||||
SHARD_COUNT* = 1024 # a constant referring to the number of shards
|
||||
DEPOSIT_SIZE* = 2^5 # You need to deposit 32 ETH to be a validator in Casper
|
||||
MIN_TOPUP_SIZE* = 1 # ETH
|
||||
MIN_ONLINE_DEPOSIT_SIZE* = 2^4 # ETH
|
||||
GWEI_PER_ETH* = 10^9 # Gwei/ETH
|
||||
DEPOSITS_FOR_CHAIN_START* = 2^14 # deposits
|
||||
TARGET_COMMITTEE_SIZE* = 2^8 # validators
|
||||
SLOT_DURATION* = 6 # seconds
|
||||
CYCLE_LENGTH* = 64 # slots (~ 6 minutes)
|
||||
MIN_VALIDATOR_SET_CHANGE_INTERVAL* = 2^8 # slots (~25 minutes)
|
||||
SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD* = 2^17 # slots (~9 days)
|
||||
MIN_ATTESTATION_INCLUSION_DELAY* = 2^2 # slots (~25 minutes)
|
||||
SQRT_E_DROP_TIME* = 2^16 # slots (~12 days); amount of time it takes for the
|
||||
MIN_ATTESTATION_INCLUSION_DELAY* = 4 # slots (~25 minutes)
|
||||
SQRT_E_DROP_TIME* = 2^9 # slots (~9 days); amount of time it takes for the
|
||||
# quadratic leak to cut deposits of non-participating
|
||||
# validators by ~39.4%
|
||||
WITHDRAWALS_PER_CYCLE* = 2^2 # validators (5.2m ETH in ~6 months)
|
||||
MIN_WITHDRAWAL_PERIOD* = 2^13 # slots (~14 hours)
|
||||
DELETION_PERIOD* = 2^22 # slots (~290 days)
|
||||
COLLECTIVE_PENALTY_CALCULATION_PERIOD* = 2^20 # slots (~2.4 months)
|
||||
POW_RECEIPT_ROOT_VOTING_PERIOD* = 2^10 # slots (~1.7 hours)
|
||||
SLASHING_WHISTLEBLOWER_REWARD_DENOMINATOR* = 2^9 # ?
|
||||
BASE_REWARD_QUOTIENT* = 2^15 # per-slot interest rate assuming all validators are
|
||||
BASE_REWARD_QUOTIENT* = 2^11 # per-cycle interest rate assuming all validators are
|
||||
# participating, assuming total deposits of 1 ETH. It
|
||||
# corresponds to ~3.88% annual interest assuming 10
|
||||
# corresponds to ~2.57% annual interest assuming 10
|
||||
# million participating ETH.
|
||||
MAX_VALIDATOR_CHURN_QUOTIENT* = 2^5 # At most `1/MAX_VALIDATOR_CHURN_QUOTIENT` of the
|
||||
# validators can change during each validator set
|
||||
# change.
|
||||
POW_HASH_VOTING_PERIOD* = 2^10 # ?
|
||||
POW_CONTRACT_MERKLE_TREE_DEPTH* = 2^5 #
|
||||
INITIAL_FORK_VERSION* = 0 # currently behaves like a constant
|
||||
MAX_ATTESTATION_COUNT* = 2^7 #
|
||||
INITIAL_FORK_VERSION* = 0 #
|
||||
|
||||
type
|
||||
# Alias
|
||||
@ -58,14 +61,10 @@ type
|
||||
|
||||
Uint24* = range[0'u32 .. 0xFFFFFF'u32] # TODO: wrap-around
|
||||
|
||||
SpecialRecord* = object
|
||||
kind*: SpecialRecordTypes # Kind
|
||||
data*: seq[byte] # Data
|
||||
|
||||
BeaconBlock* = object
|
||||
slot*: uint64 # Slot number
|
||||
randao_reveal*: Eth2Digest # Proposer RANDAO reveal
|
||||
candidate_pow_receipt_root*: Eth2Digest # Recent PoW chain reference (receipt root)
|
||||
candidate_pow_receipt_root*: Eth2Digest # Recent PoW receipt root
|
||||
ancestor_hashes*: seq[Eth2Digest] # Skip list of previous beacon block hashes
|
||||
# i'th item is most recent ancestor whose
|
||||
# slot is a multiple of 2**i for
|
||||
@ -75,49 +74,30 @@ type
|
||||
specials*: seq[SpecialRecord] # Specials (e.g. logouts, penalties)
|
||||
proposer_signature*: BLSSig # Proposer signature
|
||||
|
||||
ProposalSignedData* = object
|
||||
fork_version*: uint64 # Fork version
|
||||
slot*: uint64 # Slot number
|
||||
shard_id*: uint64 # Shard ID (or `2**64 - 1` for beacon chain)
|
||||
block_hash*: Eth2Digest # Block hash
|
||||
AttestationRecord* = object
|
||||
data*: AttestationSignedData #
|
||||
attester_bitfield*: seq[byte] # Attester participation bitfield
|
||||
poc_bitfield*: seq[byte] # Proof of custody bitfield
|
||||
aggregate_sig*: BLSSig # BLS aggregate signature
|
||||
|
||||
AttestationSignedData* = object
|
||||
fork_version*: uint64 # Fork version
|
||||
slot*: uint64 # Slot number
|
||||
shard*: uint16 # Shard number
|
||||
parent_hashes*: seq[Eth2Digest] # CYCLE_LENGTH parent hashes
|
||||
shard_block_hash*: Eth2Digest # Shard block hash
|
||||
shard*: uint64 # Shard number
|
||||
block_hash*: Eth2Digest # Hash of the block we're signing
|
||||
cycle_boundary_hash*: Eth2Digest # Hash of the ancestor at the cycle boundary
|
||||
shard_block_hash*: Eth2Digest # Shard block hash being attested to
|
||||
last_crosslink_hash*: Eth2Digest # Last crosslink hash
|
||||
shard_block_combined_data_root*: Eth2Digest
|
||||
# Root of data between last hash and this one
|
||||
justified_slot*: uint64 # Slot of last justified beacon block referenced in the attestation
|
||||
|
||||
ShardAndCommittee* = object
|
||||
shard_id*: uint16 # Shard number
|
||||
committee*: seq[Uint24] # Validator indices
|
||||
|
||||
ShardReassignmentRecord* = object
|
||||
validator_index*: Uint24 # Which validator to reassign
|
||||
shard*: uint16 # To which shard
|
||||
slot*: uint64 # When
|
||||
|
||||
CrosslinkRecord* = object
|
||||
slot*: uint64 # Slot number
|
||||
hash*: Eth2Digest # Shard chain block hash
|
||||
|
||||
AttestationRecord* = object
|
||||
slot*: uint64 # Slot number
|
||||
shard*: uint16 # Shard number
|
||||
oblique_parent_hashes*: seq[Eth2Digest]
|
||||
# Beacon block hashes not part of the current chain, oldest to newest
|
||||
shard_block_hash*: Eth2Digest # Shard block hash being attested to
|
||||
last_crosslink_hash*: Eth2Digest # Last crosslink hash
|
||||
shard_block_combined_data_root*: Eth2Digest
|
||||
# Root of data between last hash and this one
|
||||
attester_bitfield*: IntSet # Attester participation bitfield (1 bit per attester)
|
||||
justified_slot*: uint64 # Slot of last justified beacon block
|
||||
justified_block_hash*: Eth2Digest # Hash of last justified beacon block
|
||||
aggregate_sig*: BLSSig # BLS aggregate signature
|
||||
|
||||
ProposalSignedData* = object
|
||||
slot*: uint64 # Slot number
|
||||
shard*: uint64 # Shard number (or `2**64 - 1` for beacon chain)
|
||||
block_hash*: Eth2Digest # Block hash
|
||||
|
||||
SpecialRecord* = object
|
||||
kind*: SpecialRecordTypes # Kind
|
||||
data*: seq[byte] # Data
|
||||
|
||||
BeaconState* = object
|
||||
validator_set_change_slot*: uint64 # Slot of last validator set change
|
||||
@ -125,45 +105,64 @@ type
|
||||
crosslinks*: seq[CrosslinkRecord] # Most recent crosslink for each shard
|
||||
last_state_recalculation_slot*: uint64 # Last cycle-boundary state recalculation
|
||||
last_finalized_slot*: uint64 # Last finalized slot
|
||||
last_justified_slot*: uint64 # Last justified slot
|
||||
justified_streak*: uint64 # Number of consecutive justified slots
|
||||
justification_source*: uint64 # Justification source
|
||||
prev_cycle_justification_source*: uint64 #
|
||||
justified_slot_bitfield*: uint64 # Recent justified slot bitmask
|
||||
shard_and_committee_for_slots*: array[2 * CYCLE_LENGTH, seq[ShardAndCommittee]] ## \
|
||||
## Committee members and their assigned shard, per slot, covers 2 cycles
|
||||
## worth of assignments
|
||||
persistent_committees*: seq[seq[ValidatorRecord]] # Persistent shard committees
|
||||
persistent_committees*: seq[seq[Uint24]] # Persistent shard committees
|
||||
persistent_committee_reassignments*: seq[ShardReassignmentRecord]
|
||||
next_shuffling_seed*: Eth2Digest # Randao seed used for next shuffling
|
||||
deposits_penalized_in_period*: uint32 # Total deposits penalized in the given withdrawal period
|
||||
validator_set_delta_hash_chain*: Eth2Digest # Hash chain of validator set changes (for light clients to easily track deltas)
|
||||
current_exit_seq*: uint64 # Current sequence number for withdrawals
|
||||
genesis_time*: uint64 # Genesis time
|
||||
known_pow_receipt_root*: Eth2Digest # PoW chain reference
|
||||
candidate_pow_receipt_root*: Eth2Digest
|
||||
candidate_pow_receipt_root_votes*: Eth2Digest
|
||||
pre_fork_version*: uint32 # Parameters relevant to hard forks / versioning.
|
||||
post_fork_version*: uint32 # Should be updated only by hard forks.
|
||||
fork_slot_number*: uint64
|
||||
candidate_pow_receipt_root*: Eth2Digest # PoW receipt root
|
||||
candidate_pow_receipt_roots*: seq[CandidatePoWReceiptRootRecord] #
|
||||
fork_data*: ForkData # Parameters relevant to hard forks / versioning.
|
||||
# Should be updated only by hard forks.
|
||||
pending_attestations*: seq[AttestationRecord] # Attestations not yet processed
|
||||
recent_block_hashes*: seq[Eth2Digest] # recent beacon block hashes needed to process attestations, older to newer
|
||||
randao_mix*: Eth2Digest # RANDAO state
|
||||
|
||||
ValidatorRecord* = object
|
||||
pubkey*: BLSPublicKey # BLS public key
|
||||
withdrawal_shard*: uint16 # Withdrawal shard number
|
||||
withdrawal_address*: EthAddress # Withdrawal address
|
||||
withdrawal_credentials*: Eth2Digest # Withdrawal credentials
|
||||
randao_commitment*: Eth2Digest # RANDAO commitment
|
||||
randao_last_change*: uint64 # Slot the RANDAO commitment was last changed
|
||||
randao_skips*: uint64 # Slot the proposer has skipped (ie. layers of RANDAO expected)
|
||||
balance*: uint64 # Balance in Gwei
|
||||
status*: ValidatorStatusCodes # Status code
|
||||
exit_slot*: uint64 # Slot when validator exited (or 0)
|
||||
last_status_change_slot*: uint64 # Slot when validator last changed status (or 0)
|
||||
exit_seq*: uint64 # Sequence number when validator exited (or 0)
|
||||
|
||||
InitialValidator* = object
|
||||
pubkey*: BLSPublicKey
|
||||
proof_of_possession*: seq[byte]
|
||||
withdrawal_shard*: uint16
|
||||
withdrawal_address*: EthAddress
|
||||
randao_commitment*: Eth2Digest
|
||||
CrosslinkRecord* = object
|
||||
slot*: uint64 # Slot number
|
||||
hash*: Eth2Digest # Shard chain block hash
|
||||
|
||||
ShardAndCommittee* = object
|
||||
shard*: uint64 # Shard number
|
||||
committee*: seq[Uint24] # Validator indices
|
||||
|
||||
ShardReassignmentRecord* = object
|
||||
validator_index*: Uint24 # Which validator to reassign
|
||||
shard*: uint64 # To which shard
|
||||
slot*: uint64 # When
|
||||
|
||||
CandidatePoWReceiptRootRecord* = object
|
||||
candidate_pow_receipt_root*: Eth2Digest # Candidate PoW receipt root
|
||||
votes*: uint64 # Vote count
|
||||
|
||||
ForkData* = object
|
||||
pre_fork_version*: uint64 # Previous fork version
|
||||
post_fork_version*: uint64 # Post fork version
|
||||
fork_slot_number*: uint64 # Fork slot number
|
||||
|
||||
ProcessedAttestation* = object
|
||||
data*: AttestationSignedData # Signed data
|
||||
attester_bitfield*: seq[byte] # Attester participation bitfield (2 bits per attester)
|
||||
poc_bitfield*: seq[byte] # Proof of custody bitfield
|
||||
slot_included*: uint64 # Slot in which it was included
|
||||
|
||||
ValidatorStatusCodes* {.pure.} = enum
|
||||
PendingActivation = 0
|
||||
|
@ -189,17 +189,16 @@ func hashSSZ*(x: ValidatorRecord): array[32, byte] =
|
||||
# XXX hash_ssz.py code contains special cases for some types, why?
|
||||
withHash:
|
||||
# tmp.add(x.pubkey) # XXX uncertain future of public key format
|
||||
h.update hashSSZ(x.withdrawal_shard)
|
||||
h.update hashSSZ(x.withdrawal_address)
|
||||
h.update hashSSZ(x.randao_commitment)
|
||||
h.update hashSSZ(x.randao_last_change)
|
||||
h.update hashSSZ(x.withdrawal_credentials)
|
||||
h.update hashSSZ(x.randao_skips)
|
||||
h.update hashSSZ(x.balance)
|
||||
# h.update hashSSZ(x.status) # XXX it's an enum, deal with it
|
||||
h.update hashSSZ(x.exit_slot)
|
||||
h.update hashSSZ(x.last_status_change_slot)
|
||||
h.update hashSSZ(x.exit_seq)
|
||||
|
||||
func hashSSZ*(x: ShardAndCommittee): array[32, byte] =
|
||||
withHash:
|
||||
h.update hashSSZ(x.shard_id)
|
||||
h.update hashSSZ(x.shard)
|
||||
h.update merkleHash(x.committee)
|
||||
|
||||
func hashSSZ*[T: not enum](x: T): array[32, byte] =
|
||||
@ -238,15 +237,9 @@ func hashSSZ*(x: AttestationRecord): array[32, byte] =
|
||||
## as of https://github.com/ethereum/beacon_chain/pull/133/files
|
||||
## This is a "stub" needed for BeaconBlock hashing
|
||||
withHash:
|
||||
h.update hashSSZ(x.slot)
|
||||
h.update hashSSZ(x.shard)
|
||||
h.update hashSSZ(x.oblique_parent_hashes)
|
||||
h.update hashSSZ(x.shard_block_hash)
|
||||
h.update hashSSZ(x.last_crosslink_hash)
|
||||
h.update hashSSZ(x.shard_block_combined_data_root)
|
||||
# h.update hashSSZ(x.data) # TODO this is now a sub-object of its own
|
||||
# h.update hashSSZ(attester_bitfield) # TODO - the bitfield as a specific serialisation format
|
||||
h.update hashSSZ(x.justified_slot)
|
||||
h.update hashSSZ(x.justified_block_hash)
|
||||
# h.update hashSSZ(x.poc_bitfield) # TODO - same serialization format
|
||||
h.update hashSSZ(x.aggregate_sig)
|
||||
|
||||
func hashSSZ*(x: BeaconBlock): array[32, byte] =
|
||||
|
@ -26,22 +26,21 @@ import
|
||||
milagro_crypto # nimble install https://github.com/status-im/nim-milagro-crypto@#master
|
||||
|
||||
|
||||
|
||||
func process_block*(active_state: BeaconState, crystallized_state: BeaconState, blck: BeaconBlock, slot: uint64) =
|
||||
# TODO: unfinished spec
|
||||
# TODO: non-attestation verification parts of per-block processing
|
||||
|
||||
#let parent_hash = blck.ancestor_hashes[0]
|
||||
# TODO actually get parent block, which means fixing up BeaconState refs above;
|
||||
# there's no distinction between active/crystallized state anymore, etc.
|
||||
let parent_slot = 0'u64
|
||||
|
||||
for attestation in blck.attestations:
|
||||
## Spec changes: Verify that slot <= parent.slot_number and slot >= max(parent.slot_number - CYCLE_LENGTH + 1, 0)
|
||||
## (Outdated) Verify that slot < block.slot_number and slot >= max(block.slot_number - CYCLE_LENGTH, 0)
|
||||
doAssert slot < blck.slot
|
||||
doAssert slot >= max(blck.slot - CYCLE_LENGTH, 0)
|
||||
|
||||
# Compute parent_hashes = [get_block_hash(active_state, block, slot - CYCLE_LENGTH + i)
|
||||
# for i in range(1, CYCLE_LENGTH - len(oblique_parent_hashes) + 1)] + oblique_parent_hashes
|
||||
# TODO - don't allocate in tight loop
|
||||
var parent_hashes = newSeq[Eth2Digest](CYCLE_LENGTH - attestation.oblique_parent_hashes.len)
|
||||
for idx, val in parent_hashes.mpairs:
|
||||
val = get_block_hash(active_state, blck, cast[int](slot - CYCLE_LENGTH + cast[uint64](idx) + 1))
|
||||
parent_hashes.add attestation.oblique_parent_hashes
|
||||
doAssert attestation.data.slot <= blck.slot - MIN_ATTESTATION_INCLUSION_DELAY
|
||||
doAssert attestation.data.slot >= max(parent_slot - CYCLE_LENGTH + 1, 0)
|
||||
#doAssert attestation.data.justified_slot == justification_source if attestation.data.slot >= state.last_state_recalculation_slot else prev_cycle_justification_source
|
||||
# doAssert attestation.data.justified_block_hash == get_block_hash(state, block, attestation.data.justified_slot).
|
||||
# doAssert either attestation.data.last_crosslink_hash or attestation.data.shard_block_hash equals state.crosslinks[shard].shard_block_hash.
|
||||
|
||||
# Let attestation_indices be get_shards_and_committees_for_slot(crystallized_state, slot)[x], choosing x so that attestation_indices.shard_id equals the shard_id value provided to find the set of validators that is creating this attestation record.
|
||||
let attestation_indices = block:
|
||||
@ -49,7 +48,7 @@ func process_block*(active_state: BeaconState, crystallized_state: BeaconState,
|
||||
var
|
||||
x = 1
|
||||
record_creator = shard_and_committees[0]
|
||||
while record_creator.shard_id != attestation.shard:
|
||||
while record_creator.shard != attestation.data.shard:
|
||||
record_creator = shard_and_committees[x]
|
||||
inc x
|
||||
record_creator
|
||||
@ -61,7 +60,9 @@ func process_block*(active_state: BeaconState, crystallized_state: BeaconState,
|
||||
var agg_pubkey: BLSPublicKey
|
||||
var empty = true
|
||||
for attester_idx in attestation_indices.committee:
|
||||
if attester_idx in attestation.attester_bitfield:
|
||||
# TODO re-enable, but currently this whole function's a nonfunctional stub
|
||||
# because state's lacking.
|
||||
#if attester_idx in attestation.attester_bitfield:
|
||||
let validator = crystallized_state.validators[attester_idx]
|
||||
if empty:
|
||||
agg_pubkey = validator.pubkey
|
||||
@ -77,20 +78,22 @@ func process_block*(active_state: BeaconState, crystallized_state: BeaconState,
|
||||
ctx.init()
|
||||
|
||||
var be_slot: array[8, byte]
|
||||
bigEndian64(be_slot[0].addr, attestation.slot.unsafeAddr)
|
||||
bigEndian64(be_slot[0].addr, attestation.data.slot.unsafeAddr)
|
||||
ctx.update be_slot
|
||||
|
||||
let size_p_hashes = uint parent_hashes.len * sizeof(Eth2Digest)
|
||||
ctx.update(cast[ptr byte](parent_hashes[0].addr), size_p_hashes)
|
||||
# TODO: re-enable these, but parent_hashes isn't in new spec, so
|
||||
# this needs more substantial adjustment.
|
||||
# let size_p_hashes = uint parent_hashes.len * sizeof(Eth2Digest)
|
||||
# ctx.update(cast[ptr byte](parent_hashes[0].addr), size_p_hashes)
|
||||
|
||||
var be_shard_id: array[2, byte] # Unsure, spec doesn't mention big-endian representation
|
||||
bigEndian16(be_shard_id.addr, attestation.shard.unsafeAddr)
|
||||
bigEndian16(be_shard_id.addr, attestation.data.shard.unsafeAddr)
|
||||
ctx.update be_shard_id
|
||||
|
||||
ctx.update attestation.shard_block_hash.data
|
||||
ctx.update attestation.data.shard_block_hash.data
|
||||
|
||||
var be_justified_slot: array[8, byte]
|
||||
bigEndian64(be_justified_slot[0].addr, attestation.justified_slot.unsafeAddr)
|
||||
bigEndian64(be_justified_slot[0].addr, attestation.data.justified_slot.unsafeAddr)
|
||||
ctx.update be_justified_slot
|
||||
|
||||
let h = ctx.finish() # Full hash (Blake2b-512)
|
||||
|
@ -13,14 +13,14 @@ import
|
||||
|
||||
func min_empty_validator(validators: seq[ValidatorRecord], current_slot: uint64): Option[int] =
|
||||
for i, v in validators:
|
||||
if v.status == WITHDRAWN and v.exit_slot + DELETION_PERIOD.uint64 <= current_slot:
|
||||
if v.status == WITHDRAWN and v.last_status_change_slot + DELETION_PERIOD.uint64 <= current_slot:
|
||||
return some(i)
|
||||
|
||||
func add_validator*(validators: var seq[ValidatorRecord],
|
||||
fork_data: ForkData,
|
||||
pubkey: BLSPublicKey,
|
||||
proof_of_possession: seq[byte],
|
||||
withdrawal_shard: uint16,
|
||||
withdrawal_address: EthAddress,
|
||||
withdrawal_credentials: Eth2Digest,
|
||||
randao_commitment: Eth2Digest,
|
||||
status: ValidatorStatusCodes,
|
||||
current_slot: uint64
|
||||
@ -36,13 +36,12 @@ func add_validator*(validators: var seq[ValidatorRecord],
|
||||
let
|
||||
rec = ValidatorRecord(
|
||||
pubkey: pubkey,
|
||||
withdrawal_shard: withdrawal_shard,
|
||||
withdrawal_address: withdrawal_address,
|
||||
withdrawal_credentials: withdrawal_credentials,
|
||||
randao_commitment: randao_commitment,
|
||||
randao_last_change: current_slot,
|
||||
randao_skips: 0,
|
||||
balance: DEPOSIT_SIZE * GWEI_PER_ETH,
|
||||
status: status,
|
||||
exit_slot: 0,
|
||||
last_status_change_slot: current_slot,
|
||||
exit_seq: 0
|
||||
)
|
||||
|
||||
@ -88,7 +87,7 @@ func get_new_shuffling*(seed: Eth2Digest,
|
||||
|
||||
var committees = newSeq[ShardAndCommittee](shard_indices.len)
|
||||
for shard_position, indices in shard_indices:
|
||||
committees[shard_position].shard_id = (shard_id_start + shard_position).uint16 mod SHARD_COUNT
|
||||
committees[shard_position].shard = (shard_id_start + shard_position).uint16 mod SHARD_COUNT
|
||||
committees[shard_position].committee = indices
|
||||
|
||||
result[slot] = committees
|
||||
|
Loading…
x
Reference in New Issue
Block a user