Skip to content

Commit a2724e3

Browse files
committed
test: remove txid caching in CTransaction class
Rather than txids (represented by the fields `.sha256` and `.hash`) being stateful, simply compute them on-the-fly. This ensures that the correct values are always returned and takes the burden of rehashing from test writers, making the code shorter overall. In a first step, the fields are kept at the same name with @Property functions as drop-in replacements, for a minimal diff. In later commits, the names are changed to be more descriptive and indicating the return type of the txid.
1 parent f3bbc74 commit a2724e3

File tree

2 files changed

+15
-19
lines changed

2 files changed

+15
-19
lines changed

test/functional/feature_block.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,10 +1053,9 @@ def run_test(self):
10531053
self.log.info("Reject a block containing a transaction spending from a non-existent input")
10541054
self.move_tip(69)
10551055
self.next_block(70, spend=out[21])
1056-
bogus_tx = CTransaction()
1057-
bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
1056+
bogus_txid_int = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
10581057
tx = CTransaction()
1059-
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", SEQUENCE_FINAL))
1058+
tx.vin.append(CTxIn(COutPoint(bogus_txid_int, 0), b"", SEQUENCE_FINAL))
10601059
tx.vout.append(CTxOut(1, b""))
10611060
b70 = self.update_block(70, [tx])
10621061
self.send_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)

test/functional/test_framework/messages.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,7 @@ def is_null(self):
585585

586586

587587
class CTransaction:
588-
__slots__ = ("hash", "nLockTime", "version", "sha256", "vin", "vout",
589-
"wit")
588+
__slots__ = ("nLockTime", "version", "vin", "vout", "wit")
590589

591590
def __init__(self, tx=None):
592591
if tx is None:
@@ -595,15 +594,11 @@ def __init__(self, tx=None):
595594
self.vout = []
596595
self.wit = CTxWitness()
597596
self.nLockTime = 0
598-
self.sha256 = None
599-
self.hash = None
600597
else:
601598
self.version = tx.version
602599
self.vin = copy.deepcopy(tx.vin)
603600
self.vout = copy.deepcopy(tx.vout)
604601
self.nLockTime = tx.nLockTime
605-
self.sha256 = tx.sha256
606-
self.hash = tx.hash
607602
self.wit = copy.deepcopy(tx.wit)
608603

609604
def deserialize(self, f):
@@ -625,8 +620,6 @@ def deserialize(self, f):
625620
else:
626621
self.wit = CTxWitness()
627622
self.nLockTime = int.from_bytes(f.read(4), "little")
628-
self.sha256 = None
629-
self.hash = None
630623

631624
def serialize_without_witness(self):
632625
r = b""
@@ -667,23 +660,27 @@ def serialize(self):
667660
def getwtxid(self):
668661
return hash256(self.serialize())[::-1].hex()
669662

663+
@property
664+
def hash(self):
665+
"""Return txid (transaction hash without witness) as hex string."""
666+
return hash256(self.serialize_without_witness())[::-1].hex()
667+
668+
@property
669+
def sha256(self):
670+
"""Return txid (transaction hash without witness) as integer."""
671+
return uint256_from_str(hash256(self.serialize_without_witness()))
672+
670673
# Recalculate the txid (transaction hash without witness)
674+
# TODO: get rid of this method, replace call-sites by .hash access
671675
def rehash(self):
672-
self.sha256 = None
673-
self.calc_sha256()
674676
return self.hash
675677

676-
# We will only cache the serialization without witness in
677-
# self.sha256 and self.hash -- those are expected to be the txid.
678+
# TODO: get rid of this method, replace call-sites by .wtxid_int access (not introduced yet)
678679
def calc_sha256(self, with_witness=False):
679680
if with_witness:
680681
# Don't cache the result, just return it
681682
return uint256_from_str(hash256(self.serialize_with_witness()))
682683

683-
if self.sha256 is None:
684-
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
685-
self.hash = hash256(self.serialize_without_witness())[::-1].hex()
686-
687684
def is_valid(self):
688685
self.calc_sha256()
689686
for tout in self.vout:

0 commit comments

Comments
 (0)