Revamp per block processing / state transition
This commit is contained in:
parent
0b560f7307
commit
14bb9b6efd
|
@ -11,22 +11,21 @@ import intsets, eth_common, math
|
||||||
# ⚠ Spec is updated very often, implementation might quickly be outdated
|
# ⚠ Spec is updated very often, implementation might quickly be outdated
|
||||||
|
|
||||||
type
|
type
|
||||||
Keccak256_Digest* = Hash256 # TODO, previously Keccak256 fields used the "bytes" type
|
Blake2_256_Digest* = Hash256 # TODO change to Blake2b-512[0 ..< 32] see https://github.com/status-im/nim-beacon-chain/issues/3
|
||||||
Blake2_256_Digest* = Hash256 # while Blake2 used hash32, but latest spec changed everything to hash32
|
|
||||||
Uint24* = range[0'u32 .. 0xFFFFFF'u32] # TODO: wrap-around
|
Uint24* = range[0'u32 .. 0xFFFFFF'u32] # TODO: wrap-around
|
||||||
|
|
||||||
BeaconBlock* = object
|
BeaconBlock* = object
|
||||||
parent_hash*: Keccak256_Digest # Hash of the parent block
|
parent_hash*: Blake2_256_Digest # Hash of the parent block
|
||||||
slot_number*: int64 # Slot number (for the PoS mechanism)
|
slot_number*: int64 # Slot number (for the PoS mechanism)
|
||||||
randao_reveal*: Keccak256_Digest # Randao commitment reveal
|
randao_reveal*: Blake2_256_Digest # Randao commitment reveal
|
||||||
attestations*: seq[AttestationRecord] # Attestation votes
|
attestations*: seq[AttestationRecord] # Attestation votes
|
||||||
pow_chain_ref*: Keccak256_Digest # Reference to main chain block
|
pow_chain_ref*: Blake2_256_Digest # Reference to main chain block
|
||||||
active_state_root*: Blake2_256_Digest # Hash of the active state
|
active_state_root*: Blake2_256_Digest # Hash of the active state
|
||||||
crystallized_state_root*: Blake2_256_Digest # Hash of the crystallized state
|
crystallized_state_root*: Blake2_256_Digest # Hash of the crystallized state
|
||||||
|
|
||||||
ActiveState* = object
|
ActiveState* = object
|
||||||
pending_attestations*: seq[AttestationRecord] # Attestations that have not yet been processed
|
pending_attestations*: seq[AttestationRecord] # Attestations that have not yet been processed
|
||||||
recent_block_hashes*: seq[Keccak256_Digest] # Most recent 2 * CYCLE_LENGTH block hashes, older to newer
|
recent_block_hashes*: seq[Blake2_256_Digest] # Most recent 2 * CYCLE_LENGTH block hashes, older to newer
|
||||||
|
|
||||||
CrystallizedState* = object
|
CrystallizedState* = object
|
||||||
validators*: seq[ValidatorRecord] # List of active validators
|
validators*: seq[ValidatorRecord] # List of active validators
|
||||||
|
@ -42,7 +41,7 @@ type
|
||||||
crosslinking_start_shard*: int16 # The next shard that cross-linking assignment will start from
|
crosslinking_start_shard*: int16 # The next shard that cross-linking assignment will start from
|
||||||
crosslink_records*: seq[CrosslinkRecord] # Records about the most recent crosslink for each shard
|
crosslink_records*: seq[CrosslinkRecord] # Records about the most recent crosslink for each shard
|
||||||
total_deposits*: Int256 # Total balance of deposits
|
total_deposits*: Int256 # Total balance of deposits
|
||||||
dynasty_seed*: Keccak256_Digest # Used to select the committees for each shard
|
dynasty_seed*: Blake2_256_Digest # Used to select the committees for each shard
|
||||||
dynasty_seed_last_reset*: int64 # Last epoch the crosslink seed was reset
|
dynasty_seed_last_reset*: int64 # Last epoch the crosslink seed was reset
|
||||||
|
|
||||||
ShardAndCommittee* = object
|
ShardAndCommittee* = object
|
||||||
|
@ -53,14 +52,14 @@ type
|
||||||
pubkey*: BLSPublicKey # The validator's public key
|
pubkey*: BLSPublicKey # The validator's public key
|
||||||
withdrawal_shard*: int16 # What shard the validator's balance will be sent to after withdrawal
|
withdrawal_shard*: int16 # What shard the validator's balance will be sent to after withdrawal
|
||||||
withdrawal_address*: EthAddress # And what address
|
withdrawal_address*: EthAddress # And what address
|
||||||
randao_commitment*: Keccak256_Digest # The validator's current RANDAO beacon commitment
|
randao_commitment*: Blake2_256_Digest # The validator's current RANDAO beacon commitment
|
||||||
balance*: int64 # Current balance
|
balance*: int64 # Current balance
|
||||||
start_dynasty*: int64 # Dynasty where the validator is inducted
|
start_dynasty*: int64 # Dynasty where the validator is inducted
|
||||||
end_dynasty*: int64 # Dynasty where the validator leaves
|
end_dynasty*: int64 # Dynasty where the validator leaves
|
||||||
|
|
||||||
CrosslinkRecord* = object
|
CrosslinkRecord* = object
|
||||||
dynasty: int64 # What dynasty the crosslink was submitted in
|
dynasty: int64 # What dynasty the crosslink was submitted in
|
||||||
hash: Keccak256_Digest # The block hash
|
hash: Blake2_256_Digest # The block hash
|
||||||
|
|
||||||
BLSPublicKey = object
|
BLSPublicKey = object
|
||||||
# Stub for BLS signature
|
# Stub for BLS signature
|
||||||
|
@ -69,10 +68,10 @@ type
|
||||||
AttestationRecord* = object
|
AttestationRecord* = object
|
||||||
slot*: int64 # Slot number
|
slot*: int64 # Slot number
|
||||||
shard_id*: int16 # Shard ID
|
shard_id*: int16 # Shard ID
|
||||||
oblique_parent_hashes*: seq[Keccak256_Digest]
|
oblique_parent_hashes*: seq[Blake2_256_Digest]
|
||||||
# List of block hashes that this signature is signing over that
|
# List of block hashes that this signature is signing over that
|
||||||
# are NOT part of the current chain, in order of oldest to newest
|
# are NOT part of the current chain, in order of oldest to newest
|
||||||
shard_block_hash*: Keccak256_Digest # Block hash in the in the shard that we are attesting to
|
shard_block_hash*: Blake2_256_Digest # Block hash in the shard that we are attesting to
|
||||||
attester_bitfield*: IntSet # Who is participating
|
attester_bitfield*: IntSet # Who is participating
|
||||||
aggregateSig*: seq[BLSPublicKey] # The actual signature
|
aggregateSig*: seq[BLSPublicKey] # The actual signature
|
||||||
# Note:
|
# Note:
|
||||||
|
|
|
@ -21,7 +21,7 @@ func checkPartialCrosslinkRecords*(beaconBlock: BeaconBlock, crystalState: Cryst
|
||||||
if heightInEpoch < EpochLength - EndEpochGracePeriod:
|
if heightInEpoch < EpochLength - EndEpochGracePeriod:
|
||||||
assert heightCutoffs[height_in_epoch] <= int(shardCutoffs[si] < heightCutoffs[heightInEpoch + 1]) # TODO Spec unclear
|
assert heightCutoffs[height_in_epoch] <= int(shardCutoffs[si] < heightCutoffs[heightInEpoch + 1]) # TODO Spec unclear
|
||||||
else:
|
else:
|
||||||
assert vote.shardId == 65535 and vote.shardBlockHash == Keccak256_Digest()
|
assert vote.shardId == 65535 and vote.shardBlockHash == Blake2_256_Digest()
|
||||||
|
|
||||||
var shard_start, shard_end: int
|
var shard_start, shard_end: int
|
||||||
if heightInEpoch < EpochLength - 8:
|
if heightInEpoch < EpochLength - 8:
|
|
@ -91,13 +91,23 @@ func get_indices_for_slot*(crystallized_state: CrystallizedState,
|
||||||
# Clarify with EF if light clients will need the beacon chain
|
# Clarify with EF if light clients will need the beacon chain
|
||||||
|
|
||||||
func get_block_hash*(active_state: ActiveState,
|
func get_block_hash*(active_state: ActiveState,
|
||||||
beacon_block: BeaconBlock, slot: int64): Keccak256_Digest =
|
beacon_block: BeaconBlock, slot: int64): Blake2_256_Digest =
|
||||||
|
|
||||||
# TODO: Spec uses crystallized_state as arg and activ_state.slot_number
|
|
||||||
# which doesn't exist
|
|
||||||
|
|
||||||
let sback = beacon_block.slot_number - CYCLE_LENGTH * 2
|
let sback = beacon_block.slot_number - CYCLE_LENGTH * 2
|
||||||
assert sback <= slot
|
assert sback <= slot
|
||||||
assert slot < sback + CYCLE_LENGTH * 2
|
assert slot < sback + CYCLE_LENGTH * 2
|
||||||
|
|
||||||
result = active_state.recent_block_hashes[int slot - sback]
|
result = active_state.recent_block_hashes[int slot - sback]
|
||||||
|
|
||||||
|
func get_new_recent_block_hashes*(
|
||||||
|
old_block_hashes: seq[Blake2_256_Digest],
|
||||||
|
parent_slot, current_slot: int64,
|
||||||
|
parent_hash: Blake2_256_Digest
|
||||||
|
): seq[Blake2_256_Digest] =
|
||||||
|
|
||||||
|
# Should throw for `current_slot - CYCLE_LENGTH * 2 - 1` according to spec comment
|
||||||
|
let d = current_slot - parent_slot
|
||||||
|
result = old_block_hashes[d .. ^1]
|
||||||
|
for _ in 0 ..< min(d, old_block_hashes.len):
|
||||||
|
result.add parent_hash
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# beacon_chain
|
||||||
|
# Copyright (c) 2018 Status Research & Development GmbH
|
||||||
|
# Licensed and distributed under either of
|
||||||
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||||
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
|
# Note: this is also inspired by https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/state/state_transition.py
|
||||||
|
# The official spec at https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ# is not fully
|
||||||
|
# defining the state transitions.
|
||||||
|
#
|
||||||
|
# Note that the ethresearch impl is using "block_vote_cache" field, which is a dictionary mapping hashes
|
||||||
|
# to the following sub-dictionary:
|
||||||
|
# {
|
||||||
|
# 'voter_indices': set(),
|
||||||
|
# 'total_voter_deposits': 0
|
||||||
|
# }
|
||||||
|
# It should not be needed anymore with the new AttestationRecord type
|
||||||
|
|
||||||
|
{.warning: "The official spec at https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ# is not fully defining state transitions.".}
|
||||||
|
|
||||||
|
import ./datatypes, ./private/helpers
|
||||||
|
|
||||||
|
|
||||||
|
func process_block(active_state: ActiveState, crystallized_state: CrystallizedState, blck: BeaconBlock, slot: int64) =
|
||||||
|
# TODO: unfinished spec
|
||||||
|
|
||||||
|
for attestation in blck.attestations:
|
||||||
|
# Verify that slot < block.slot_number and slot >= max(block.slot_number - CYCLE_LENGTH, 0)
|
||||||
|
doAssert slot < blck.slot_number
|
||||||
|
doAssert slot >= max(blck.slot_number - CYCLE_LENGTH, 0)
|
||||||
|
|
||||||
|
# Compute parent_hashes = [get_block_hash(active_state, block, slot - CYCLE_LENGTH + i) for i in range(CYCLE_LENGTH - len(oblique_parent_hashes))] + oblique_parent_hashes
|
||||||
|
# TODO - don't allocate in tight loop
|
||||||
|
var parent_hashes = newSeq[Blake2_256_Digest](CYCLE_LENGTH - attestation.oblique_parent_hashes.len)
|
||||||
|
for idx, val in parent_hashes.mpairs:
|
||||||
|
val = get_block_hash(active_state, blck, slot - CYCLE_LENGTH + idx)
|
||||||
|
parent_hashes.add attestation.oblique_parent_hashes
|
||||||
|
|
||||||
|
# Let attestation_indices be get_indices_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:
|
||||||
|
let shard_and_committees = get_indices_for_slot(crystallized_state, slot)
|
||||||
|
var
|
||||||
|
x = 1
|
||||||
|
record_creator = shard_and_committees[0]
|
||||||
|
while record_creator.shard_id != attestation.shard_id:
|
||||||
|
record_creator = shard_and_committees[x]
|
||||||
|
inc x
|
||||||
|
record_creator
|
||||||
|
|
||||||
|
# Verify that len(attester_bitfield) == ceil_div8(len(attestation_indices)), where ceil_div8 = (x + 7) // 8. Verify that bits len(attestation_indices).... and higher, if present (i.e. len(attestation_indices) is not a multiple of 8), are all zero
|
||||||
|
doAssert attestation.attester_bitfield.len == attestation_indices.committee.len
|
||||||
|
|
||||||
|
# Derive a group public key by adding the public keys of all of the attesters in attestation_indices for whom the corresponding bit in attester_bitfield (the ith bit is (attester_bitfield[i // 8] >> (7 - (i %8))) % 2) equals 1
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# Verify that aggregate_sig verifies using the group pubkey generated and hash((slot % CYCLE_LENGTH).to_bytes(8, 'big') + parent_hashes + shard_id + shard_block_hash) as the message.
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# Extend the list of AttestationRecord objects in the active_state, ordering the new additions in the same order as they came in the block.
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# Verify that the slot % len(get_indices_for_slot(crystallized_state, slot-1)[0])'th attester in get_indices_for_slot(crystallized_state, slot-1)[0]is part of at least one of the AttestationRecord objects; this attester can be considered to be the proposer of the block.
|
||||||
|
# TODO
|
Loading…
Reference in New Issue