assorted fixes; some of algorithms aren't 100% updated yet, but want to get data structures in place

This commit is contained in:
Dustin Brody 2018-11-27 20:23:27 -08:00
parent 548b6922ba
commit e63b452181
4 changed files with 105 additions and 111 deletions

View File

@ -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
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*: 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
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

View File

@ -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] =

View File

@ -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)

View File

@ -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