def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, eth1_timestamp: uint64, deposits: Sequence[Deposit]) -> BeaconState: state = BeaconState( genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy ) # Process deposits leaves = list(map(lambda deposit: deposit.data, deposits)) for index, deposit in enumerate(deposits): deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) process_deposit(state, deposit) # Process activations for index, validator in enumerate(state.validators): balance = state.balances[index] validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) if validator.effective_balance == MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH return state
def aggregate_attestations(state, attestations): # Take in a set of attestations # Output aggregated attestations hashes = [hash_tree_root(att) for att in attestations] return [ build_aggregate(state, [ att for att in attestations if att_hash == hash_tree_root(att) ]) for att_hash in hashes ]
def process_slot(state: BeaconState) -> None: # Cache state root previous_state_root = hash_tree_root(state) state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root # Cache latest block header state root if state.latest_block_header.state_root == Bytes32(): state.latest_block_header.state_root = previous_state_root # Cache block root previous_block_root = hash_tree_root(state.latest_block_header) state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
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 == hash_tree_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, # `state_root` is zeroed and overwritten in the next `process_slot` call body_root=hash_tree_root(block.body), ) # Verify proposer is not slashed proposer = state.validators[get_beacon_proposer_index(state)] assert not proposer.slashed
def propose_block(params, step, sL, s): # Given state w-[s], propose a block for slot s # `state` is w-[s] state = s['beacon_state'] # `current_slot` is s current_slot = state.slot print("propose a block, current_slot", current_slot) # If this is the first slot, use the `genesis_block` if current_slot == 0: return ({'block': get_genesis_block(state)}) # Later on, we populate the `BeaconBlockBody`. For now, our validators merely produce empty blocks. beacon_block_body = BeaconBlockBody(attestations=s[ 'current_slot_attestations'] # <--- THIS IS THE NEW LINE ) beacon_block = BeaconBlock( slot=current_slot, parent_root=hash_tree_root( state.latest_block_header ), # the parent root is accessed from the state body=beacon_block_body) signed_beacon_block = SignedBeaconBlock(message=beacon_block) return ({'block': signed_beacon_block})
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None: epoch = get_current_epoch(state) # Verify RANDAO reveal proposer = state.validators[get_beacon_proposer_index(state)] assert bls_verify(proposer.pubkey, hash_tree_root(epoch), body.randao_reveal, get_domain(state, DOMAIN_RANDAO)) # Mix in RANDAO reveal mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal)) state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
def process_deposit(state: BeaconState, deposit: Deposit) -> None: # Verify the Merkle branch assert is_valid_merkle_branch( leaf=hash_tree_root(deposit.data), branch=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in index=state.eth1_deposit_index, root=state.eth1_data.deposit_root, ) # Deposits must be processed in order state.eth1_deposit_index += 1 pubkey = deposit.data.pubkey amount = deposit.data.amount validator_pubkeys = [v.pubkey for v in state.validators] if pubkey not in validator_pubkeys: # Verify the deposit signature (proof of possession) for new validators. # Note: The deposit contract does not check signatures. # Note: Deposits are valid across forks, thus the deposit domain is retrieved directly from `compute_domain`. domain = compute_domain(DOMAIN_DEPOSIT) deposit_message = DepositMessage( pubkey=deposit.data.pubkey, withdrawal_credentials=deposit.data.withdrawal_credentials, amount=deposit.data.amount) if not bls_verify(pubkey, hash_tree_root(deposit_message), deposit.data.signature, domain): return # Add validator and balance entries state.validators.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 = ValidatorIndex(validator_pubkeys.index(pubkey)) increase_balance(state, index, amount)
def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState: # Process slots (including those with no blocks) since block process_slots(state, signed_block.message.slot) # Verify signature if validate_result: assert verify_block_signature(state, signed_block) # Process block process_block(state, signed_block.message) if validate_result: assert signed_block.message.state_root == hash_tree_root(state) # Validate state root # Return post-state return state
def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: voluntary_exit = signed_voluntary_exit.message validator = state.validators[voluntary_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) >= voluntary_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, voluntary_exit.epoch) assert bls_verify(validator.pubkey, hash_tree_root(voluntary_exit), signed_voluntary_exit.signature, domain) # Initiate exit initiate_validator_exit(state, voluntary_exit.validator_index)
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool: """ Check if ``indexed_attestation`` has valid indices and signature. """ indices = indexed_attestation.attesting_indices # Verify max number of indices if not len(indices) <= MAX_VALIDATORS_PER_COMMITTEE: return False # Verify indices are sorted if not indices == sorted(indices): return False # Verify aggregate signature if not bls_verify( pubkey=aggregate_pubkeys([state.validators[i].pubkey for i in indices]), message_hash=hash_tree_root(indexed_attestation.data), signature=indexed_attestation.signature, domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch), ): return False return True
def process_final_updates(state: BeaconState) -> None: current_epoch = get_current_epoch(state) next_epoch = 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.validators): 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) # Reset slashings state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0) # Set randao mix state.randao_mixes[next_epoch % EPOCHS_PER_HISTORICAL_VECTOR] = 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.block_roots, state_roots=state.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 = []
def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool: proposer = state.validators[get_beacon_proposer_index(state)] domain = get_domain(state, DOMAIN_BEACON_PROPOSER) return bls_verify(proposer.pubkey, hash_tree_root(signed_block.message), signed_block.signature, domain)
def hash_tree_root(self): from ssz_impl import hash_tree_root return hash_tree_root(self)
def get_genesis_block(genesis_state): return SignedBeaconBlock(message=BeaconBlock( state_root=hash_tree_root(genesis_state), parent_root=hash_tree_root(genesis_state.latest_block_header)))
def process_genesis_block(genesis_state): genesis_block = specs.SignedBeaconBlock(message=specs.BeaconBlock( state_root=hash_tree_root(genesis_state), parent_root=hash_tree_root(genesis_state.latest_block_header))) specs.process_block(genesis_state, genesis_block.message)