def test_ensure_update_eth1_vote_if_exists(genesis_state, config,
                                           vote_offsets):
    # one less than a majority is the majority divided by 2
    threshold = config.SLOTS_PER_ETH1_VOTING_PERIOD // 2
    data_votes = tuple(
        concat((Eth1Data.create(block_hash=(i).to_bytes(32, "little")), ) *
               (threshold + offset) for i, offset in enumerate(vote_offsets)))
    state = genesis_state

    for vote in data_votes:
        state = process_eth1_data(
            state,
            BeaconBlock.create(body=BeaconBlockBody.create(eth1_data=vote)),
            config,
        )

    if not vote_offsets:
        assert state.eth1_data == genesis_state.eth1_data

    # we should update the 'latest' entry if we have a majority
    for offset in vote_offsets:
        if offset <= 0:
            assert genesis_state.eth1_data == state.eth1_data
        else:
            assert state.eth1_data == data_votes[0]
Пример #2
0
def create_mock_genesis(
    pubkeys: Sequence[BLSPubkey],
    config: Eth2Config,
    keymap: Dict[BLSPubkey, int],
    genesis_block_class: Type[BaseBeaconBlock],
    genesis_time: Timestamp = ZERO_TIMESTAMP,
) -> Tuple[BeaconState, BaseBeaconBlock]:
    genesis_deposits, deposit_root = create_mock_deposits_and_root(
        pubkeys=pubkeys, keymap=keymap, config=config)

    genesis_eth1_data = Eth1Data.create(
        deposit_root=deposit_root,
        deposit_count=len(genesis_deposits),
        block_hash=ZERO_HASH32,
    )

    state = initialize_beacon_state_from_eth1(
        eth1_block_hash=genesis_eth1_data.block_hash,
        eth1_timestamp=genesis_time,
        deposits=genesis_deposits,
        config=config,
    )

    block = get_genesis_block(genesis_state_root=state.hash_tree_root,
                              block_class=genesis_block_class)
    assert len(state.validators) == len(pubkeys)

    return state, block
def test_process_eth1_data(
    original_votes,
    block_data,
    expected_votes,
    sample_beacon_state_params,
    sample_beacon_block_params,
    sample_beacon_block_body_params,
    config,
):
    eth1_data_votes = tuple(mapcat(_expand_eth1_votes, original_votes))
    state = BeaconState.create(**sample_beacon_state_params).set(
        "eth1_data_votes", eth1_data_votes)

    block_body = BeaconBlockBody.create(
        **sample_beacon_block_body_params).mset(
            "eth1_data", Eth1Data.create(block_hash=block_data))

    block = BeaconBlock.create(**sample_beacon_block_params).set(
        "body", block_body)

    updated_state = process_eth1_data(state, block, config)
    updated_votes = updated_state.eth1_data_votes
    expanded_expected_votes = tuple(mapcat(_expand_eth1_votes, expected_votes))

    assert tuple(updated_votes) == expanded_expected_votes
Пример #4
0
def genesis_state(genesis_validators, genesis_balances, genesis_time,
                  sample_eth1_data_params, config):
    genesis_eth1_data = Eth1Data.create(**sample_eth1_data_params).set(
        "deposit_count", len(genesis_validators))

    return create_mock_genesis_state_from_validators(genesis_time,
                                                     genesis_eth1_data,
                                                     genesis_validators,
                                                     genesis_balances, config)
Пример #5
0
def sample_beacon_block_body_params(sample_signature, sample_eth1_data_params):
    return {
        "randao_reveal": sample_signature,
        "eth1_data": Eth1Data.create(**sample_eth1_data_params),
        "graffiti": ZERO_HASH32,
        "proposer_slashings": (),
        "attester_slashings": (),
        "attestations": (),
        "deposits": (),
        "voluntary_exits": (),
    }
Пример #6
0
def initialize_beacon_state_from_eth1(*, eth1_block_hash: Hash32,
                                      eth1_timestamp: Timestamp,
                                      deposits: Sequence[Deposit],
                                      config: Eth2Config) -> BeaconState:
    fork = Fork.create(
        previous_version=config.GENESIS_FORK_VERSION,
        current_version=config.GENESIS_FORK_VERSION,
        epoch=GENESIS_EPOCH,
    )

    state = BeaconState.create(
        genesis_time=_genesis_time_from_eth1_timestamp(eth1_timestamp,
                                                       config.GENESIS_DELAY),
        fork=fork,
        eth1_data=Eth1Data.create(block_hash=eth1_block_hash,
                                  deposit_count=len(deposits)),
        latest_block_header=BeaconBlockHeader.create(
            body_root=BeaconBlockBody.create().hash_tree_root),
        block_roots=(ZERO_ROOT, ) * config.SLOTS_PER_HISTORICAL_ROOT,
        state_roots=(ZERO_HASH32, ) * config.SLOTS_PER_HISTORICAL_ROOT,
        randao_mixes=(eth1_block_hash, ) * config.EPOCHS_PER_HISTORICAL_VECTOR,
        slashings=(Gwei(0), ) * config.EPOCHS_PER_SLASHINGS_VECTOR,
        config=config,
    )

    # Process genesis deposits
    for index, deposit in enumerate(deposits):
        deposit_data_list = tuple(deposit.data
                                  for deposit in deposits[:index + 1])
        deposit_root = ssz.get_hash_tree_root(
            deposit_data_list,
            ssz.List(DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH))
        state = state.transform(("eth1_data", "deposit_root"), deposit_root)
        state = process_deposit(state=state, deposit=deposit, config=config)

    # Process genesis activations
    for validator_index in range(len(state.validators)):
        validator_index = ValidatorIndex(validator_index)
        balance = state.balances[validator_index]
        effective_balance = calculate_effective_balance(balance, config)

        state = state.transform(
            ("validators", validator_index, "effective_balance"),
            effective_balance)

        if effective_balance == config.MAX_EFFECTIVE_BALANCE:
            activated_validator = activate_validator(
                state.validators[validator_index], GENESIS_EPOCH)
            state = state.transform(("validators", validator_index),
                                    activated_validator)

    return state.set("genesis_validators_root",
                     state.validators.hash_tree_root)
Пример #7
0
    def _get_eth1_data(
            self, distance: BlockNumber,
            eth1_voting_period_start_timestamp: Timestamp) -> Eth1Data:
        """
        Return `Eth1Data` at `distance` relative to the eth1 block earlier and closest to the
        timestamp `eth1_voting_period_start_timestamp`.
        Ref: https://github.com/ethereum/eth2.0-specs/blob/61f2a0662ebcfb4c097360cc1835c5f01872705c/specs/validator/0_beacon-chain-validator.md#eth1-data  # noqa: E501

        First, we find the `eth1_block` whose timestamp is the largest timestamp which is smaller
        than `eth1_voting_period_start_timestamp`. Then, find the block `target_block` at number
        `eth1_block.number - distance`. Therefore, we can return `Eth1Data` according to the
        information of this block.
        """
        eth1_voting_period_start_block_number = self._get_closest_eth1_voting_period_start_block(
            eth1_voting_period_start_timestamp)
        target_block_number = BlockNumber(
            eth1_voting_period_start_block_number - distance)
        if target_block_number < 0:
            raise Eth1MonitorValidationError(
                f"`distance` is larger than `eth1_voting_period_start_block_number`: "
                f"`distance`={distance}, ",
                f"eth1_voting_period_start_block_number={eth1_voting_period_start_block_number}",
            )
        try:
            block = self._eth1_data_provider.get_block(target_block_number)
        except BlockNotFound:
            raise Eth1MonitorValidationError(
                f"Block does not exist for block number={target_block_number}")
        block_hash = block.block_hash
        # `Eth1Data.deposit_count`: get the `deposit_count` corresponding to the block.
        accumulated_deposit_count = self._get_accumulated_deposit_count(
            target_block_number)
        if accumulated_deposit_count == 0:
            raise Eth1MonitorValidationError(
                f"failed to make `Eth1Data`: `deposit_count = 0` at block #{target_block_number}"
            )
        # Verify that the deposit data in db and the deposit data in contract match
        deposit_data_in_range = self._db.get_deposit_data_range(
            0, accumulated_deposit_count)
        _, deposit_root = make_deposit_tree_and_root(deposit_data_in_range)
        contract_deposit_root = self._get_deposit_root_from_contract(
            target_block_number)
        if contract_deposit_root != deposit_root:
            raise DepositDataCorrupted(
                "deposit root built locally mismatches the one in the contract on chain: "
                f"contract_deposit_root={contract_deposit_root.hex()}, "
                f"deposit_root={deposit_root.hex()}")
        return Eth1Data.create(
            deposit_root=deposit_root,
            deposit_count=accumulated_deposit_count,
            block_hash=block_hash,
        )
Пример #8
0
def sample_beacon_state_params(
    config,
    genesis_slot,
    genesis_epoch,
    sample_fork_params,
    sample_eth1_data_params,
    sample_block_header_params,
):
    return {
        # Versioning
        "genesis_time":
        0,
        "slot":
        genesis_slot + 100,
        "fork":
        Fork.create(**sample_fork_params),
        # History
        "latest_block_header":
        BeaconBlockHeader.create(**sample_block_header_params),
        "block_roots": (ZERO_HASH32, ) * config.SLOTS_PER_HISTORICAL_ROOT,
        "state_roots": (ZERO_HASH32, ) * config.SLOTS_PER_HISTORICAL_ROOT,
        "historical_roots": (),
        # Eth1
        "eth1_data":
        Eth1Data.create(**sample_eth1_data_params),
        "eth1_data_votes": (),
        "eth1_deposit_index":
        0,
        # Registry
        "validators": (),
        "balances": (),
        # Shuffling
        "randao_mixes": (ZERO_HASH32, ) * config.EPOCHS_PER_HISTORICAL_VECTOR,
        # Slashings
        "slashings": (0, ) * config.EPOCHS_PER_SLASHINGS_VECTOR,
        # Attestations
        "previous_epoch_attestations": (),
        "current_epoch_attestations": (),
        # Justification
        "justification_bits": (False, ) * JUSTIFICATION_BITS_LENGTH,
        "previous_justified_checkpoint":
        Checkpoint.create(epoch=0, root=b"\x99" * 32),
        "current_justified_checkpoint":
        Checkpoint.create(epoch=0, root=b"\x55" * 32),
        # Finality
        "finalized_checkpoint":
        Checkpoint.create(epoch=0, root=b"\x33" * 32),
    }
def _build_chain_of_blocks_with_states(
    chain,
    state,
    parent_block,
    slots,
    config,
    keymap,
    attestation_participation=1.0,
    eth1_block_hash=ZERO_HASH32,
):
    blocks = ()
    states = ()
    for slot in range(parent_block.slot + 1, parent_block.slot + 1 + slots):
        sm = chain.get_state_machine(state.slot)
        pre_state, _ = sm.apply_state_transition(state, future_slot=slot)
        proposer_index = get_beacon_proposer_index(pre_state, config)
        public_key = state.validators[proposer_index].pubkey
        private_key = keymap[public_key]
        randao_reveal = generate_randao_reveal(private_key, slot, pre_state,
                                               config)

        attestations = create_mock_signed_attestations_at_slot(
            state,
            config,
            sm,
            slot - 1,
            parent_block.hash_tree_root,
            keymap,
            voted_attesters_ratio=attestation_participation,
        )
        block = create_block(
            slot,
            parent_block.hash_tree_root,
            randao_reveal,
            Eth1Data.create(block_hash=eth1_block_hash),
            attestations,
            state,
            sm,
            private_key,
        )

        parent_block = block.message
        state, block = sm.apply_state_transition(state, block)

        blocks += (block, )
        states += (state, )
    return blocks, states
Пример #10
0
def test_get_genesis_beacon_state(
    validator_count,
    pubkeys,
    genesis_epoch,
    genesis_slot,
    max_committees_per_slot,
    slots_per_historical_root,
    epochs_per_slashings_vector,
    epochs_per_historical_vector,
    config,
    keymap,
):
    genesis_deposits, deposit_root = create_mock_deposits_and_root(
        pubkeys=pubkeys[:validator_count], keymap=keymap, config=config)

    genesis_eth1_data = Eth1Data.create(
        deposit_count=len(genesis_deposits),
        deposit_root=deposit_root,
        block_hash=ZERO_HASH32,
    )
    eth1_timestamp = 10
    eth1_block_hash = genesis_eth1_data.block_hash

    state = initialize_beacon_state_from_eth1(
        eth1_block_hash=eth1_block_hash,
        eth1_timestamp=eth1_timestamp,
        deposits=genesis_deposits,
        config=config,
    )

    # Versioning
    assert state.slot == genesis_slot
    assert state.genesis_time == _genesis_time_from_eth1_timestamp(
        eth1_timestamp)
    assert state.fork == Fork.create()

    # History
    assert state.latest_block_header == BeaconBlockHeader.create(
        body_root=BeaconBlockBody.create().hash_tree_root)
    assert len(state.block_roots) == slots_per_historical_root
    assert tuple(
        state.block_roots) == (ZERO_HASH32, ) * slots_per_historical_root
    assert len(state.state_roots) == slots_per_historical_root
    assert tuple(
        state.block_roots) == (ZERO_HASH32, ) * slots_per_historical_root
    assert len(state.historical_roots) == 0

    # Ethereum 1.0 chain data
    assert state.eth1_data == genesis_eth1_data
    assert len(state.eth1_data_votes) == 0
    assert state.eth1_deposit_index == len(genesis_deposits)

    # Validator registry
    assert len(state.validators) == validator_count
    assert len(state.balances) == validator_count

    # Shuffling
    assert len(state.randao_mixes) == epochs_per_historical_vector
    assert (tuple(state.randao_mixes) == (eth1_block_hash, ) *
            epochs_per_historical_vector)

    # Slashings
    assert len(state.slashings) == epochs_per_slashings_vector
    assert tuple(state.slashings) == (Gwei(0), ) * epochs_per_slashings_vector

    # Attestations
    assert len(state.previous_epoch_attestations) == 0
    assert len(state.current_epoch_attestations) == 0

    # Justification
    assert state.previous_justified_checkpoint.epoch == genesis_epoch
    assert state.previous_justified_checkpoint.root == ZERO_HASH32
    assert state.current_justified_checkpoint.epoch == genesis_epoch
    assert state.current_justified_checkpoint.root == ZERO_HASH32
    assert state.justification_bits == (False, ) * JUSTIFICATION_BITS_LENGTH

    # Finalization
    assert state.finalized_checkpoint.epoch == genesis_epoch
    assert state.finalized_checkpoint.root == ZERO_HASH32

    for i in range(len(genesis_deposits)):
        assert state.validators[i].is_active(genesis_epoch)
def _expand_eth1_votes(args):
    block_hash, vote_count = args
    return (Eth1Data.create(block_hash=block_hash), ) * vote_count
Пример #12
0
def _mini_stf(state: BeaconState, block: Optional[BeaconBlock],
              config: Eth2Config) -> BeaconState:
    """
    A simplified state transition for testing state storage.

    - updates ``state_roots`` with the previous slot's state root
    - updates ``block_roots`` with the previous slot's block root
    - updates ``randao_mixes`` with an arbitrary mix at the current epoch
    - creates a new ``latest_block_header`` and adds it to the state
    - fills in the rest of the attributes with arbitrary values
    """
    current_slot = state.slot + 1
    current_epoch = current_slot // config.SLOTS_PER_EPOCH

    if block:
        latest_block_header = block.header
    else:
        latest_block_header = state.latest_block_header

    # state changes that depend on the previous state for retrieval
    randao_mix = Root(Hash32(current_slot.to_bytes(32, byteorder="little")))
    state = (state.transform(
        ("state_roots", state.slot % config.SLOTS_PER_HISTORICAL_ROOT),
        state.hash_tree_root,
    ).transform(
        ("block_roots", state.slot % config.SLOTS_PER_HISTORICAL_ROOT),
        state.latest_block_header.hash_tree_root,
    ).transform(
        ("randao_mixes", current_epoch % config.EPOCHS_PER_HISTORICAL_VECTOR),
        randao_mix,
    ).mset("slot", current_slot, "latest_block_header", latest_block_header))

    # state changes that do not depend on the previous state for retrieval
    new_validators = [
        Validator.create(pubkey=BLSPubkey(n.to_bytes(48, byteorder="little")))
        for n in range(current_slot, current_slot + 20)
    ]
    new_eth1_data_votes = [
        Eth1Data.create(
            deposit_root=Root(Hash32(n.to_bytes(32, byteorder="little"))))
        for n in range(current_slot, current_slot + 7)
    ]
    new_previous_epoch_attestations = [
        PendingAttestation.create(proposer_index=ValidatorIndex(n))
        for n in range(current_slot, current_slot + 5)
    ]
    new_current_epoch_attestations = [
        PendingAttestation.create(proposer_index=ValidatorIndex(n))
        for n in range(current_slot + 5, current_slot + 10)
    ]
    state = state.mset(
        "validators",
        new_validators,
        "balances",
        (32, ) * len(new_validators),
        "eth1_data_votes",
        new_eth1_data_votes,
        "eth1_data",
        new_eth1_data_votes[0],
        "previous_epoch_attestations",
        new_previous_epoch_attestations,
        "current_epoch_attestations",
        new_current_epoch_attestations,
        "previous_justified_checkpoint",
        Checkpoint.create(epoch=Epoch(current_slot + 42)),
        "current_justified_checkpoint",
        Checkpoint.create(epoch=Epoch(current_slot + 43)),
        "finalized_checkpoint",
        Checkpoint.create(epoch=Epoch(current_slot + 44)),
    )

    return state
Пример #13
0
def test_defaults(sample_eth1_data_params):
    eth1_data = Eth1Data.create(**sample_eth1_data_params)
    assert eth1_data.deposit_root == sample_eth1_data_params["deposit_root"]
    assert eth1_data.block_hash == sample_eth1_data_params["block_hash"]