Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 8ff06a4

Browse files
committed
Switch _builder -> _decoder in ChainDB, plus tests
Add tests for getting a transaction receipt, since that code path was not exercised in testing, and caused a fatal bug when using Trinity. Note that ChainDB uses the keyword receipt_decoder instead of receipt_builder everywhere (and the same for transaction_decoder). At the DB level, the logic only cares to decode from bytestrings (as opposed to the p2p layer, which always needs to be rlp-encodable, even if it's an opaque bytestring). Since the database only uses the "decode from bytestring" API, in can use the "tighter" ReceiptDecoderAPI instead of the broader ReceiptBuilderAPI. Enforcing that tighter usage seems to make sense.
1 parent 8af30c9 commit 8ff06a4

File tree

5 files changed

+59
-14
lines changed

5 files changed

+59
-14
lines changed

eth/abc.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ def add_transaction(self,
10781078
def get_block_transactions(
10791079
self,
10801080
block_header: BlockHeaderAPI,
1081-
transaction_builder: Type[TransactionBuilderAPI]) -> Tuple[SignedTransactionAPI, ...]:
1081+
transaction_decoder: Type[TransactionDecoderAPI]) -> Tuple[SignedTransactionAPI, ...]:
10821082
"""
10831083
Return an iterable of transactions for the block speficied by the
10841084
given block header.
@@ -1096,7 +1096,7 @@ def get_block_transaction_hashes(self, block_header: BlockHeaderAPI) -> Tuple[Ha
10961096
def get_receipt_by_index(self,
10971097
block_number: BlockNumber,
10981098
receipt_index: int,
1099-
receipt_builder: Type[ReceiptBuilderAPI]) -> ReceiptAPI:
1099+
receipt_decoder: Type[ReceiptDecoderAPI]) -> ReceiptAPI:
11001100
"""
11011101
Return the receipt of the transaction at specified index
11021102
for the block header obtained by the specified block number
@@ -1106,7 +1106,7 @@ def get_receipt_by_index(self,
11061106
@abstractmethod
11071107
def get_receipts(self,
11081108
header: BlockHeaderAPI,
1109-
receipt_class: Type[ReceiptBuilderAPI]) -> Tuple[ReceiptAPI, ...]:
1109+
receipt_decoder: Type[ReceiptDecoderAPI]) -> Tuple[ReceiptAPI, ...]:
11101110
"""
11111111
Return a tuple of receipts for the block specified by the given
11121112
block header.
@@ -1118,7 +1118,7 @@ def get_transaction_by_index(
11181118
self,
11191119
block_number: BlockNumber,
11201120
transaction_index: int,
1121-
transaction_builder: Type[TransactionBuilderAPI]) -> SignedTransactionAPI:
1121+
transaction_decoder: Type[TransactionDecoderAPI]) -> SignedTransactionAPI:
11221122
"""
11231123
Return the transaction at the specified `transaction_index` from the
11241124
block specified by `block_number` from the canonical chain.

eth/chains/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,9 @@ def get_transaction_receipt_by_index(self,
427427
vm = self.get_vm_class_for_block_number(block_number)
428428

429429
receipt = self.chaindb.get_receipt_by_index(
430-
block_number=block_number,
431-
receipt_index=index,
432-
receipt_builder=vm.get_receipt_builder(),
430+
block_number,
431+
index,
432+
vm.get_receipt_builder(),
433433
)
434434

435435
return receipt

eth/db/chain.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
ReceiptAPI,
3232
ReceiptDecoderAPI,
3333
SignedTransactionAPI,
34-
TransactionBuilderAPI,
34+
TransactionDecoderAPI,
3535
)
3636
from eth.constants import (
3737
EMPTY_UNCLE_HASH,
@@ -307,8 +307,8 @@ def add_transaction(self,
307307
def get_block_transactions(
308308
self,
309309
header: BlockHeaderAPI,
310-
transaction_builder: Type[TransactionBuilderAPI]) -> Tuple[SignedTransactionAPI, ...]:
311-
return self._get_block_transactions(header.transaction_root, transaction_builder)
310+
transaction_decoder: Type[TransactionDecoderAPI]) -> Tuple[SignedTransactionAPI, ...]:
311+
return self._get_block_transactions(header.transaction_root, transaction_decoder)
312312

313313
def get_block_transaction_hashes(self, block_header: BlockHeaderAPI) -> Tuple[Hash32, ...]:
314314
"""
@@ -347,7 +347,7 @@ def get_transaction_by_index(
347347
self,
348348
block_number: BlockNumber,
349349
transaction_index: int,
350-
transaction_builder: Type[TransactionBuilderAPI]) -> SignedTransactionAPI:
350+
transaction_decoder: Type[TransactionDecoderAPI]) -> SignedTransactionAPI:
351351
try:
352352
block_header = self.get_canonical_block_header_by_number(block_number)
353353
except HeaderNotFound:
@@ -356,7 +356,7 @@ def get_transaction_by_index(
356356
encoded_index = rlp.encode(transaction_index)
357357
encoded_transaction = transaction_db[encoded_index]
358358
if encoded_transaction != b'':
359-
return transaction_builder.decode(encoded_transaction)
359+
return transaction_decoder.decode(encoded_transaction)
360360
else:
361361
raise TransactionNotFound(
362362
f"No transaction is at index {transaction_index} of block {block_number}"
@@ -413,12 +413,12 @@ def _get_block_transaction_data(db: DatabaseAPI, transaction_root: Hash32) -> It
413413
def _get_block_transactions(
414414
self,
415415
transaction_root: Hash32,
416-
transaction_builder: Type[TransactionBuilderAPI]) -> Iterable[SignedTransactionAPI]:
416+
transaction_decoder: Type[TransactionDecoderAPI]) -> Iterable[SignedTransactionAPI]:
417417
"""
418418
Memoizable version of `get_block_transactions`
419419
"""
420420
for encoded_transaction in self._get_block_transaction_data(self.db, transaction_root):
421-
yield transaction_builder.decode(encoded_transaction)
421+
yield transaction_decoder.decode(encoded_transaction)
422422

423423
@staticmethod
424424
def _remove_transaction_from_canonical_chain(db: DatabaseAPI, transaction_hash: Hash32) -> None:

newsfragments/1994.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash in :meth:`eth.chains.base.Chain.get_transaction_receipt` and
2+
:meth:`eth.chains.base.Chain.get_transaction_receipt_by_index` that resulted in this exception:
3+
``TypeError: get_receipt_by_index() got an unexpected keyword argument 'receipt_builder'``

tests/core/chain-object/test_chain.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,45 @@ def test_mainnet_genesis_hash():
158158
def test_ropsten_genesis_hash():
159159
assert ROPSTEN_GENESIS_HEADER.hash == decode_hex(
160160
'0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d')
161+
162+
163+
def test_get_canonical_transaction_by_index(chain, tx):
164+
if hasattr(chain, 'apply_transaction'):
165+
# working on a Mining chain which can directly apply transactions
166+
new_block, _, computation = chain.apply_transaction(tx)
167+
computation.raise_if_error()
168+
else:
169+
# working on a non-mining chain, so we have to build the block to apply manually
170+
new_block, receipts, computations = chain.build_block_with_transactions([tx])
171+
assert len(computations) == 1
172+
computations[0].raise_if_error()
173+
174+
block_import_result = chain.import_block(new_block)
175+
block = block_import_result.imported_block
176+
177+
assert block.transactions == (tx,)
178+
# transaction at block 1, idx 0
179+
assert chain.get_canonical_transaction_index(tx.hash) == (1, 0)
180+
assert chain.get_canonical_transaction_by_index(1, 0) == tx
181+
182+
183+
def test_get_transaction_receipt(chain, tx):
184+
if hasattr(chain, 'apply_transaction'):
185+
# working on a Mining chain which can directly apply transactions
186+
new_block, expected_receipt, computation = chain.apply_transaction(tx)
187+
computation.raise_if_error()
188+
else:
189+
# working on a non-mining chain, so we have to build the block to apply manually
190+
new_block, receipts, computations = chain.build_block_with_transactions([tx])
191+
assert len(computations) == 1
192+
computations[0].raise_if_error()
193+
expected_receipt = receipts[0]
194+
195+
block_import_result = chain.import_block(new_block)
196+
block = block_import_result.imported_block
197+
198+
assert block.transactions == (tx,)
199+
# receipt at block 1, idx 0
200+
assert chain.get_canonical_transaction_index(tx.hash) == (1, 0)
201+
assert chain.get_transaction_receipt_by_index(1, 0) == expected_receipt
202+
assert chain.get_transaction_receipt(tx.hash) == expected_receipt

0 commit comments

Comments
 (0)