Exemplo n.º 1
0
def validate_gte(value: int, minimum: int, title: str = "Value") -> None:
    if value < minimum:
        raise ValidationError(
            f"{title} {value} is not greater than or equal to {minimum}")
    validate_is_integer(value)
Exemplo n.º 2
0
    def return_gas(self, amount: int) -> None:
        if amount < 0:
            raise ValidationError("Gas return amount must be positive")

        self.gas_remaining += amount
Exemplo n.º 3
0
    async def _fetch_full_skeleton(self) -> None:
        """
        Request a skeleton of headers.  In other words, return headers with gaps like so:
        parent -> child -> [skip] ... [skip] -> parent -> child -> [skip] ... [skip] -> ...

        There are some exceptions where more than two headers are returned consecutively.
        """
        peer = self.peer

        # launch the skeleton sync by finding a segment that has a parent header in the DB
        launch_headers = await self.wait(self._find_launch_headers(peer))
        self._fetched_headers.put_nowait(launch_headers)
        previous_tail_header = launch_headers[-1]
        start_num = BlockNumber(previous_tail_header.block_number +
                                self._skip_length)

        while self.is_operational:
            # get parents
            parents = await self._fetch_headers_from(peer, start_num)
            if not parents:
                break

            # get children
            children = await self._fetch_headers_from(
                peer, BlockNumber(start_num + 1))
            if not children:
                break

            # validate that parents and children match
            pairs = tuple(zip(parents, children))
            try:
                validate_pair_coros = [
                    self.wait(
                        self._chain.coro_validate_chain(parent, (child, )))
                    for parent, child in pairs
                ]
                await asyncio.gather(*validate_pair_coros,
                                     loop=self.get_event_loop())
            except ValidationError as e:
                self.logger.warning(
                    "Received invalid headers from %s, disconnecting: %s",
                    peer, e)
                raise

            # select and validate a single random gap, to test that skeleton peer has meat headers
            if len(pairs) >= 2:
                # choose random gap to fill
                gap_index = randrange(0, len(pairs) - 1)
                segments = await self._fill_in_gap(peer, pairs, gap_index)
                if len(segments) == 0:
                    raise ValidationError(
                        "Unexpected - filling in gap silently returned no headers"
                    )
            else:
                segments = pairs

            previous_lead_header = segments[0][0]
            previous_tail_header = segments[-1][-1]
            self.logger.debug(
                "Got new header bones from %s: %s-%s",
                peer,
                previous_lead_header,
                previous_tail_header,
            )
            # load all headers, pausing when buffer is full
            for segment in segments:
                if len(segment) > 0:
                    await self.wait(self._fetched_headers.put(segment))
                else:
                    raise ValidationError(
                        f"Found empty header segment in {segments}")

            # prepare for the next request
            start_num = previous_tail_header.block_number + self._skip_length - 1

        await self._get_final_headers(peer, previous_tail_header)
Exemplo n.º 4
0
    def _persist_block_chain(
            cls,
            db: BaseDB,
            blocks: Iterable[BaseBeaconBlock],
            block_class: Type[BaseBeaconBlock]
    ) -> Tuple[Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]:
        blocks_iterator = iter(blocks)

        try:
            first_block = first(blocks_iterator)
        except StopIteration:
            return tuple(), tuple()

        try:
            previous_canonical_head = cls._get_canonical_head(db, block_class).root
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            no_canonical_head = True
        else:
            no_canonical_head = False

        is_genesis = first_block.parent_root == GENESIS_PARENT_HASH
        if not is_genesis and not cls._block_exists(db, first_block.parent_root):
            raise ParentNotFound(
                "Cannot persist block ({}) with unknown parent ({})".format(
                    encode_hex(first_block.root), encode_hex(first_block.parent_root)))

        if is_genesis:
            score = 0
            # TODO: this should probably be done as part of the fork choice rule processing
            db.set(
                SchemaV1.make_finalized_head_root_lookup_key(),
                first_block.hash,
            )
        else:
            score = first_block.slot

        curr_block_head = first_block
        db.set(
            curr_block_head.root,
            ssz.encode(curr_block_head),
        )
        cls._add_block_root_to_slot_lookup(db, curr_block_head)
        cls._set_block_scores_to_db(db, curr_block_head)

        orig_blocks_seq = concat([(first_block,), blocks_iterator])

        for parent, child in sliding_window(2, orig_blocks_seq):
            if parent.root != child.parent_root:
                raise ValidationError(
                    "Non-contiguous chain. Expected {} to have {} as parent but was {}".format(
                        encode_hex(child.root),
                        encode_hex(parent.root),
                        encode_hex(child.parent_root),
                    )
                )

            curr_block_head = child
            db.set(
                curr_block_head.root,
                ssz.encode(curr_block_head),
            )
            cls._add_block_root_to_slot_lookup(db, curr_block_head)
            score = cls._set_block_scores_to_db(db, curr_block_head)

        if no_canonical_head:
            return cls._set_as_canonical_chain_head(db, curr_block_head.root, block_class)

        if score > head_score:
            return cls._set_as_canonical_chain_head(db, curr_block_head.root, block_class)
        else:
            return tuple(), tuple()
Exemplo n.º 5
0
def validate_header_integrity(header: BlockHeaderAPI,
                              epoch_length: int) -> None:

    if header.timestamp > eth_now():
        raise ValidationError(f"Invalid future timestamp: {header.timestamp}")

    at_checkpoint = is_checkpoint(header.block_number, epoch_length)

    if at_checkpoint and header.coinbase != ZERO_ADDRESS:
        raise ValidationError(
            f"Coinbase must be {encode_hex(ZERO_ADDRESS)} on checkpoints "
            f"but is {encode_hex(header.coinbase)}")

    if header.nonce != NONCE_AUTH and header.nonce != NONCE_DROP:
        raise ValidationError(f"Invalid nonce: {header.nonce!r}")

    if at_checkpoint and header.nonce != NONCE_DROP:
        raise ValidationError(f"Invalid checkpoint nonce: {header.nonce!r}")

    if len(header.extra_data) < VANITY_LENGTH:
        raise ValidationError("Missing vanity bytes in extra data")

    if len(header.extra_data) < VANITY_LENGTH + SIGNATURE_LENGTH:
        raise ValidationError("Missing signature in extra_data")

    signers_length = len(header.extra_data) - VANITY_LENGTH - SIGNATURE_LENGTH

    if not at_checkpoint and signers_length != 0:
        raise ValidationError(
            "Non-checkpoint header must not contain list of signers")

    if at_checkpoint and signers_length % COMMON_ADDRESS_LENGTH != 0:
        raise ValidationError("Checkpoint header must contain list of signers")

    if header.mix_hash != ZERO_HASH32:
        raise ValidationError(f"Invalid mix hash: {header.mix_hash!r}")

    if header.uncles_hash != EMPTY_UNCLE_HASH:
        raise ValidationError(f"Invalid uncle hash: {header.uncles_hash!r}")

    if header.difficulty not in ALLOWED_CLIQUE_DIFFICULTIES:
        raise ValidationError(f"Invalid difficulty: {header.difficulty}")
Exemplo n.º 6
0
def validate_homestead_transaction(
        state: BaseState, transaction: BaseOrSpoofTransaction) -> None:
    if transaction.s > SECPK1_N // 2 or transaction.s == 0:
        raise ValidationError("Invalid signature S value")

    validate_frontier_transaction(state, transaction)
Exemplo n.º 7
0
 def get_target_header_hash(self) -> Hash32:
     if self._target_header_hash is None:
         raise ValidationError("Cannot check the target hash when there is no active sync")
     else:
         return self._target_header_hash
Exemplo n.º 8
0
 def _validate_has_task(self, task_id: TTaskID) -> None:
     if task_id not in self._tasks:
         raise ValidationError(f"No task {task_id} is present")
Exemplo n.º 9
0
 def create_enr_signature(cls, enr, private_key: bytes) -> bytes:
     if len(private_key) != cls.private_key_size:
         raise ValidationError("Invalid private key")
     return private_key + enr.get_signing_message()
Exemplo n.º 10
0
Arquivo: base.py Projeto: nipz/py-evm
    def validate_uncles(self, block: BaseBlock) -> None:
        """
        Validate the uncles for the given block.
        """
        has_uncles = len(block.uncles) > 0
        should_have_uncles = block.header.uncles_hash != EMPTY_UNCLE_HASH

        if not has_uncles and not should_have_uncles:
            # optimization to avoid loading ancestors from DB, since the block has no uncles
            return
        elif has_uncles and not should_have_uncles:
            raise ValidationError(
                "Block has uncles but header suggests uncles should be empty")
        elif should_have_uncles and not has_uncles:
            raise ValidationError(
                "Header suggests block should have uncles but block has none")

        # Check for duplicates
        uncle_groups = groupby(operator.attrgetter('hash'), block.uncles)
        duplicate_uncles = tuple(
            sorted(hash for hash, twins in uncle_groups.items()
                   if len(twins) > 1))
        if duplicate_uncles:
            raise ValidationError("Block contains duplicate uncles:\n"
                                  " - {0}".format(
                                      ' - '.join(duplicate_uncles)))

        recent_ancestors = tuple(ancestor for ancestor in self.get_ancestors(
            MAX_UNCLE_DEPTH + 1, header=block.header))
        recent_ancestor_hashes = {
            ancestor.hash
            for ancestor in recent_ancestors
        }
        recent_uncle_hashes = _extract_uncle_hashes(recent_ancestors)

        for uncle in block.uncles:
            if uncle.hash == block.hash:
                raise ValidationError("Uncle has same hash as block")

            # ensure the uncle has not already been included.
            if uncle.hash in recent_uncle_hashes:
                raise ValidationError("Duplicate uncle: {0}".format(
                    encode_hex(uncle.hash)))

            # ensure that the uncle is not one of the canonical chain blocks.
            if uncle.hash in recent_ancestor_hashes:
                raise ValidationError(
                    "Uncle {0} cannot be an ancestor of {1}".format(
                        encode_hex(uncle.hash), encode_hex(block.hash)))

            # ensure that the uncle was built off of one of the canonical chain
            # blocks.
            if uncle.parent_hash not in recent_ancestor_hashes or (
                    uncle.parent_hash == block.header.parent_hash):
                raise ValidationError(
                    "Uncle's parent {0} is not an ancestor of {1}".format(
                        encode_hex(uncle.parent_hash), encode_hex(block.hash)))

            # Now perform VM level validation of the uncle
            self.validate_seal(uncle)

            try:
                uncle_parent = self.get_block_header_by_hash(uncle.parent_hash)
            except HeaderNotFound:
                raise ValidationError("Uncle ancestor not found: {0}".format(
                    uncle.parent_hash))

            uncle_vm_class = self.get_vm_class_for_block_number(
                uncle.block_number)
            uncle_vm_class.validate_uncle(block, uncle, uncle_parent)
Exemplo n.º 11
0
    def __setitem__(self, key: bytes, value: bytes) -> None:
        if self._track_diff is None:
            raise ValidationError(
                "Cannot set data from a write batch, out of context")

        self._track_diff[key] = value
Exemplo n.º 12
0
from eth2.beacon.state_machines.forks.serenity.block_validation import (
    validate_block_slot,
    validate_proposer_signature,
    validate_randao_reveal,
)
from eth2.beacon.tools.builder.initializer import create_mock_validator
from eth2.beacon.types.blocks import BeaconBlock, SignedBeaconBlock
from eth2.beacon.types.states import BeaconState
from eth2.configs import CommitteeConfig


@pytest.mark.parametrize(
    "state_slot,"
    "block_slot,"
    "expected",
    ((10, 10, None), (1, 10, ValidationError()), (10, 1, ValidationError())),
)
def test_validate_block_slot(
    sample_beacon_state_params,
    sample_beacon_block_params,
    state_slot,
    block_slot,
    expected,
):
    state = BeaconState.create(**sample_beacon_state_params).set(
        "slot", state_slot)
    block = BeaconBlock.create(**sample_beacon_block_params).set(
        "slot", block_slot)
    if isinstance(expected, Exception):
        with pytest.raises(ValidationError):
            validate_block_slot(state, block)
Exemplo n.º 13
0
def validate_lt(value: int, maximum: int, title: str = "Value") -> None:
    if value >= maximum:
        raise ValidationError(f"{title} {value} is not less than {maximum}")
    validate_is_integer(value, title=title)
Exemplo n.º 14
0
def validate_gt(value: int, minimum: int, title: str = "Value") -> None:
    if value <= minimum:
        raise ValidationError(f"{title} {value} is not greater than {minimum}")
    validate_is_integer(value, title=title)
Exemplo n.º 15
0
def validate_lt(value, maximum, title="Value"):
    if value >= maximum:
        raise ValidationError("{title} {0} is not less than {1}".format(
            value, maximum, title=title))
    validate_is_integer(value, title=title)
Exemplo n.º 16
0
 def validate_enr_signature(cls, enr) -> None:
     if not enr.signature == enr.node_id + enr.get_signing_message():
         raise ValidationError("Invalid signature")
Exemplo n.º 17
0
def validate_canonical_address(value, title="Value"):
    if not isinstance(value, bytes) or not len(value) == 20:
        raise ValidationError(
            "{title} {0} is not a valid canonical address".format(value,
                                                                  title=title))
Exemplo n.º 18
0
def validate_tag_prefix(encoded_packet: bytes) -> None:
    if len(encoded_packet) < TAG_SIZE:
        raise ValidationError(
            f"Encoded packet is only {len(encoded_packet)} bytes, but should start with a "
            f"{TAG_SIZE} bytes tag"
        )
Exemplo n.º 19
0
 def _validate_sequence_number(self) -> None:
     if self.sequence_number < 0:
         raise ValidationError("Sequence number is negative")
Exemplo n.º 20
0
def validate_multiple_of(value, multiple_of, title="Value"):
    if not value % multiple_of == 0:
        raise ValidationError("{title} {0} is not a multiple of {1}".format(
            value, multiple_of, title=title))
    (-99, ) + (1, ) * 9,
), (
    (1, ) * 10,
    5,
    -99,
    (1, ) * 5 + (-99, ) + (1, ) * 4,
), (
    (1, ) * 10,
    9,
    -99,
    (1, ) * 9 + (-99, ),
), (
    (1, ) * 10,
    10,
    -99,
    ValidationError(),
)])
def test_update_tuple_item(tuple_data, index, new_value, expected):
    if isinstance(expected, Exception):
        with pytest.raises(ValidationError):
            update_tuple_item(
                tuple_data=tuple_data,
                index=index,
                new_value=new_value,
            )
    else:
        result = update_tuple_item(
            tuple_data=tuple_data,
            index=index,
            new_value=new_value,
        )
Exemplo n.º 22
0
def validate_is_boolean(value, title="Value"):
    if not isinstance(value, bool):
        raise ValidationError(
            "{title} must be an boolean.  Got type: {0}".format(type(value),
                                                                title=title))
Exemplo n.º 23
0
    # shard assignments should wrap around to 0 rather than continuing to SHARD_COUNT
    for slot_indices in shuffling:
        for shard_committee in slot_indices:
            assert shard_committee.shard < shard_count


#
# Get proposer postition
#
@pytest.mark.parametrize(
    ('num_validators,committee,parent_block_number,result_proposer_index'),
    [
        (100, [4, 5, 6, 7], 0, 4),
        (100, [4, 5, 6, 7], 2, 6),
        (100, [4, 5, 6, 7], 11, 7),
        (100, [], 1, ValidationError()),
    ],
)
def test_get_block_committees_info(monkeypatch, sample_block, sample_state,
                                   num_validators, committee,
                                   parent_block_number, result_proposer_index,
                                   epoch_length):
    from eth.beacon import helpers

    def mock_get_shard_committees_at_slot(state, slot, epoch_length):
        return (ShardCommittee(
            shard=1,
            committee=committee,
            total_validator_count=num_validators,
        ), )
Exemplo n.º 24
0
def validate_is_bytes(value, title="Value"):
    if not isinstance(value, bytes):
        raise ValidationError(
            "{title} must be a byte string.  Got: {0}".format(type(value),
                                                              title=title))
Exemplo n.º 25
0
def default_refund_strategy(gas_refunded_total: int, amount: int) -> int:
    if amount < 0:
        raise ValidationError("Gas refund amount must be positive")

    return gas_refunded_total + amount
Exemplo n.º 26
0
def validate_is_integer(value, title="Value"):
    if not isinstance(value, int) or isinstance(value, bool):
        raise ValidationError("{title} must be a an integer.  Got: {0}".format(
            type(value), title=title))
Exemplo n.º 27
0
 def validate(self) -> None:
     if self.gas < self.intrinsic_gas:
         raise ValidationError("Insufficient gas")
     self.check_signature_validity()
Exemplo n.º 28
0
def validate_gt(value, minimum, title="Value"):
    if value <= minimum:
        raise ValidationError("{title} {0} is not greater than {1}".format(
            value, minimum, title=title))
    validate_is_integer(value, title=title)
Exemplo n.º 29
0
    async def _find_launch_headers(
            self, peer: TChainPeer) -> Tuple[BlockHeader, ...]:
        """
        When getting started with a peer, find exactly where the headers start differing from the
        current database of headers by requesting contiguous headers from peer. Return the first
        headers returned that are missing from the local db.

        It is possible that it will be unreasonable to find the exact starting header. For example,
        the canonical head may update while waiting for a response from the skeleton peer. In
        that case, return a *stale* header that we already know about, and there will be some
        duplicate header downloads.
        """
        newest_matching_header = await self._find_newest_matching_skeleton_header(
            peer)

        # This next gap will have at least one header that's new to us, because it overlaps
        # with the skeleton header that is next in the previous skeleton request, and
        # we chose the starting skeleton header so it goes past our canonical head
        start_num = newest_matching_header.block_number + 1
        launch_headers = await self._fetch_headers_from(peer,
                                                        start_num,
                                                        skip=0)

        if len(launch_headers) == 0:
            raise ValidationError(
                f"{peer} gave 0 headers when seeking common meat ancestors from {start_num}"
            )

        # identify headers that are not already stored locally
        new_headers = tuple(
            # The inner list comprehension is needed because async_generators
            # cannot be cast to a tuple.
            [
                header async for header in self.wait_iter(
                    self._get_missing_tail(launch_headers))
            ])
        if len(new_headers) == 0:
            self.logger.debug(
                "Canonical head updated while finding new head from %s, returning old %s instead",
                peer,
                launch_headers[-1],
            )
            return (launch_headers[-1], )
        else:
            try:
                launch_parent = await self.wait(
                    self._db.coro_get_block_header_by_hash(
                        new_headers[0].parent_hash))
            except HeaderNotFound as exc:
                raise ValidationError(
                    f"First header {new_headers[0]} did not have parent in DB"
                ) from exc

            # validate new headers against the parent in the database
            await self.wait(
                self._chain.coro_validate_chain(
                    launch_parent,
                    new_headers,
                    SEAL_CHECK_RANDOM_SAMPLE_RATE,
                ))
            return new_headers
Exemplo n.º 30
0
def validate_is_integer(value: Union[int, bool], title: str = "Value") -> None:
    if not isinstance(value, int) or isinstance(value, bool):
        raise ValidationError(
            f"{title} must be a an integer.  Got: {type(value)}")