def __init__(self,
                 status_code: bytes,
                 gas_used: int,
                 logs: Iterable[Log],
                 bloom: int = None) -> None:

        if bloom is None:
            bloomables = itertools.chain.from_iterable(log.bloomables
                                                       for log in logs)
            bloom = int(BloomFilter.from_iterable(bloomables))

        super(Receipt, self).__init__(
            status_code=status_code,
            gas_used=gas_used,
            bloom=bloom,
            logs=logs,
        )

        for log_idx, log in enumerate(self.logs):
            if log.address not in self.bloom_filter:
                raise ValidationError(
                    "The address from the log entry at position {0} is not "
                    "present in the provided bloom filter.".format(log_idx))
            for topic_idx, topic in enumerate(log.topics):
                if int32.serialize(topic) not in self.bloom_filter:
                    raise ValidationError(
                        "The topic at position {0} from the log entry at "
                        "position {1} is not present in the provided bloom "
                        "filter.".format(topic_idx, log_idx))
Exemple #2
0
    def validate_node_staking_score_with_context(
            self, node_staking_score: NodeStakingScore, chain_address: Address,
            block_timestamp: Timestamp,
            latest_reward_block_number: BlockNumber) -> None:

        if (node_staking_score.timestamp >
            (block_timestamp +
             self.reward_proof_timestamp_variability_allowance)
                or node_staking_score.timestamp <
            (block_timestamp -
             self.reward_proof_timestamp_variability_allowance)):
            raise ValidationError(
                'Reward type 2 proof isnt within acceptable range of block timestamp'
            )

        # make sure recipient node wlalet address is this node
        if node_staking_score.recipient_node_wallet_address != chain_address:
            raise ValidationError(
                "Reward type 2 proof recipient_node_wallet_address doesnt match this chain address"
            )

        #make sure the node_staking_score isnt from the same node trying to recieve the reward
        if node_staking_score.sender == chain_address:
            raise ValidationError(
                'One of the reward proofs was generated by the node receiving the reward. It needs proof from other nodes.'
            )

        self.validate_node_staking_score(
            node_staking_score, since_block_number=latest_reward_block_number)
def serialize_blobs(blobs: Iterable[bytes]) -> Iterator[bytes]:
    """Serialize a sequence of blobs and return a collation body."""
    for i, blob in enumerate(blobs):
        if len(blob) == 0:
            raise ValidationError(
                "Cannot serialize blob {} of length 0".format(i))
        if len(blob) > MAX_BLOB_SIZE:
            raise ValidationError("Cannot serialize blob {} of size {}".format(
                i, len(blob)))

        for blob_index in range(0, len(blob), CHUNK_DATA_SIZE):
            remaining_blob_bytes = len(blob) - blob_index

            if remaining_blob_bytes <= CHUNK_DATA_SIZE:
                length_bits = remaining_blob_bytes
            else:
                length_bits = 0

            flag_bits = 0  # TODO: second parameter? blobs as tuple `(flag, blob)`?
            indicator_byte = int_to_big_endian(length_bits | (flag_bits << 5))
            if len(indicator_byte) != 1:
                raise Exception("Invariant: indicator is not a single byte")

            yield indicator_byte
            yield blob[blob_index:blob_index + CHUNK_DATA_SIZE]

        # end of range(0, N, k) is given by the largest multiple of k smaller than N, i.e.,
        # (ceil(N / k) - 1) * k where ceil(N / k) == -(-N // k)
        last_blob_index = (-(-len(blob) // CHUNK_DATA_SIZE) -
                           1) * CHUNK_DATA_SIZE
        if last_blob_index != blob_index:
            raise Exception("Invariant: last blob index calculation failed")
        chunk_filler = b"\x00" * (CHUNK_DATA_SIZE -
                                  (len(blob) - last_blob_index))
        yield chunk_filler
Exemple #4
0
 def validate(self) -> None:
     """
     Hook called during instantiation to ensure that all transaction
     parameters pass validation rules.
     """
     if self.gas_price <= 0:
         raise ValidationError("Insufficient gas price. Must be at least 1")
     if self.intrinsic_gas > self.gas:
         raise ValidationError("Insufficient gas")
     self.check_signature_validity()
Exemple #5
0
    def validate_node_staking_score(self, node_staking_score: NodeStakingScore,
                                    since_block_number: BlockNumber) -> None:
        node_staking_score.validate()

        # make sure all proof's have valid signatures
        node_staking_score.check_signature_validity()

        # need to make sure we have the up-to-date peer chain so that our stake calculation is correct.
        # RewardProofSenderBlockMissing
        if not self.chaindb.is_in_canonical_chain(
                node_staking_score.head_hash_of_sender_chain):
            raise RewardProofSenderBlockMissing(
                "Our chain for chain_address {} appears to be out of date. We need the block with hash {}"
                .format(
                    encode_hex(node_staking_score.sender),
                    encode_hex(node_staking_score.head_hash_of_sender_chain)))

        # The node staking score proof cannot know about a block in the future.
        claimed_header = self.chaindb.get_block_header_by_hash(
            node_staking_score.head_hash_of_sender_chain)
        if claimed_header.timestamp > node_staking_score.timestamp:
            raise ValidationError(
                "Reward proof has a timestamp that is less than the claimed head hash of sender chain. This is impossible because it cannot know about the future, and not allowed."
            )

        # we have to make sure the head_hash_of_sender_chain is the newest block before the given timestamp
        next_block_number = claimed_header.block_number + 1
        try:
            next_header = self.chaindb.get_canonical_block_header_by_number(
                next_block_number, node_staking_score.sender)
            if next_header.timestamp < node_staking_score.timestamp:
                # it found a block that is earlier than the proof timestamp, but is newer than the claimed header. This means they claimed the wrong header
                raise ValidationError(
                    "Reward proof has incorrect header hash for the sender chain, at the timestamp the proof was made. "
                    "The timestamp of the node staking score is {}. The timestamp of the next block is {}. "
                    "The block number of the next block is {}. The hash of the next block is {}"
                    .format(node_staking_score.timestamp,
                            next_header.timestamp, next_header.block_number,
                            encode_hex(next_header.hash)))
        except HeaderNotFound:
            pass

        # We need to validate that the previous reward block in proof equals the latest reward block
        if node_staking_score.since_block_number != since_block_number:
            raise ValidationError(
                "Reward proof has incorrect since_block_number. Got {}, but should be {}"
                .format(node_staking_score.since_block_number,
                        since_block_number))

        if node_staking_score.score < 0 or node_staking_score.score > 1000000:
            raise ValidationError(
                'Node staking score is out of allowed range of 0 to 1,000,000. Got {}'
                .format(node_staking_score.score))
def validate_transaction_signature(salt, v, r, s) -> None:
    vrs = (v, r, s)
    signature = keys.Signature(vrs=vrs)

    parts_for_sig = salt
    message = rlp.encode(parts_for_sig)

    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")
def validate_word(value, title="Value"):
    if not isinstance(value, bytes):
        raise ValidationError(
            "{title} is not a valid word. Must be of bytes type: Got: {0}".
            format(
                type(value),
                title=title,
            ))
    elif not len(value) == 32:
        raise ValidationError(
            "{title} is not a valid word. Must be 32 bytes in length: Got: {0}"
            .format(
                len(value),
                title=title,
            ))
def calc_merkle_root(leaves: Iterable[Hash32]) -> Hash32:
    leaves = list(leaves)  # convert potential iterator to list
    if len(leaves) == 0:
        raise ValidationError("No leaves given")

    n_layers = math.log2(len(leaves))
    if not n_layers.is_integer():
        raise ValidationError("Leave number is not a power of two")
    n_layers = int(n_layers)

    first_layer = (keccak(leaf) for leaf in leaves)

    root, *extras = pipe(first_layer, *itertools.repeat(hash_layer, n_layers))
    assert not extras, "Invariant: should only be a single value"
    return root
Exemple #9
0
    def _decode_header_to_dict(cls, encoded_header: bytes) -> Iterator[Tuple[str, Any]]:
        if len(encoded_header) != cls.smc_encoded_size:
            raise ValidationError(
                "Expected encoded header to be of size: {0}. Got size {1} instead.\n- {2}".format(
                    cls.smc_encoded_size,
                    len(encoded_header),
                    encode_hex(encoded_header),
                )
            )

        start_indices = accumulate(lambda i, field: i + field[2], cls.fields_with_sizes, 0)
        field_bounds = sliding_window(2, start_indices)
        for byte_range, field in zip(field_bounds, cls._meta.fields):
            start_index, end_index = byte_range
            field_name, field_type = field

            field_bytes = encoded_header[start_index:end_index]
            if field_type == rlp.sedes.big_endian_int:
                # remove the leading zeros, to avoid `not minimal length` error in deserialization
                formatted_field_bytes = field_bytes.lstrip(b'\x00')
            elif field_type == address:
                formatted_field_bytes = field_bytes[-20:]
            else:
                formatted_field_bytes = field_bytes
            yield field_name, field_type.deserialize(formatted_field_bytes)
Exemple #10
0
def validate_frontier_transaction(account_db, transaction):
    gas_cost = transaction.gas * transaction.gas_price
    sender_balance = account_db.get_balance(transaction.sender)

    if sender_balance < gas_cost:
        raise ValidationError(
            "Sender account balance cannot afford txn gas: `{0}`".format(
                transaction.sender))

    total_cost = transaction.value + gas_cost

    if sender_balance < total_cost:
        raise ValidationError("Sender account balance cannot afford txn")

    if account_db.get_nonce(transaction.sender) != transaction.nonce:
        raise ValidationError("Invalid transaction nonce")
Exemple #11
0
def validate_rlp_equal(obj_a,
                       obj_b,
                       obj_a_name: str = None,
                       obj_b_name: str = None) -> None:
    if obj_a == obj_b:
        return

    if obj_a_name is None:
        obj_a_name = obj_a.__class__.__name__ + '_a'
    if obj_b_name is None:
        obj_b_name = obj_b.__class__.__name__ + '_b'

    diff = diff_rlp_object(obj_a, obj_b)
    if len(diff) == 0:
        raise TypeError("{} ({!r}) != {} ({!r}) but got an empty diff".format(
            obj_a_name,
            obj_a,
            obj_b_name,
            obj_b,
        ))
    longest_field_name = max(len(field_name) for field_name, _, _ in diff)
    error_message = (
        "Mismatch between {obj_a_name} and {obj_b_name} on {0} fields:\n - {1}"
        .format(
            len(diff),
            "\n - ".join(
                tuple("{0}:\n    (actual)  : {1}\n    (expected): {2}".format(
                    field_name.ljust(longest_field_name, ' '),
                    actual,
                    expected,
                ) for field_name, actual, expected in diff)),
            obj_a_name=obj_a_name,
            obj_b_name=obj_b_name,
        ))
    raise ValidationError(error_message)
Exemple #12
0
def validate_point(x: int, y: int) -> Tuple[bn128.FQ, bn128.FQ, bn128.FQ]:
    FQ = bn128.FQ

    if x >= bn128.field_modulus:
        raise ValidationError("Point x value is greater than field modulus")
    elif y >= bn128.field_modulus:
        raise ValidationError("Point y value is greater than field modulus")

    if (x, y) != (0, 0):
        p1 = (FQ(x), FQ(y), FQ(1))
        if not bn128.is_on_curve(p1, bn128.b):
            raise ValidationError("Point is not on the curve")
    else:
        p1 = (FQ(1), FQ(1), FQ(0))

    return p1
    def validate(self):
        if self.is_create:
            if self.execute_on_send:
                raise ValidationError(
                    "Create transactions are not allowed to execute on send.")

        super(PhotonTransaction, self).validate()
def validate_uint64(value, title="Value"):
    if not isinstance(value, int) or isinstance(value, bool):
        raise ValidationError("{title} must be an integer: Got: {0}".format(
            type(value),
            title=title,
        ))
    if value < 0:
        raise ValidationError("{title} cannot be negative: Got: {0}".format(
            value,
            title=title,
        ))
    if value > UINT_64_MAX:
        raise ValidationError(
            "{title} exeeds maximum UINT64 size.  Got: {0}".format(
                value,
                title=title,
            ))
def validate_stack_item(value):
    if isinstance(value, bytes) and len(value) <= 32:
        return
    elif isinstance(value, int) and 0 <= value <= UINT_256_MAX:
        return
    raise ValidationError(
        "Invalid Stack Item: Must be either a length 32 byte "
        "string or a 256 bit integer. Got {0}".format(value))
def validate_block_header_signature(block_header: BaseBlockHeader) -> None:
    v = extract_signature_v(block_header.v)

    canonical_v = v - 27

    vrs = (canonical_v, block_header.r, block_header.s)
    signature = keys.Signature(vrs=vrs)

    message = block_header.get_message_for_signing()
    
    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")
def validate_historical_timestamp(value, title="Value"):
    validate_uint256(value, title=title)
    if value % TIME_BETWEEN_HEAD_HASH_SAVE != 0:
        raise ValidationError(
            "{title} must be a multiple of {0}: Got: {1}".format(
                TIME_BETWEEN_HEAD_HASH_SAVE,
                value,
                title=title,
            ))
Exemple #18
0
    def save_items_to_db_as_trie(self, items, root_hash_to_verify=None):
        root_hash, kv_nodes = make_trie_root_and_nodes(items)
        if root_hash_to_verify is not None:
            if root_hash != root_hash_to_verify:
                raise ValidationError(
                    "root hash is not what it is expected to be.")

        self.chaindb.persist_trie_data_dict(kv_nodes)
        return root_hash, kv_nodes
def validate_centisecond_timestamp(value, title="Value"):
    validate_uint256(value, title=title)
    if value % 100 != 0:
        raise ValidationError(
            "{title} must be a multiple of {0}: Got: {1}".format(
                100,
                value,
                title=title,
            ))
def validate_lte(value, maximum, title="Value"):
    if value > maximum:
        raise ValidationError(
            "{title} {0} is not less than or equal to {1}".format(
                value,
                maximum,
                title=title,
            ))
    validate_is_integer(value, title=title)
def validate_gte(value, minimum, title="Value"):
    if value < minimum:
        raise ValidationError(
            "{title} {0} is not greater than or equal to {1}".format(
                value,
                minimum,
                title=title,
            ))
    validate_is_integer(value)
def validate_length(value, length, title="Value"):
    if not len(value) == length:
        raise ValidationError(
            "{title} must be of length {0}.  Got {1} of length {2}".format(
                length,
                value,
                len(value),
                title=title,
            ))
def validate_header_params_for_configuration(header_params):
    extra_fields = set(header_params.keys()).difference(ALLOWED_HEADER_FIELDS)
    if extra_fields:
        raise ValidationError(
            "The `configure_header` method may only be used with the fields ({0}). "
            "The provided fields ({1}) are not supported".format(
                ", ".join(tuple(sorted(ALLOWED_HEADER_FIELDS))),
                ", ".join(tuple(sorted(extra_fields))),
            ))
Exemple #24
0
def validate_frontier_transaction_against_header(_vm, base_header,
                                                 transaction):
    if base_header.gas_used + transaction.gas > base_header.gas_limit:
        raise ValidationError(
            "Transaction exceeds gas limit: using {}, bringing total to {}, but limit is {}"
            .format(
                transaction.gas,
                base_header.gas_used + transaction.gas,
                base_header.gas_limit,
            ))
def validate_helios_testnet_transaction_against_header(_vm, base_header,
                                                       send_transaction):
    if base_header.gas_used + send_transaction.gas > base_header.gas_limit:
        raise ValidationError(
            "send_transaction exceeds gas limit: using {}, bringing total to {}, but limit is {}"
            .format(
                send_transaction.gas,
                base_header.gas_used + send_transaction.gas,
                base_header.gas_limit,
            ))
def validate_length_lte(value, maximum_length, title="Value"):
    if len(value) > maximum_length:
        raise ValidationError(
            "{title} must be of length less than or equal to {0}.  "
            "Got {1} of length {2}".format(
                maximum_length,
                value,
                len(value),
                title=title,
            ))
Exemple #27
0
def check_shard_id(
        shard: Shard, header_or_collation: Union[CollationHeader,
                                                 Collation]) -> None:
    if header_or_collation.shard_id != shard.shard_id:
        raise ValidationError(
            "Header or collation belongs to shard {} instead of shard {}".
            format(
                header_or_collation.shard_id,
                shard.shard_id,
            ))
Exemple #28
0
    def validate_transaction(self, transaction):

        # Validate the transaction

        if transaction.intrinsic_gas > transaction.gas:
            raise ValidationError("Insufficient gas")

        transaction.validate()
        self.vm_state.validate_transaction(transaction)

        return transaction
Exemple #29
0
def extract_chain_id(v: int) -> int:
    if is_even(v):
        chain_id = (v - EIP155_CHAIN_ID_OFFSET - 1) // 2
    else:
        chain_id = (v - EIP155_CHAIN_ID_OFFSET) // 2

    if chain_id < 0:
        raise ValidationError(
            'Cannot extract chain id from object. Invalid signature or chain id.'
        )

    return chain_id
    def refund_gas(self, amount: int) -> None:
        if amount < 0:
            raise ValidationError("Gas refund amount must be positive")

        self.gas_refunded += amount

        self.logger.trace(
            'GAS REFUND: %s + %s -> %s',
            self.gas_refunded - amount,
            amount,
            self.gas_refunded,
        )