Closed dangerousfood closed 5 years ago
The following data structures are defined as SimpleSerialize (SSZ) objects.
The types are defined topologically to aid in facilitating an executable version of the spec.
Fork
class Fork(Container):
# Previous fork version
previous_version: Bytes4
# Current fork version
current_version: Bytes4
# Fork epoch number
epoch: uint64
Validator
python class Validator(Container): # BLS public key pubkey: Bytes48 # Withdrawal credentials withdrawal_credentials: Bytes32 # Epoch when became eligible for activation activation_eligibility_epoch: uint64 # Epoch when validator activated activation_epoch: uint64 # Epoch when validator exited exit_epoch: uint64 # Epoch when validator is eligible to withdraw withdrawable_epoch: uint64 # Was the validator slashed slashed: bool # Effective balance effective_balance: uint64
Crosslink
python class Crosslink(Container): # Shard number shard: uint64 # Crosslinking data from epochs [start....end-1] start_epoch: uint64 end_epoch: uint64 # Root of the previous crosslink parent_root: Bytes32 # Root of the crosslinked shard data since the previous crosslink data_root: Bytes32
AttestationData
python class AttestationData(Container): # LMD GHOST vote beacon_block_root: Bytes32 # FFG vote source_epoch: uint64 source_root: Bytes32 target_epoch: uint64 target_root: Bytes32 # Crosslink vote crosslink: Crosslink
AttestationDataAndCustodyBit
class AttestationDataAndCustodyBit(Container):
# Attestation data
data: AttestationData
# Custody bit
custody_bit: bool
IndexedAttestation
python class IndexedAttestation(Container): # Validator indices custody_bit_0_indices: List[uint64] custody_bit_1_indices: List[uint64] # Attestation data data: AttestationData # Aggregate signature signature: Bytes96
PendingAttestation
python class PendingAttestation(Container): # Attester aggregation bitfield aggregation_bitfield: bytes # Attestation data data: AttestationData # Inclusion delay inclusion_delay: uint64 # Proposer index proposer_index: uint64
Eth1Data
class Eth1Data(Container):
# Root of the deposit tree
deposit_root: Bytes32
# Total number of deposits
deposit_count: uint64
# Block hash
block_hash: Bytes32
HistoricalBatch
class HistoricalBatch(Container):
# Block roots
block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT]
# State roots
state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT]
DepositData
python class DepositData(Container): # BLS pubkey pubkey: Bytes48 # Withdrawal credentials withdrawal_credentials: Bytes32 # Amount in Gwei amount: uint64 # Container self-signature signature: Bytes96
BeaconBlockHeader
class BeaconBlockHeader(Container):
slot: uint64
<b>parent_root: Bytes32</b>
state_root: Bytes32
<b>body_root: Bytes32</b>
signature: Bytes96
ProposerSlashing
class ProposerSlashing(Container):
# Proposer index
proposer_index: uint64
# First block header
header_1: BeaconBlockHeader
# Second block header
header_2: BeaconBlockHeader
AttesterSlashing
python class AttesterSlashing(Container): # First attestation attestation_1: IndexedAttestation # Second attestation attestation_2: IndexedAttestation
Attestation
class Attestation(Container):
# Attester aggregation bitfield
aggregation_bitfield: bytes
# Attestation data
data: AttestationData
# Custody bitfield
custody_bitfield: bytes
# BLS aggregate signature
signature: Bytes96
Deposit
index field removed
class Deposit(Container):
# Branch in the deposit tree
proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH]
# Data
data: DepositData
VoluntaryExit
class VoluntaryExit(Container):
# Minimum epoch for processing exit
epoch: uint64
# Index of the exiting validator
validator_index: uint64
# Validator signature
signature: Bytes96
Transfer
class Transfer(Container):
# Sender index
sender: uint64
# Recipient index
recipient: uint64
# Amount in Gwei
amount: uint64
# Fee in Gwei for block proposer
fee: uint64
# Inclusion slot
slot: uint64
# Sender withdrawal pubkey
pubkey: Bytes48
# Sender signature
signature: Bytes96
BeaconBlockBody
python class BeaconBlockBody(Container): randao_reveal: Bytes96 eth1_data: Eth1Data graffiti: Bytes32 proposer_slashings: List[ProposerSlashing] attester_slashings: List[AttesterSlashing] attestations: List[Attestation] deposits: List[Deposit] voluntary_exits: List[VoluntaryExit] transfers: List[Transfer]
BeaconBlock
python class BeaconBlock(Container): # Header slot: uint64 parent_root: Bytes32 state_root: Bytes32 body: BeaconBlockBody signature: Bytes96
BeaconState
python class BeaconState(Container): # Misc slot: uint64 genesis_time: uint64 fork: Fork # For versioning hard forks # Validator registry validator_registry: List[Validator] balances: List[uint64] # Randomness and committees latest_randao_mixes: Vector[Bytes32, LATEST_RANDAO_MIXES_LENGTH] latest_start_shard: uint64 # Finality previous_epoch_attestations: List[PendingAttestation] current_epoch_attestations: List[PendingAttestation] previous_justified_epoch: uint64 current_justified_epoch: uint64 previous_justified_root: Bytes32 current_justified_root: Bytes32 justification_bitfield: uint64 finalized_epoch: uint64 finalized_root: Bytes32 # Recent state current_crosslinks: Vector[Crosslink, SHARD_COUNT] previous_crosslinks: Vector[Crosslink, SHARD_COUNT] latest_block_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] latest_state_roots: Vector[Bytes32, SLOTS_PER_HISTORICAL_ROOT] latest_active_index_roots: Vector[Bytes32, LATEST_ACTIVE_INDEX_ROOTS_LENGTH] latest_slashed_balances: Vector[uint64, LATEST_SLASHED_EXIT_LENGTH] latest_block_header: BeaconBlockHeader historical_roots: List[Bytes32] # Ethereum 1.0 chain data latest_eth1_data: Eth1Data eth1_data_votes: List[Eth1Data] deposit_index: uint64
We define the following Python custom types for type hinting and readability:
Name | SSZ equivalent | Description |
---|---|---|
Slot |
uint64 |
a slot number |
Epoch |
uint64 |
an epoch number |
Shard |
uint64 |
a shard number |
ValidatorIndex |
uint64 |
a validator registry index |
Gwei |
uint64 |
an amount in Gwei |
BLSPubkey |
Bytes48 |
a BLS12-381 public key |
BLSSignature |
Bytes96 |
a BLS12-381 signature |
Note: The definitions below are for specification purposes and are not necessarily optimal implementations.
xor
python def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32: return Bytes32(a ^ b for a, b in zip(bytes1, bytes2))
hash
The hash
function is SHA256.
Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethereum 2.0 deployment phase.
hash_tree_root
def hash_tree_root(object: SSZSerializable) -> Bytes32
is a function for hashing objects into a single root utilizing a hash tree structure. hash_tree_root
is defined in the SimpleSerialize spec.
signing_root
def signing_root(object: Container) -> Bytes32
is a function defined in the SimpleSerialize spec to compute signing messages.
bls_domain
python def bls_domain(domain_type: int, fork_version: bytes=b'\x00\x00\x00\x00') -> int: """ Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero). """ return bytes_to_int(int_to_bytes(domain_type, length=4) + fork_version)
slot_to_epoch
def slot_to_epoch(slot: Slot) -> Epoch:
"""
Return the epoch number of the given ``slot``.
"""
return slot // SLOTS_PER_EPOCH
get_previous_epoch
python def get_previous_epoch(state: BeaconState) -> Epoch: """` Return the previous epoch of the given ``state``. Return the current epoch if it's genesis epoch. """ current_epoch = get_current_epoch(state) return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else current_epoch - 1
get_current_epoch
def get_current_epoch(state: BeaconState) -> Epoch:
"""
Return the current epoch of the given ``state``.
"""
return slot_to_epoch(state.slot)
get_epoch_start_slot
def get_epoch_start_slot(epoch: Epoch) -> Slot:
"""
Return the starting slot of the given ``epoch``.
"""
return epoch * SLOTS_PER_EPOCH
is_active_validator
def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
"""
Check if ``validator`` is active.
"""
return validator.activation_epoch <= epoch < validator.exit_epoch
is_slashable_validator
python def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: """ Check if ``validator`` is slashable. """ return validator.slashed is False and (validator.activation_epoch <= epoch < validator.withdrawable_epoch)
get_active_validator_indices
python def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[ValidatorIndex]: """ Get active validator indices at ``epoch``. """ return [i for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)]
increase_balance
python def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: """ Increase validator balance by ``delta``. """ state.balances[index] += delta
decrease_balance
python def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: """ Decrease validator balance by ``delta`` with underflow protection. """ state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
get_epoch_committee_count
python def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int: """ Return the number of committees at ``epoch``. """ active_validator_indices = get_active_validator_indices(state, epoch) return max( 1, min( SHARD_COUNT // SLOTS_PER_EPOCH, len(active_validator_indices) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, ) ) * SLOTS_PER_EPOCH
get_shard_delta
python def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: """ Return the number of shards to increment ``state.latest_start_shard`` during ``epoch``. """ return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH)
get_epoch_start_shard
python def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: assert epoch <= get_current_epoch(state) + 1 check_epoch = get_current_epoch(state) + 1 shard = (state.latest_start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT while check_epoch > epoch: check_epoch -= 1 shard = (shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT return shard
get_attestation_data_slot
python def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot: committee_count = get_epoch_committee_count(state, data.target_epoch) offset = (data.crosslink.shard + SHARD_COUNT - get_epoch_start_shard(state, data.target_epoch)) % SHARD_COUNT return get_epoch_start_slot(data.target_epoch) + offset // (committee_count // SLOTS_PER_EPOCH)
get_block_root_at_slot
python def get_block_root_at_slot(state: BeaconState, slot: Slot) -> Bytes32: """ Return the block root at a recent ``slot``. """ assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
get_block_root
python def get_block_root(state: BeaconState, epoch: Epoch) -> Bytes32: """ Return the block root at a recent ``epoch``. """ return get_block_root_at_slot(state, get_epoch_start_slot(epoch))
get_randao_mix
python def get_randao_mix(state: BeaconState, epoch: Epoch) -> Bytes32: """ Return the randao mix at a recent ``epoch``. ``epoch`` expected to be between (current_epoch - LATEST_RANDAO_MIXES_LENGTH, current_epoch]. """ return state.latest_randao_mixes[epoch % LATEST_RANDAO_MIXES_LENGTH]
get_active_index_root
python def get_active_index_root(state: BeaconState, epoch: Epoch) -> Bytes32: """ Return the index root at a recent ``epoch``. ``epoch`` expected to be between (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY]. """ return state.latest_active_index_roots[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH]
generate_seed
python def generate_seed(state: BeaconState, epoch: Epoch) -> Bytes32: """ Generate a seed for the given ``epoch``. """ return hash( get_randao_mix(state, epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD) + get_active_index_root(state, epoch) + int_to_bytes(epoch, length=32) )
get_beacon_proposer_index
python def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: """ Return the current beacon proposer index. """ epoch = get_current_epoch(state) committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH) shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT first_committee = get_crosslink_committee(state, epoch, shard) MAX_RANDOM_BYTE = 2**8 - 1 seed = generate_seed(state, epoch) i = 0 while True: candidate_index = first_committee[(epoch + i) % len(first_committee)] random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32] effective_balance = state.validator_registry[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: return candidate_index i += 1
verify_merkle_branch
def verify_merkle_branch(leaf: Bytes32, proof: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool:
"""
Verify that the given ``leaf`` is on the merkle branch ``proof``
starting with the given ``root``.
"""
value = leaf
for i in range(depth):
if index // (2**i) % 2:
value = hash(proof[i] + value)
else:
value = hash(value + proof[i])
return value == root
get_shuffled_index
python def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) -> ValidatorIndex: """ Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). """ assert index < index_count assert index_count <= 2**40 # Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf) # See the 'generalized domain' algorithm on page 3 for round in range(SHUFFLE_ROUND_COUNT): pivot = bytes_to_int(hash(seed + int_to_bytes(round, length=1))[0:8]) % index_count flip = (pivot + index_count - index) % index_count position = max(index, flip) source = hash(seed + int_to_bytes(round, length=1) + int_to_bytes(position // 256, length=4)) byte = source[(position % 256) // 8] bit = (byte >> (position % 8)) % 2 index = flip if bit else index return index
compute_committee
python def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: start = (len(indices) * index) // count end = (len(indices) * (index + 1)) // count return [indices[get_shuffled_index(i, len(indices), seed)] for i in range(start, end)]
get_crosslink_committee
python def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> List[ValidatorIndex]: return compute_committee( indices=get_active_validator_indices(state, epoch), seed=generate_seed(state, epoch), index=(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) % SHARD_COUNT, count=get_epoch_committee_count(state, epoch), )
get_attesting_indices
python def get_attesting_indices(state: BeaconState, attestation_data: AttestationData, bitfield: bytes) -> List[ValidatorIndex]: """ Return the sorted attesting indices corresponding to ``attestation_data`` and ``bitfield``. """ committee = get_crosslink_committee(state, attestation_data.target_epoch, attestation_data.crosslink.shard) assert verify_bitfield(bitfield, len(committee)) return sorted([index for i, index in enumerate(committee) if get_bitfield_bit(bitfield, i) == 0b1])
int_to_bytes
python def int_to_bytes(integer: int, length: int) -> bytes: return integer.to_bytes(length, 'little')
bytes_to_int
def bytes_to_int(data: bytes) -> int:
return int.from_bytes(data, 'little')
get_total_balance
python def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.) """ return max(sum([state.validator_registry[index].effective_balance for index in indices]), 1)
get_domain
python def get_domain(state: BeaconState, domain_type: int, message_epoch: int=None) -> int: """ Return the signature domain (fork version concatenated with domain type) of a message. """ epoch = get_current_epoch(state) if message_epoch is None else message_epoch fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version return bls_domain(domain_type, fork_version)
get_bitfield_bit
def get_bitfield_bit(bitfield: bytes, i: int) -> int:
"""
Extract the bit in ``bitfield`` at position ``i``.
"""
return (bitfield[i // 8] >> (i % 8)) % 2
verify_bitfield
def verify_bitfield(bitfield: bytes, committee_size: int) -> bool:
"""
Verify ``bitfield`` against the ``committee_size``.
"""
if len(bitfield) != (committee_size + 7) // 8:
return False
# Check `bitfield` is padded with zero bits only
for i in range(committee_size, len(bitfield) * 8):
if get_bitfield_bit(bitfield, i) == 0b1:
return False
return True
convert_to_indexed
python def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedAttestation: """ Convert ``attestation`` to (almost) indexed-verifiable form. """ attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield) custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bitfield) custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices] return IndexedAttestation( custody_bit_0_indices=custody_bit_0_indices, custody_bit_1_indices=custody_bit_1_indices, data=attestation.data, signature=attestation.signature, )
validate_indexed_attestation
python def validate_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> None: """ Verify validity of ``indexed_attestation``. """ bit_0_indices = indexed_attestation.custody_bit_0_indices bit_1_indices = indexed_attestation.custody_bit_1_indices # Verify no index has custody bit equal to 1 [to be removed in phase 1] assert len(bit_1_indices) == 0 # Verify max number of indices assert len(bit_0_indices) + len(bit_1_indices) <= MAX_INDICES_PER_ATTESTATION # Verify index sets are disjoint assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0 # Verify indices are sorted assert bit_0_indices == sorted(bit_0_indices) and bit_1_indices == sorted(bit_1_indices) # Verify aggregate signature assert bls_verify_multiple( pubkeys=[ bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_0_indices]), bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in bit_1_indices]), ], message_hashes=[ hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)), hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)), ], signature=indexed_attestation.signature, domain=get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.data.target_epoch), )
is_slashable_attestation_data
python def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool: """ Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules. """ return ( # Double vote (data_1 != data_2 and data_1.target_epoch == data_2.target_epoch) or # Surround vote (data_1.source_epoch < data_2.source_epoch and data_2.target_epoch < data_1.target_epoch) )
integer_squareroot
def integer_squareroot(n: int) -> int:
"""
The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``.
"""
assert n >= 0
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
get_delayed_activation_exit_epoch
def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
"""
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
"""
return epoch + 1 + ACTIVATION_EXIT_DELAY
get_churn_limit
python def get_churn_limit(state: BeaconState) -> int: """ Return the churn limit based on the active validator count. """ return max( MIN_PER_EPOCH_CHURN_LIMIT, len(get_active_validator_indices(state, get_current_epoch(state))) // CHURN_LIMIT_QUOTIENT )
bls_verify
bls_verify
is a function for verifying a BLS signature, defined in the BLS Signature spec.
bls_verify_multiple
bls_verify_multiple
is a function for verifying a BLS signature constructed from multiple messages, defined in the BLS Signature spec.
bls_aggregate_pubkeys
bls_aggregate_pubkeys
is a function for aggregating multiple BLS public keys into a single aggregate key, defined in the BLS Signature spec.
Note: All functions in this section mutate state
.
initiate_validator_exit
python def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None: """ Initiate the exit of the validator of the given ``index``. """ # Return if validator already initiated exit validator = state.validator_registry[index] if validator.exit_epoch != FAR_FUTURE_EPOCH: return # Compute exit queue epoch exit_epochs = [v.exit_epoch for v in state.validator_registry if v.exit_epoch != FAR_FUTURE_EPOCH] exit_queue_epoch = max(exit_epochs + [get_delayed_activation_exit_epoch(get_current_epoch(state))]) exit_queue_churn = len([v for v in state.validator_registry if v.exit_epoch == exit_queue_epoch]) if exit_queue_churn >= get_churn_limit(state): exit_queue_epoch += 1 # Set validator exit epoch and withdrawable epoch validator.exit_epoch = exit_queue_epoch validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
slash_validator
python def slash_validator(state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex=None) -> None: """ Slash the validator with index ``slashed_index``. """ current_epoch = get_current_epoch(state) initiate_validator_exit(state, slashed_index) state.validator_registry[slashed_index].slashed = True state.validator_registry[slashed_index].withdrawable_epoch = current_epoch + LATEST_SLASHED_EXIT_LENGTH slashed_balance = state.validator_registry[slashed_index].effective_balance state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance proposer_index = get_beacon_proposer_index(state) if whistleblower_index is None: whistleblower_index = proposer_index whistleblowing_reward = slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT proposer_reward = whistleblowing_reward // PROPOSER_REWARD_QUOTIENT increase_balance(state, proposer_index, proposer_reward) increase_balance(state, whistleblower_index, whistleblowing_reward - proposer_reward) decrease_balance(state, slashed_index, whistleblowing_reward)
Eth2Genesis
When enough deposits of size MAX_EFFECTIVE_BALANCE
have been made to the deposit contract an Eth2Genesis
log is emitted triggering the genesis of the beacon chain. Let:
eth2genesis
be the object corresponding to Eth2Genesis
genesis_eth1_data
be object of type Eth1Data
where
genesis_eth1_data.deposit_root = eth2genesis.deposit_root
genesis_eth1_data.deposit_count = eth2genesis.deposit_count
genesis_eth1_data.block_hash
is the hash of the Ethereum 1.0 block that emitted the Eth2Genesis
loggenesis_deposits
be the object of type List[Deposit]
with deposits ordered chronologically up to and including the deposit that triggered the Eth2Genesis
logLet genesis_state = get_genesis_beacon_state(genesis_deposits, eth2genesis.genesis_time, genesis_eth1_data)
.
python def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState: state = BeaconState( genesis_time=genesis_time, latest_eth1_data=genesis_eth1_data, latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) # Process genesis deposits for deposit in deposits: process_deposit(state, deposit) # Process genesis activations for validator in state.validator_registry: if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH # Populate latest_active_index_roots genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH)) for index in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH): state.latest_active_index_roots[index] = genesis_active_index_root return state
Let genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))
.
The post-state corresponding to a pre-state state
and a block block
is defined as state_transition(state, block)
. State transitions that trigger an unhandled excpetion (e.g. a failed assert
or an out-of-range list access) are considered invalid.
python def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState: # Process slots (including those with no blocks) since block process_slots(state, block.slot) # Process block process_block(state, block) # Validate state root (`validate_state_root == True` in production) if validate_state_root: assert block.state_root == hash_tree_root(state) # Return post-state return state
python def process_slots(state: BeaconState, slot: Slot) -> None: assert state.slot <= slot while state.slot < slot: process_slot(state) # Process epoch on the first slot of the next epoch if (state.slot + 1) % SLOTS_PER_EPOCH == 0: process_epoch(state) state.slot += 1
python def process_slot(state: BeaconState) -> None: # Cache state root previous_state_root = hash_tree_root(state) state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root # Cache latest block header state root if state.latest_block_header.state_root == ZERO_HASH: state.latest_block_header.state_root = previous_state_root # Cache block root previous_block_root = signing_root(state.latest_block_header) state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
Note: the # @LabelHere
lines below are placeholders to show that code will be inserted here in a future phase.
python def process_epoch(state: BeaconState) -> None: process_justification_and_finalization(state) process_crosslinks(state) process_rewards_and_penalties(state) process_registry_updates(state) # @process_reveal_deadlines # @process_challenge_deadlines process_slashings(state) process_final_updates(state) # @after_process_final_updates
python def get_total_active_balance(state: BeaconState) -> Gwei: return get_total_balance(state, get_active_validator_indices(state, get_current_epoch(state)))
python def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: assert epoch in (get_current_epoch(state), get_previous_epoch(state)) return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations
python def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: return [ a for a in get_matching_source_attestations(state, epoch) if a.data.target_root == get_block_root(state, epoch) ]
python def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: return [ a for a in get_matching_source_attestations(state, epoch) if a.data.beacon_block_root == get_block_root_at_slot(state, get_attestation_data_slot(state, a.data)) ]
python def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]: output = set() for a in attestations: output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield)) return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output)))
python def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei: return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
python def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch, shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]: attestations = [a for a in get_matching_source_attestations(state, epoch) if a.data.crosslink.shard == shard] crosslinks = list(filter( lambda c: hash_tree_root(state.current_crosslinks[shard]) in (c.parent_root, hash_tree_root(c)), [a.data.crosslink for a in attestations] )) # Winning crosslink has the crosslink data root with the most balance voting for it (ties broken lexicographically) winning_crosslink = max(crosslinks, key=lambda c: ( get_attesting_balance(state, [a for a in attestations if a.data.crosslink == c]), c.data_root ), default=Crosslink()) winning_attestations = [a for a in attestations if a.data.crosslink == winning_crosslink] return winning_crosslink, get_unslashed_attesting_indices(state, winning_attestations)
python def process_justification_and_finalization(state: BeaconState) -> None: if get_current_epoch(state) <= GENESIS_EPOCH + 1: return previous_epoch = get_previous_epoch(state) current_epoch = get_current_epoch(state) old_previous_justified_epoch = state.previous_justified_epoch old_current_justified_epoch = state.current_justified_epoch # Process justifications state.previous_justified_epoch = state.current_justified_epoch state.previous_justified_root = state.current_justified_root state.justification_bitfield = (state.justification_bitfield << 1) % 2**64 previous_epoch_matching_target_balance = get_attesting_balance( state, get_matching_target_attestations(state, previous_epoch) ) if previous_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2: state.current_justified_epoch = previous_epoch state.current_justified_root = get_block_root(state, state.current_justified_epoch) state.justification_bitfield |= (1 << 1) current_epoch_matching_target_balance = get_attesting_balance( state, get_matching_target_attestations(state, current_epoch) ) if current_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2: state.current_justified_epoch = current_epoch state.current_justified_root = get_block_root(state, state.current_justified_epoch) state.justification_bitfield |= (1 << 0) # Process finalizations bitfield = state.justification_bitfield # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch + 3 == current_epoch: state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, state.finalized_epoch) # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch + 2 == current_epoch: state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, state.finalized_epoch) # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch + 2 == current_epoch: state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, state.finalized_epoch) # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch + 1 == current_epoch: state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, state.finalized_epoch)
python def process_crosslinks(state: BeaconState) -> None: state.previous_crosslinks = [c for c in state.current_crosslinks] for epoch in (get_previous_epoch(state), get_current_epoch(state)): for offset in range(get_epoch_committee_count(state, epoch)): shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT crosslink_committee = get_crosslink_committee(state, epoch, shard) winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee): state.current_crosslinks[shard] = winning_crosslink
python def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: total_balance = get_total_active_balance(state) effective_balance = state.validator_registry[index].effective_balance return effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH
python def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: previous_epoch = get_previous_epoch(state) total_balance = get_total_active_balance(state) rewards = [0 for _ in range(len(state.validator_registry))] penalties = [0 for _ in range(len(state.validator_registry))] eligible_validator_indices = [ index for index, v in enumerate(state.validator_registry) if is_active_validator(v, previous_epoch) or (v.slashed and previous_epoch + 1 < v.withdrawable_epoch) ] # Micro-incentives for matching FFG source, FFG target, and head matching_source_attestations = get_matching_source_attestations(state, previous_epoch) matching_target_attestations = get_matching_target_attestations(state, previous_epoch) matching_head_attestations = get_matching_head_attestations(state, previous_epoch) for attestations in (matching_source_attestations, matching_target_attestations, matching_head_attestations): unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations) attesting_balance = get_total_balance(state, unslashed_attesting_indices) for index in eligible_validator_indices: if index in unslashed_attesting_indices: rewards[index] += get_base_reward(state, index) * attesting_balance // total_balance else: penalties[index] += get_base_reward(state, index) # Proposer and inclusion delay micro-rewards for index in get_unslashed_attesting_indices(state, matching_source_attestations): attestation = min([ a for a in matching_source_attestations if index in get_attesting_indices(state, a.data, a.aggregation_bitfield) ], key=lambda a: a.inclusion_delay) rewards[attestation.proposer_index] += get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT rewards[index] += get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay # Inactivity penalty finality_delay = previous_epoch - state.finalized_epoch if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY: matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations) for index in eligible_validator_indices: penalties[index] += BASE_REWARDS_PER_EPOCH * get_base_reward(state, index) if index not in matching_target_attesting_indices: penalties[index] += ( state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT ) return rewards, penalties
python def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: rewards = [0 for index in range(len(state.validator_registry))] penalties = [0 for index in range(len(state.validator_registry))] epoch = get_previous_epoch(state) for offset in range(get_epoch_committee_count(state, epoch)): shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT crosslink_committee = get_crosslink_committee(state, epoch, shard) winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) attesting_balance = get_total_balance(state, attesting_indices) committee_balance = get_total_balance(state, crosslink_committee) for index in crosslink_committee: base_reward = get_base_reward(state, index) if index in attesting_indices: rewards[index] += base_reward * attesting_balance // committee_balance else: penalties[index] += base_reward return rewards, penalties
python def process_rewards_and_penalties(state: BeaconState) -> None: if get_current_epoch(state) == GENESIS_EPOCH: return rewards1, penalties1 = get_attestation_deltas(state) rewards2, penalties2 = get_crosslink_deltas(state) for i in range(len(state.validator_registry)): increase_balance(state, i, rewards1[i] + rewards2[i]) decrease_balance(state, i, penalties1[i] + penalties2[i])
python def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections for index, validator in enumerate(state.validator_registry): if ( validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.effective_balance >= MAX_EFFECTIVE_BALANCE ): validator.activation_eligibility_epoch = get_current_epoch(state) if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: initiate_validator_exit(state, index) # Queue validators eligible for activation and not dequeued for activation prior to finalized epoch activation_queue = sorted([ index for index, validator in enumerate(state.validator_registry) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch) ], key=lambda index: state.validator_registry[index].activation_eligibility_epoch) # Dequeued validators for activation up to churn limit (without resetting activation epoch) for index in activation_queue[:get_churn_limit(state)]: validator = state.validator_registry[index] if validator.activation_epoch == FAR_FUTURE_EPOCH: validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
python def process_slashings(state: BeaconState) -> None: current_epoch = get_current_epoch(state) total_balance = get_total_active_balance(state) # Compute slashed balances in the current epoch total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH] total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] total_penalties = total_at_end - total_at_start for index, validator in enumerate(state.validator_registry): if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2: penalty = max( validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT ) decrease_balance(state, index, penalty)
python def process_final_updates(state: BeaconState) -> None: current_epoch = get_current_epoch(state) next_epoch = current_epoch + 1 # Reset eth1 data votes if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] # Update effective balances with hysteresis for index, validator in enumerate(state.validator_registry): balance = state.balances[index] HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2 if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance: validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) # Update start shard state.latest_start_shard = (state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH state.latest_active_index_roots[index_root_position] = hash_tree_root( get_active_validator_indices(state, next_epoch + ACTIVATION_EXIT_DELAY) ) # Set total slashed balances state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = ( state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] ) # Set randao mix state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch) # Set historical root accumulator if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: historical_batch = HistoricalBatch( block_roots=state.latest_block_roots, state_roots=state.latest_state_roots, ) state.historical_roots.append(hash_tree_root(historical_batch)) # Rotate current/previous epoch attestations state.previous_epoch_attestations = state.current_epoch_attestations state.current_epoch_attestations = []
python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body)
python def process_block_header(state: BeaconState, block: BeaconBlock) -> None: # Verify that the slots match assert block.slot == state.slot # Verify that the parent matches assert block.parent_root == signing_root(state.latest_block_header) # Save current block as the new latest block state.latest_block_header = BeaconBlockHeader( slot=block.slot, parent_root=block.parent_root, body_root=hash_tree_root(block.body), ) # Verify proposer is not slashed proposer = state.validator_registry[get_beacon_proposer_index(state)] assert not proposer.slashed # Verify proposer signature assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
python def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: proposer = state.validator_registry[get_beacon_proposer_index(state)] # Verify that the provided randao value is valid assert bls_verify( proposer.pubkey, hash_tree_root(get_current_epoch(state)), body.randao_reveal, get_domain(state, DOMAIN_RANDAO), ) # Mix it in state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = ( xor(get_randao_mix(state, get_current_epoch(state)), hash(body.randao_reveal)) )
python def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None: state.eth1_data_votes.append(body.eth1_data) if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD: state.latest_eth1_data = body.eth1_data
python def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: # Verify that outstanding deposits are processed up to the maximum number of deposits assert len(body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index) # Verify that there are no duplicate transfers assert len(body.transfers) == len(set(body.transfers)) for operations, max_operations, function in ( (body.proposer_slashings, MAX_PROPOSER_SLASHINGS, process_proposer_slashing), (body.attester_slashings, MAX_ATTESTER_SLASHINGS, process_attester_slashing), (body.attestations, MAX_ATTESTATIONS, process_attestation), (body.deposits, MAX_DEPOSITS, process_deposit), (body.voluntary_exits, MAX_VOLUNTARY_EXITS, process_voluntary_exit), (body.transfers, MAX_TRANSFERS, process_transfer), ): assert len(operations) <= max_operations for operation in operations: function(state, operation)
python def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: """ Process ``ProposerSlashing`` operation. """ proposer = state.validator_registry[proposer_slashing.proposer_index] # Verify that the epoch is the same assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot) # But the headers are different assert proposer_slashing.header_1 != proposer_slashing.header_2 # Check proposer is slashable assert is_slashable_validator(proposer, get_current_epoch(state)) # Signatures are valid for header in (proposer_slashing.header_1, proposer_slashing.header_2): domain = get_domain(state, DOMAIN_BEACON_PROPOSER, slot_to_epoch(header.slot)) assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain) slash_validator(state, proposer_slashing.proposer_index)
python def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None: """ Process ``AttesterSlashing`` operation. """ attestation_1 = attester_slashing.attestation_1 attestation_2 = attester_slashing.attestation_2 assert is_slashable_attestation_data(attestation_1.data, attestation_2.data) validate_indexed_attestation(state, attestation_1) validate_indexed_attestation(state, attestation_2) slashed_any = False attesting_indices_1 = attestation_1.custody_bit_0_indices + attestation_1.custody_bit_1_indices attesting_indices_2 = attestation_2.custody_bit_0_indices + attestation_2.custody_bit_1_indices for index in sorted(set(attesting_indices_1).intersection(attesting_indices_2)): if is_slashable_validator(state.validator_registry[index], get_current_epoch(state)): slash_validator(state, index) slashed_any = True assert slashed_any
python def process_attestation(state: BeaconState, attestation: Attestation) -> None: """ Process ``Attestation`` operation. """ data = attestation.data attestation_slot = get_attestation_data_slot(state, data) assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH pending_attestation = PendingAttestation( data=data, aggregation_bitfield=attestation.aggregation_bitfield, inclusion_delay=state.slot - attestation_slot, proposer_index=get_beacon_proposer_index(state), ) assert data.target_epoch in (get_previous_epoch(state), get_current_epoch(state)) if data.target_epoch == get_current_epoch(state): ffg_data = (state.current_justified_epoch, state.current_justified_root, get_current_epoch(state)) parent_crosslink = state.current_crosslinks[data.crosslink.shard] state.current_epoch_attestations.append(pending_attestation) else: ffg_data = (state.previous_justified_epoch, state.previous_justified_root, get_previous_epoch(state)) parent_crosslink = state.previous_crosslinks[data.crosslink.shard] state.previous_epoch_attestations.append(pending_attestation) # Check FFG data, crosslink data, and signature assert ffg_data == (data.source_epoch, data.source_root, data.target_epoch) assert data.crosslink.start_epoch == parent_crosslink.end_epoch assert data.crosslink.end_epoch == min(data.target_epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK) assert data.crosslink.parent_root == hash_tree_root(parent_crosslink) assert data.crosslink.data_root == ZERO_HASH # [to be removed in phase 1] validate_indexed_attestation(state, convert_to_indexed(state, attestation))
python def process_deposit(state: BeaconState, deposit: Deposit) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ # Verify the Merkle branch assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, index=state.deposit_index, root=state.latest_eth1_data.deposit_root, ) # Deposits must be processed in order state.deposit_index += 1 pubkey = deposit.data.pubkey amount = deposit.data.amount validator_pubkeys = [v.pubkey for v in state.validator_registry] if pubkey not in validator_pubkeys: # Verify the deposit signature (proof of possession). # Invalid signatures are allowed by the deposit contract, # and hence included on-chain, but must not be processed. # Note: deposits are valid across forks, hence the deposit domain is retrieved directly from `bls_domain` if not bls_verify( pubkey, signing_root(deposit.data), deposit.data.signature, bls_domain(DOMAIN_DEPOSIT) ): return # Add validator and balance entries state.validator_registry.append(Validator( pubkey=pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, activation_eligibility_epoch=FAR_FUTURE_EPOCH, activation_epoch=FAR_FUTURE_EPOCH, exit_epoch=FAR_FUTURE_EPOCH, withdrawable_epoch=FAR_FUTURE_EPOCH, effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) )) state.balances.append(amount) else: # Increase balance by deposit amount index = validator_pubkeys.index(pubkey) increase_balance(state, index, amount)
python def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None: """ Process ``VoluntaryExit`` operation. """ validator = state.validator_registry[exit.validator_index] # Verify the validator is active assert is_active_validator(validator, get_current_epoch(state)) # Verify the validator has not yet exited assert validator.exit_epoch == FAR_FUTURE_EPOCH # Exits must specify an epoch when they become valid; they are not valid before then assert get_current_epoch(state) >= exit.epoch # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD # Verify signature domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch) assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain) # Initiate exit initiate_validator_exit(state, exit.validator_index)
python def process_transfer(state: BeaconState, transfer: Transfer) -> None: """ Process ``Transfer`` operation. """ # Verify the amount and fee are not individually too big (for anti-overflow purposes) assert state.balances[transfer.sender] >= max(transfer.amount, transfer.fee) # A transfer is valid in only one slot assert state.slot == transfer.slot # Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE assert ( state.validator_registry[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender] ) # Verify that the pubkey is valid assert ( state.validator_registry[transfer.sender].withdrawal_credentials == int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:] ) # Verify that the signature is valid assert bls_verify(transfer.pubkey, signing_root(transfer), transfer.signature, get_domain(state, DOMAIN_TRANSFER)) # Process the transfer decrease_balance(state, transfer.sender, transfer.amount + transfer.fee) increase_balance(state, transfer.recipient, transfer.amount) increase_balance(state, get_beacon_proposer_index(state), transfer.fee) # Verify balances are not dust assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT) assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT)
Name | Value |
---|---|
SHARD_COUNT |
2**10 (= 1,024) |
TARGET_COMMITTEE_SIZE |
2**7 (= 128) |
MAX_INDICES_PER_ATTESTATION |
`212` (= 4,096)** |
MIN_PER_EPOCH_CHURN_LIMIT |
`22` (= 4)** |
CHURN_LIMIT_QUOTIENT |
`216` (= 65,536)** |
BASE_REWARDS_PER_EPOCH |
5 |
SHUFFLE_ROUND_COUNT |
90 |
Name | Value |
---|---|
DEPOSIT_CONTRACT_TREE_DEPTH |
2**5 (= 32) |
Name | Value | Unit |
---|---|---|
MIN_DEPOSIT_AMOUNT |
2**0 * 10**9 (= 1,000,000,000) |
Gwei |
MAX_EFFECTIVE_BALANCE |
`25 * 109` (= 32,000,000,000) | Gwei |
EJECTION_BALANCE |
2**4 * 10**9 (= 16,000,000,000) |
Gwei |
EFFECTIVE_BALANCE_INCREMENT |
`20 * 109` (= 1,000,000,000) | Gwei |
Name | Value |
---|---|
GENESIS_SLOT |
0 |
GENESIS_EPOCH |
0 |
FAR_FUTURE_EPOCH |
2**64 - 1 |
ZERO_HASH |
*`b'\x00' 32`** |
BLS_WITHDRAWAL_PREFIX |
0 |
Name | Value | Unit | Duration |
---|---|---|---|
MIN_ATTESTATION_INCLUSION_DELAY |
2**2 (= 4) |
slots | 24 seconds |
SLOTS_PER_EPOCH |
2**6 (= 64) |
slots | 6.4 minutes |
MIN_SEED_LOOKAHEAD |
2**0 (= 1) |
epochs | 6.4 minutes |
ACTIVATION_EXIT_DELAY |
2**2 (= 4) |
epochs | 25.6 minutes |
SLOTS_PER_ETH1_VOTING_PERIOD |
`210` (= 1,024)** | slots | ~1.7 hours |
SLOTS_PER_HISTORICAL_ROOT |
2**13 (= 8,192) |
slots | ~13 hours |
MIN_VALIDATOR_WITHDRAWABILITY_DELAY |
2**8 (= 256) |
epochs | ~27 hours |
PERSISTENT_COMMITTEE_PERIOD |
2**11 (= 2,048) |
epochs | 9 days |
MAX_EPOCHS_PER_CROSSLINK |
`26` (= 64)** | epochs | ~7 hours |
MIN_EPOCHS_TO_INACTIVITY_PENALTY |
`22` (= 4)** | epochs | 25.6 minutes |
MAX_EPOCHS_PER_CROSSLINK
should be a small constant times SHARD_COUNT // SLOTS_PER_EPOCH
Name | Value | Unit | Duration |
---|---|---|---|
LATEST_RANDAO_MIXES_LENGTH |
2**13 (= 8,192) |
epochs | ~36 days |
LATEST_ACTIVE_INDEX_ROOTS_LENGTH |
2**13 (= 8,192) |
epochs | ~36 days |
LATEST_SLASHED_EXIT_LENGTH |
2**13 (= 8,192) |
epochs | ~36 days |
Name | Value |
---|---|
BASE_REWARD_FACTOR |
`25` (= 32)** |
WHISTLEBLOWING_REWARD_QUOTIENT |
`29` (= 512)** |
PROPOSER_REWARD_QUOTIENT |
`23` (= 8)** |
INACTIVITY_PENALTY_QUOTIENT |
`225` (= 33,554,432)** |
MIN_SLASHING_PENALTY_QUOTIENT |
`25` (= 32)** |
BASE_REWARD_FACTOR
is NOT final. Once all other protocol details are finalized, it will be adjusted to target a theoretical maximum total issuance of `221ETH per year if
227ETH is validating (and therefore
220per year if
225` ETH is validating, etc.)INACTIVITY_PENALTY_QUOTIENT
equals `INVERSE_SQRT_E_DROP_TIME2where
INVERSE_SQRT_E_DROP_TIME := 212 epochs(~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about
1/sqrt(e) ~= 60.6%. Indeed, the balance retained by offline [validators](#dfn-validator) after
nepochs is about
(1 - 1/INACTIVITY_PENALTY_QUOTIENT)(n2/2)so after
INVERSE_SQRT_E_DROP_TIMEepochs it is roughly
(1 - 1/INACTIVITY_PENALTY_QUOTIENT)(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.**Name | Value |
---|---|
MAX_PROPOSER_SLASHINGS |
2**4 (= 16) |
MAX_ATTESTER_SLASHINGS |
2**0 (= 1) |
MAX_ATTESTATIONS |
2**7 (= 128) |
MAX_DEPOSITS |
2**4 (= 16) |
MAX_VOLUNTARY_EXITS |
2**4 (= 16) |
MAX_TRANSFERS |
0 |
Name | Value |
---|---|
DOMAIN_BEACON_PROPOSER |
0 |
DOMAIN_RANDAO |
1 |
DOMAIN_ATTESTATION |
2 |
DOMAIN_DEPOSIT |
3 |
DOMAIN_VOLUNTARY_EXIT |
4 |
DOMAIN_TRANSFER |
5 |
Resolved in PR #730, PR #731, and PR #736
Update TODO
Constants
[x]
MAX_INDICES_PER_ATTESTATION
added[x]
MIN_PER_EPOCH_CHURN_LIMIT
added[x]
CHURN_LIMIT_QUOTIENT
added[x]
BASE_REWARDS_PER_EPOCH
added[x]
MAX_BALANCE_CHURN_QUOTIENT
removed[x]
MAX_INDICES_PER_SLASHABLE_VOTE
removed[x]
MAX_EXIT_DEQUEUES_PER_EPOCH
removed[x]
MAX_DEPOSIT_AMOUNT
removed[x]
MAX_EFFECTIVE_BALANCE
added[x]
FORK_CHOICE_BALANCE_INCREMENT
removed[x]
EFFECTIVE_BALANCE_INCREMENT
added[x]
GENESIS_FORK_VERSION
removed[x]
GENESIS_SLOT
modified[x]
GENESIS_EPOCH
modified[x]
GENESIS_START_SHARD
removed[x]
ZERO_HASH
modified[x]
EMPTY_SIGNATURE
removed[x]
BLS_WITHDRAWAL_PREFIX_BYTE
removed[x]
BLS_WITHDRAWAL_PREFIX
added[x]
SECONDS_PER_SLOT
removed[x]
EPOCHS_PER_ETH1_VOTING_PERIOD
removed[x]
SLOTS_PER_ETH1_VOTING_PERIOD
added[x]
MAX_EPOCHS_PER_CROSSLINK
added[x]
MIN_EPOCHS_TO_INACTIVITY_PENALTY
added[x]
MAX_EPOCHS_PER_CROSSLINK
added[x]
BASE_REWARD_QUOTIENT
->BASE_REWARD_FACTOR
[x]
ATTESTATION_INCLUSION_REWARD_QUOTIENT
->PROPOSER_REWARD_QUOTIENT
[x]
MIN_PENALTY_QUOTIENT
->MIN_SLASHING_PENALTY_QUOTIENT
[x]
MAX_TRANSFERS
modified[x]
DOMAIN_BEACON_BLOCK
->DOMAIN_BEACON_PROPOSER
Datastructures
[x]
Eth1DataVote
removed[x]
SlashableAttestation
removed[x]
DepositInput
removed[x]
IndexedAttestation
added[x]
Fork
modified[x]
Crosslink
modified[x]
AttestationData
modified[x]
IndexedAttestation
modified[x]
PendingAttestation
modified[x]
DepositData
modified[x]
BeaconBlockHeader
modified[x]
AttesterSlashing
modified[x]
BeaconBlockBody
modified[x]
BeaconBlock
modified[x]
BeaconState
modifiedHelper Functions
[x]
signed_root
->signing_root
[x]
get_temporary_block_header
removed[x]
get_permuted_index
removed[x]
split
removed[x]
get_shuffling
removed[x]
get_previous_epoch_committee_count
removed[x]
get_current_epoch_committee_count
removed[x]
get_next_epoch_committee_count
removed[x]
get_crosslink_committees_at_slot
removed[x]
get_state_root
removed[x]
get_attestation_participants
removed[x]
is_power_of_two
removed[ ]
int_to_bytes1, int_to_bytes2, ...
removed[x]
get_effective_balance
removed[x]
get_fork_version
removed[x]
is_double_vote
removed[x]
is_surround_vote
removed[x]
prepare_validator_for_withdrawal
removed[x]
is_slashable_validator
added[x]
increase_balance
added[x]
decrease_balance
added[x]
get_shard_delta
added[x]
get_epoch_start_shard
added[x]
get_attestation_data_slot
added[x]
get_block_root_at_slot
added[x]
get_shuffled_index
added[x]
compute_committee
added[x]
get_crosslink_committee
added[x]
get_attesting_indices
added[ ]
int_to_bytes
added[x]
convert_to_indexed
added[x]
validate_indexed_attestation
added[x]
is_slashable_attestation_data
added[x]
get_churn_limit
added[x]
bls_domain
added[ ]
xor
modified[ ]
hash
modified[x]
signing_root
modified[x]
get_previous_epoch
modified[x]
is_slashable_validator
modified[x]
get_active_validator_indices
modified[x]
get_epoch_committee_count
modified[x]
get_block_root
modified[x]
get_randao_mix
modified[x]
get_active_index_root
modified[x]
generate_seed
modified[x]
get_beacon_proposer_index
modified[x]
get_attesting_indices
modified[x]
get_total_balance
modified[x]
get_domain
modifiedState Processing
get_genesis_beacon_state
modifiedstate_transition
addedprocess_slots
addedprocess_slot
addedprocess_epoch
addedget_total_active_balance
addedget_matching_source_attestations
addedget_matching_target_attestations
addedget_matching_head_attestations
addedget_unslashed_attesting_indices
addedget_attesting_balance
modifiedget_winning_crosslink_and_attesting_indices
addedprocess_justification_and_finalization
addedprocess_crosslinks
modifiedget_base_reward
modifiedget_attestation_deltas
addedget_crosslink_deltas
modifiedprocess_rewards_and_penalties
addedprocess_registry_updates
addedprocess_slashings
modifiedprocess_final_updates
addedprocess_block
addedprocess_block_header
modifiedprocess_randao
modifiedprocess_eth1_data
modifiedprocess_operations
addedprocess_proposer_slashing
modifiedprocess_attester_slashing
modifiedprocess_attestation
modifiedprocess_deposit
modifiedprocess_voluntary_exit
modifiedprocess_transfer
modified