Exemplo n.º 1
0
def get_shuffling(*, seed: Hash32, validators: Sequence['ValidatorRecord'],
                  epoch: EpochNumber, epoch_length: int,
                  target_committee_size: int,
                  shard_count: int) -> Tuple[Iterable[ValidatorIndex], ...]:
    """
    Shuffle ``validators`` into crosslink committees seeded by ``seed`` and ``epoch``.
    Return a list of ``committee_per_epoch`` committees where each
    committee is itself a list of validator indices.

    If ``get_shuffling(seed, validators, epoch)`` returns some value ``x`` for some
    ``epoch <= get_current_epoch(state) + ENTRY_EXIT_DELAY``, it should return the
    same value ``x`` for the same ``seed`` and ``epoch`` and possible future modifications
    of ``validators`` forever in phase 0, and until the ~1 year deletion delay in phase 2
    and in the future.
    """
    active_validator_indices = get_active_validator_indices(validators, epoch)

    committees_per_epoch = get_epoch_committee_count(
        len(active_validator_indices),
        shard_count,
        epoch_length,
        target_committee_size,
    )

    # Shuffle
    shuffled_active_validator_indices = shuffle(active_validator_indices, seed)

    # Split the shuffled list into committees_per_epoch pieces
    return tuple(
        split(
            shuffled_active_validator_indices,
            committees_per_epoch,
        ))
Exemplo n.º 2
0
def get_shuffling(*,
                  seed: Hash32,
                  validators: Sequence['ValidatorRecord'],
                  epoch: Epoch,
                  committee_config: CommitteeConfig) -> Tuple[Sequence[ValidatorIndex], ...]:
    """
    Shuffle ``validators`` into crosslink committees seeded by ``seed`` and ``epoch``.
    Return a list of ``committee_per_epoch`` committees where each
    committee is itself a list of validator indices.

    If ``get_shuffling(seed, validators, epoch)`` returns some value ``x`` for some
    ``epoch <= get_current_epoch(state) + ACTIVATION_EXIT_DELAY``, it should return the
    same value ``x`` for the same ``seed`` and ``epoch`` and possible future modifications
    of ``validators`` forever in phase 0, and until the ~1 year deletion delay in phase 2
    and in the future.
    """
    slots_per_epoch = committee_config.SLOTS_PER_EPOCH
    target_committee_size = committee_config.TARGET_COMMITTEE_SIZE
    shard_count = committee_config.SHARD_COUNT
    shuffle_round_count = committee_config.SHUFFLE_ROUND_COUNT

    active_validator_indices = get_active_validator_indices(validators, epoch)

    committees_per_epoch = get_epoch_committee_count(
        len(active_validator_indices),
        shard_count,
        slots_per_epoch,
        target_committee_size,
    )

    # Shuffle
    shuffled_active_validator_indices = shuffle(
        active_validator_indices,
        seed,
        shuffle_round_count=shuffle_round_count,
    )

    # Split the shuffled list into committees_per_epoch pieces
    return tuple(
        split(
            shuffled_active_validator_indices,
            committees_per_epoch,
        )
    )
Exemplo n.º 3
0
def get_shuffling(*, seed: Hash32, validators: Sequence['ValidatorRecord'],
                  slot: SlotNumber, epoch_length: int,
                  target_committee_size: int,
                  shard_count: int) -> Tuple[Iterable[ValidatorIndex], ...]:
    """
    Shuffle ``validators`` into crosslink committees seeded by ``seed`` and ``slot``.
    Return a list of ``EPOCH_LENGTH * committees_per_slot`` committees where each
    committee is itself a list of validator indices.

    If ``get_shuffling(seed, validators, slot)`` returns some value ``x``, it should return
    the same value ``x`` for the same seed and slot and possible future modifications of
    validators forever in phase 0, and until the ~1 year deletion delay in phase 2 and in the
    future.
    """
    # Normalizes slot to start of epoch boundary
    slot = SlotNumber(slot - slot % epoch_length)

    active_validator_indices = get_active_validator_indices(validators, slot)

    committees_per_slot = get_committee_count_per_slot(
        len(active_validator_indices),
        shard_count,
        epoch_length,
        target_committee_size,
    )

    # Shuffle
    seed = bitwise_xor(seed, Hash32(slot.to_bytes(32, byteorder="big")))
    shuffled_active_validator_indices = shuffle(active_validator_indices, seed)

    # Split the shuffled list into epoch_length * committees_per_slot pieces
    return tuple(
        split(
            shuffled_active_validator_indices,
            committees_per_slot * epoch_length,
        ))
Exemplo n.º 4
0
def test_shuffle_out_of_bound():
    values = [i for i in range(2**24 + 1)]
    with pytest.raises(ValueError):
        shuffle(values, b'hello')
Exemplo n.º 5
0
def test_shuffle_consistent(values, seed, expect):
    assert shuffle(values, seed) == expect
Exemplo n.º 6
0
def test_shuffle_consistent(values, seed, shuffle_round_count):
    expect = slow_shuffle(values, seed, shuffle_round_count)
    assert shuffle(values, seed, shuffle_round_count) == expect
Exemplo n.º 7
0
def get_shuffling(*, seed: Hash32, validators: Sequence['ValidatorRecord'],
                  crosslinking_start_shard: ShardNumber, slot: SlotNumber,
                  epoch_length: int, target_committee_size: int,
                  shard_count: int) -> Iterable[Tuple[ShardCommittee]]:
    """
    Return shuffled ``shard_committee_for_slots`` (``[[ShardCommittee]]``) of
    the given active ``validators`` using ``seed`` as entropy.

    Two-dimensional:
    The first layer is ``slot`` number
        ``shard_committee_for_slots[slot] -> [ShardCommittee]``
    The second layer is ``shard_indices`` number
        ``shard_committee_for_slots[slot][shard_indices] -> ShardCommittee``

    Example:
        validators:
            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
        After shuffling:
            [6, 0, 2, 12, 14, 8, 10, 4, 9, 1, 5, 13, 15, 7, 3, 11]
        Split by slot:
            [
                [6, 0, 2, 12, 14], [8, 10, 4, 9, 1], [5, 13, 15, 7, 3, 11]
            ]
        Split by shard:
            [
                [6, 0], [2, 12, 14], [8, 10], [4, 9, 1], [5, 13, 15] ,[7, 3, 11]
            ]
        Fill to output:
            [
                # slot 0
                [
                    ShardCommittee(shard_id=0, committee=[6, 0]),
                    ShardCommittee(shard_id=1, committee=[2, 12, 14]),
                ],
                # slot 1
                [
                    ShardCommittee(shard_id=2, committee=[8, 10]),
                    ShardCommittee(shard_id=3, committee=[4, 9, 1]),
                ],
                # slot 2
                [
                    ShardCommittee(shard_id=4, committee=[5, 13, 15]),
                    ShardCommittee(shard_id=5, committee=[7, 3, 11]),
                ],
            ]
    """
    active_validators = get_active_validator_indices(validators, slot)
    active_validators_size = len(active_validators)
    committees_per_slot = clamp(
        1,
        shard_count // epoch_length,
        active_validators_size // epoch_length // target_committee_size,
    )
    # Shuffle with seed
    shuffled_active_validator_indices = shuffle(active_validators, seed)

    # Split the shuffled list into epoch_length pieces
    validators_per_slot = split(shuffled_active_validator_indices,
                                epoch_length)
    for index, slot_indices in enumerate(validators_per_slot):
        # Split the shuffled list into committees_per_slot pieces
        shard_indices = split(slot_indices, committees_per_slot)
        start_shard = crosslinking_start_shard + index * committees_per_slot
        yield _get_shards_committees_for_shard_indices(
            shard_indices,
            start_shard,
            active_validators_size,
            shard_count,
        )