|
| 1 | +import os |
| 2 | +import random |
| 3 | +import time |
| 4 | + |
| 5 | +import pytest |
| 6 | + |
| 7 | +import rlp |
| 8 | + |
| 9 | +from eth_hash.auto import keccak |
| 10 | + |
| 11 | +from eth_utils import ( |
| 12 | + to_tuple, |
| 13 | + big_endian_to_int, |
| 14 | +) |
| 15 | + |
| 16 | +from eth.db.trie import make_trie_root_and_nodes |
| 17 | +from eth.rlp.headers import BlockHeader |
| 18 | +from eth.rlp.transactions import BaseTransactionFields |
| 19 | + |
| 20 | +from p2p.exceptions import ValidationError |
| 21 | + |
| 22 | +from trinity.rlp.block_body import BlockBody |
| 23 | +from trinity.protocol.eth.requests import BlockBodiesRequest |
| 24 | + |
| 25 | + |
| 26 | +def mk_uncle(block_number): |
| 27 | + return BlockHeader( |
| 28 | + state_root=os.urandom(32), |
| 29 | + difficulty=1000000, |
| 30 | + block_number=block_number, |
| 31 | + gas_limit=3141592, |
| 32 | + timestamp=int(time.time()), |
| 33 | + ) |
| 34 | + |
| 35 | + |
| 36 | +def mk_transaction(): |
| 37 | + return BaseTransactionFields( |
| 38 | + nonce=0, |
| 39 | + gas=21000, |
| 40 | + gas_price=1, |
| 41 | + to=os.urandom(20), |
| 42 | + value=random.randint(0, 100), |
| 43 | + data=b'', |
| 44 | + v=27, |
| 45 | + r=big_endian_to_int(os.urandom(32)), |
| 46 | + s=big_endian_to_int(os.urandom(32)), |
| 47 | + ) |
| 48 | + |
| 49 | + |
| 50 | +def mk_header_and_body(block_number, num_transactions, num_uncles): |
| 51 | + transactions = tuple(mk_transaction() for _ in range(num_transactions)) |
| 52 | + uncles = tuple(mk_uncle(block_number - 1) for _ in range(num_uncles)) |
| 53 | + |
| 54 | + transaction_root, trie_data = make_trie_root_and_nodes(transactions) |
| 55 | + uncles_hash = keccak(rlp.encode(uncles)) |
| 56 | + |
| 57 | + body = BlockBody(transactions=transactions, uncles=uncles) |
| 58 | + |
| 59 | + header = BlockHeader( |
| 60 | + difficulty=1000000, |
| 61 | + block_number=block_number, |
| 62 | + gas_limit=3141592, |
| 63 | + timestamp=int(time.time()), |
| 64 | + transaction_root=transaction_root, |
| 65 | + uncles_hash=uncles_hash, |
| 66 | + ) |
| 67 | + |
| 68 | + return header, body, transaction_root, trie_data, uncles_hash |
| 69 | + |
| 70 | + |
| 71 | +@to_tuple |
| 72 | +def mk_headers(*counts): |
| 73 | + for idx, (num_transactions, num_uncles) in enumerate(counts, 1): |
| 74 | + yield mk_header_and_body(idx, num_transactions, num_uncles) |
| 75 | + |
| 76 | + |
| 77 | +def test_block_bodies_request_empty_response_is_valid(): |
| 78 | + headers_bundle = mk_headers((2, 3), (8, 4), (0, 1), (0, 0)) |
| 79 | + headers, _, _, _, _ = zip(*headers_bundle) |
| 80 | + request = BlockBodiesRequest(headers) |
| 81 | + request.validate_response(tuple(), tuple()) |
| 82 | + |
| 83 | + |
| 84 | +def test_block_bodies_request_valid_with_full_response(): |
| 85 | + headers_bundle = mk_headers((2, 3), (8, 4), (0, 1), (0, 0)) |
| 86 | + headers, bodies, transactions_roots, trie_data_dicts, uncles_hashes = zip(*headers_bundle) |
| 87 | + transactions_bundles = tuple(zip(transactions_roots, trie_data_dicts)) |
| 88 | + bodies_bundle = tuple(zip(bodies, transactions_bundles, uncles_hashes)) |
| 89 | + request = BlockBodiesRequest(headers) |
| 90 | + request.validate_response(bodies, bodies_bundle) |
| 91 | + |
| 92 | + |
| 93 | +def test_block_bodies_request_valid_with_partial_response(): |
| 94 | + headers_bundle = mk_headers((2, 3), (8, 4), (0, 1), (0, 0)) |
| 95 | + headers, bodies, transactions_roots, trie_data_dicts, uncles_hashes = zip(*headers_bundle) |
| 96 | + transactions_bundles = tuple(zip(transactions_roots, trie_data_dicts)) |
| 97 | + bodies_bundle = tuple(zip(bodies, transactions_bundles, uncles_hashes)) |
| 98 | + request = BlockBodiesRequest(headers) |
| 99 | + |
| 100 | + request.validate_response(bodies[:2], bodies_bundle[:2]) |
| 101 | + request.validate_response(bodies[2:], bodies_bundle[2:]) |
| 102 | + request.validate_response( |
| 103 | + (bodies[0], bodies[2], bodies[3]), |
| 104 | + (bodies_bundle[0], bodies_bundle[2], bodies_bundle[3]), |
| 105 | + ) |
| 106 | + |
| 107 | + |
| 108 | +def test_block_bodies_request_with_fully_invalid_response(): |
| 109 | + headers_bundle = mk_headers((2, 3), (8, 4), (0, 1), (0, 0)) |
| 110 | + headers, _, _, _, _ = zip(*headers_bundle) |
| 111 | + |
| 112 | + wrong_headers_bundle = mk_headers((3, 2), (4, 8), (1, 0), (0, 0)) |
| 113 | + w_headers, w_bodies, w_transactions_roots, w_trie_data_dicts, w_uncles_hashes = zip( |
| 114 | + *wrong_headers_bundle |
| 115 | + ) |
| 116 | + w_transactions_bundles = tuple(zip(w_transactions_roots, w_trie_data_dicts)) |
| 117 | + w_bodies_bundle = tuple(zip(w_bodies, w_transactions_bundles, w_uncles_hashes)) |
| 118 | + |
| 119 | + request = BlockBodiesRequest(headers) |
| 120 | + with pytest.raises(ValidationError): |
| 121 | + request.validate_response(w_bodies, w_bodies_bundle) |
| 122 | + |
| 123 | + |
| 124 | +def test_block_bodies_request_with_extra_unrequested_bodies(): |
| 125 | + headers_bundle = mk_headers((2, 3), (8, 4), (0, 1), (0, 0)) |
| 126 | + headers, bodies, transactions_roots, trie_data_dicts, uncles_hashes = zip(*headers_bundle) |
| 127 | + transactions_bundles = tuple(zip(transactions_roots, trie_data_dicts)) |
| 128 | + bodies_bundle = tuple(zip(bodies, transactions_bundles, uncles_hashes)) |
| 129 | + request = BlockBodiesRequest(headers) |
| 130 | + |
| 131 | + wrong_headers_bundle = mk_headers((3, 2), (4, 8), (1, 0), (0, 0)) |
| 132 | + w_headers, w_bodies, w_transactions_roots, w_trie_data_dicts, w_uncles_hashes = zip( |
| 133 | + *wrong_headers_bundle |
| 134 | + ) |
| 135 | + w_transactions_bundles = tuple(zip(w_transactions_roots, w_trie_data_dicts)) |
| 136 | + w_bodies_bundle = tuple(zip(w_bodies, w_transactions_bundles, w_uncles_hashes)) |
| 137 | + |
| 138 | + request = BlockBodiesRequest(headers) |
| 139 | + with pytest.raises(ValidationError): |
| 140 | + request.validate_response( |
| 141 | + bodies + w_bodies, |
| 142 | + bodies_bundle + w_bodies_bundle, |
| 143 | + ) |
0 commit comments