Exemple #1
0
def test_signing(block, private_key):
    canonicalized_block = get_canonicalized_block(block)
    signature = calculate_block_signature(canonicalized_block, private_key)
    resigned_block = AttributeDict(
        merge(canonicalized_block, {"signature": signature.to_bytes()}))
    assert get_proposer(
        resigned_block) == private_key.public_key.to_canonical_address()
Exemple #2
0
def blocks_from_block_dicts(block_dicts):
    return [
        Block(
            hash=block_dict.hash,
            proposer=get_proposer(get_canonicalized_block(block_dict)),
            step=get_step(block_dict),
        ) for block_dict in block_dicts
    ]
Exemple #3
0
def make_block(*,
               block_hash=None,
               parent_hash=None,
               proposer_privkey=None,
               step=None):
    if proposer_privkey is None:
        proposer_privkey = random_private_key()

    block = MutableAttributeDict({
        "hash":
        HexBytes(block_hash or random_hash()),
        "sealFields": [HexBytes(b""), HexBytes(b"")],
        "parentHash":
        HexBytes(parent_hash or random_hash()),
        "sha3Uncles":
        HexBytes(random_hash()),
        "author":
        proposer_privkey.public_key.to_address(),
        "stateRoot":
        HexBytes(random_hash()),
        "transactionsRoot":
        HexBytes(random_hash()),
        "receiptsRoot":
        HexBytes(random_hash()),
        "logsBloom":
        HexBytes(b"\x00" * 256),
        "difficulty":
        0,
        "number":
        0,
        "gasLimit":
        0,
        "gasUsed":
        0,
        "timestamp":
        0,  # only needed to compute hash, not step
        "step":
        str(step if step is not None else random_step()),
        "extraData":
        HexBytes(random_hash()),
        "privkey":
        proposer_privkey,  # add proposer private key to simplify testing.
        "signature":
        "",
    })

    block["signature"] = calculate_block_signature(
        get_canonicalized_block(block), proposer_privkey).to_hex()
    return block
def test_retrieve_no_blocks_by_proposer_and_step_for_non_existing_combinations(
        populated_db, inserted_blocks):
    block = inserted_blocks[-1]

    proposer = get_proposer(get_canonicalized_block(block))
    proposer_without_block = (
        random_address()
    )  # Collision rate with an actual proposer is most like zero.

    step = get_step(block)
    step_without_block = random_step()

    assert not populated_db.get_blocks_by_proposer_and_step(
        proposer, step_without_block)
    assert not populated_db.get_blocks_by_proposer_and_step(
        proposer_without_block, step)
def test_retrieve_single_block_by_proposer_and_step(populated_db,
                                                    inserted_blocks):
    for block in inserted_blocks:
        proposer = get_proposer(get_canonicalized_block(block))
        step = get_step(block)

        retrieved_blocks = populated_db.get_blocks_by_proposer_and_step(
            proposer, step)

        assert len(retrieved_blocks) == 1

        retrieved_block = retrieved_blocks[0]

        assert retrieved_block.hash == block.hash
        assert retrieved_block.step == step
        assert retrieved_block.proposer == proposer
Exemple #6
0
    def __call__(self, block):
        proposer = get_proposer(get_canonicalized_block(block))
        step = get_step(block)
        blocks_by_same_proposer_at_same_step = self.db.get_blocks_by_proposer_and_step(
            proposer, step
        )
        block_hashes_by_same_proposer_on_same_step = [
            block.hash for block in blocks_by_same_proposer_at_same_step
        ]

        # Ensures that the block has been added to the database, otherwise the following logic will not work.
        assert block.hash in block_hashes_by_same_proposer_on_same_step

        if len(block_hashes_by_same_proposer_on_same_step) >= 2:
            self.logger.info(
                "detected equivocation", proposer=encode_hex(proposer), step=step
            )

            for callback in self.report_callbacks:
                callback(block_hashes_by_same_proposer_on_same_step)
Exemple #7
0
    def equivocation_logger(self, equivocated_block_hashes):
        """Log a reported equivocation event.

        Equivocation reports are logged into files separated by the proposers
        address. Logged information are the proposer of the blocks, the steps
        at which all blocks have been equivocated and a list of all block hashes
        with their timestamp. Additionally two representing blocks are logged
        with their RLP encoded header and related signature, which can be used
        for an equivocation proof on reporting a validator.
        """

        assert len(equivocated_block_hashes) >= 2

        blocks = [
            self.w3.eth.getBlock(block_hash)
            for block_hash in equivocated_block_hashes
        ]

        block_hashes_and_timestamp_strings = [
            BLOCK_HASH_AND_TIMESTAMP_TEMPLATE.format(
                block_hash=encode_hex(block.hash),
                block_timestamp=datetime.datetime.utcfromtimestamp(
                    block.timestamp),
            ) for block in blocks
        ]

        block_hash_and_timestamp_summary = "\n".join(
            block_hashes_and_timestamp_strings)

        # Use the first two blocks as representational data for the equivocation proof.
        block_one = get_canonicalized_block(blocks[0])
        block_two = get_canonicalized_block(blocks[1])

        proposer_address_hex = encode_hex(get_proposer(block_one))

        equivocation_report_template_variables = {
            "proposer_address":
            proposer_address_hex,
            "block_step":
            block_one.step,
            "detection_time":
            datetime.datetime.utcnow(),
            "block_hash_timestamp_summary":
            block_hash_and_timestamp_summary,
            "rlp_encoded_block_header_one":
            encode_hex(rlp_encoded_block(block_one)),
            "signature_block_header_one":
            keys.Signature(block_one.signature),
            "rlp_encoded_block_header_two":
            encode_hex(rlp_encoded_block(block_two)),
            "signature_block_header_two":
            keys.Signature(block_two.signature),
        }

        equivocation_report_file_name = (
            f"equivocation_reports_for_proposer_{proposer_address_hex}")

        with open(self.report_dir / equivocation_report_file_name,
                  "a") as equivocation_report_file:
            equivocation_report_file.write(
                EQUIVOCATION_REPORT_TEMPLATE.format(
                    **equivocation_report_template_variables))
Exemple #8
0
def test_get_proposer_of_genesis_block():
    canonicalized_genesis_block = get_canonicalized_block(KOVAN_GENESIS_BLOCK)
    assert get_proposer(canonicalized_genesis_block) == b"\x00" * 20
Exemple #9
0
def test_get_proposer(block):
    canonicalized_block = get_canonicalized_block(block)
    # check the signer against the author field, which is the same address for the test data
    assert get_proposer(canonicalized_block) == canonicalized_block.author