Skip to content

Commit d6a5916

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#22257: test: refactor: various (de)serialization helpers cleanups/improvements
bdb8b9a test: doc: improve doc for `from_hex` helper (mention `to_hex` alternative) (Sebastian Falbesoner) 1914054 scripted-diff: test: rename `FromHex` to `from_hex` (Sebastian Falbesoner) a79396f test: remove `ToHex` helper, use .serialize().hex() instead (Sebastian Falbesoner) 2ce7b47 test: introduce `tx_from_hex` helper for tx deserialization (Sebastian Falbesoner) Pull request description: There are still many functional tests that perform conversions from a hex-string to a message object (deserialization) manually. This PR identifies all those instances and replaces them with a newly introduced helper `tx_from_hex`. Instances were found via * `git grep "deserialize.*BytesIO"` and some of them manually, when it were not one-liners. Further, the helper `ToHex` was removed and simply replaced by `.serialize().hex()`, since now both variants are in use (sometimes even within the same test) and using the helper doesn't really have an advantage in readability. (see discussion bitcoin/bitcoin#22257 (comment)) ACKs for top commit: MarcoFalke: review re-ACK bdb8b9a 😁 Tree-SHA512: e25d7dc85918de1d6755a5cea65471b07a743204c20ad1c2f71ff07ef48cc1b9ad3fe5f515c1efaba2b2e3d89384e7980380c5d81895f9826e2046808cd3266e
2 parents c31161f + bdb8b9a commit d6a5916

33 files changed

+396
-261
lines changed

contrib/signet/miner

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNE
2323
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
2424

2525
from test_framework.blocktools import WITNESS_COMMITMENT_HEADER, script_BIP34_coinbase_height # noqa: E402
26-
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, ToHex, deser_string, hash256, ser_compact_size, ser_string, ser_uint256, uint256_from_str # noqa: E402
26+
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_hex, deser_string, hash256, ser_compact_size, ser_string, ser_uint256, tx_from_hex, uint256_from_str # noqa: E402
2727
from test_framework.script import CScriptOp # noqa: E402
2828

2929
logging.basicConfig(
@@ -37,7 +37,7 @@ RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
3737

3838
# #### some helpers that could go into test_framework
3939

40-
# like FromHex, but without the hex part
40+
# like from_hex, but without the hex part
4141
def FromBinary(cls, stream):
4242
"""deserialize a binary stream (or bytes object) into an object"""
4343
# handle bytes object by turning it into a stream
@@ -195,7 +195,7 @@ def finish_block(block, signet_solution, grind_cmd):
195195
headhex = CBlockHeader.serialize(block).hex()
196196
cmd = grind_cmd.split(" ") + [headhex]
197197
newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
198-
newhead = FromHex(CBlockHeader(), newheadhex.decode('utf8'))
198+
newhead = from_hex(CBlockHeader(), newheadhex.decode('utf8'))
199199
block.nNonce = newhead.nNonce
200200
block.rehash()
201201
return block
@@ -216,7 +216,7 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None):
216216
block.nTime = tmpl["mintime"]
217217
block.nBits = int(tmpl["bits"], 16)
218218
block.nNonce = 0
219-
block.vtx = [cbtx] + [FromHex(CTransaction(), t["data"]) for t in tmpl["transactions"]]
219+
block.vtx = [cbtx] + [tx_from_hex(t["data"]) for t in tmpl["transactions"]]
220220

221221
witnonce = 0
222222
witroot = block.calc_witness_merkle_root()
@@ -274,7 +274,7 @@ def do_genpsbt(args):
274274
def do_solvepsbt(args):
275275
block, signet_solution = do_decode_psbt(sys.stdin.read())
276276
block = finish_block(block, signet_solution, args.grind_cmd)
277-
print(ToHex(block))
277+
print(block.serialize().hex())
278278

279279
def nbits_to_target(nbits):
280280
shift = (nbits >> 24) & 0xff
@@ -503,7 +503,7 @@ def do_generate(args):
503503
block = finish_block(block, signet_solution, args.grind_cmd)
504504

505505
# submit block
506-
r = args.bcli("-stdin", "submitblock", input=ToHex(block).encode('utf8'))
506+
r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8'))
507507

508508
# report
509509
bstr = "block" if is_mine else "backup block"

test/functional/feature_bip68_sequence.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,19 @@
66

77
import time
88

9-
from test_framework.blocktools import create_block, NORMAL_GBT_REQUEST_PARAMS, add_witness_commitment
10-
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
9+
from test_framework.blocktools import (
10+
NORMAL_GBT_REQUEST_PARAMS,
11+
add_witness_commitment,
12+
create_block,
13+
)
14+
from test_framework.messages import (
15+
COIN,
16+
COutPoint,
17+
CTransaction,
18+
CTxIn,
19+
CTxOut,
20+
tx_from_hex,
21+
)
1122
from test_framework.test_framework import BitcoinTestFramework
1223
from test_framework.util import (
1324
assert_equal,
@@ -89,7 +100,7 @@ def test_disable_flag(self):
89100
tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)]
90101
tx1.vout = [CTxOut(value, DUMMY_P2WPKH_SCRIPT)]
91102

92-
tx1_signed = self.nodes[0].signrawtransactionwithwallet(ToHex(tx1))["hex"]
103+
tx1_signed = self.nodes[0].signrawtransactionwithwallet(tx1.serialize().hex())["hex"]
93104
tx1_id = self.nodes[0].sendrawtransaction(tx1_signed)
94105
tx1_id = int(tx1_id, 16)
95106

@@ -102,13 +113,13 @@ def test_disable_flag(self):
102113
tx2.vout = [CTxOut(int(value - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
103114
tx2.rehash()
104115

105-
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
116+
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx2.serialize().hex())
106117

107118
# Setting the version back down to 1 should disable the sequence lock,
108119
# so this should be accepted.
109120
tx2.nVersion = 1
110121

111-
self.nodes[0].sendrawtransaction(ToHex(tx2))
122+
self.nodes[0].sendrawtransaction(tx2.serialize().hex())
112123

113124
# Calculate the median time past of a prior block ("confirmations" before
114125
# the current tip).
@@ -193,9 +204,9 @@ def test_sequence_lock_confirmed_inputs(self):
193204
tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value))
194205
value += utxos[j]["amount"]*COIN
195206
# Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
196-
tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50
207+
tx_size = len(tx.serialize().hex())//2 + 120*num_inputs + 50
197208
tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), DUMMY_P2WPKH_SCRIPT))
198-
rawtx = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))["hex"]
209+
rawtx = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())["hex"]
199210

200211
if (using_sequence_locks and not should_pass):
201212
# This transaction should be rejected
@@ -215,7 +226,7 @@ def test_sequence_lock_unconfirmed_inputs(self):
215226

216227
# Create a mempool tx.
217228
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
218-
tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
229+
tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid))
219230
tx1.rehash()
220231

221232
# Anyone-can-spend mempool tx.
@@ -224,8 +235,8 @@ def test_sequence_lock_unconfirmed_inputs(self):
224235
tx2.nVersion = 2
225236
tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
226237
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
227-
tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
228-
tx2 = FromHex(tx2, tx2_raw)
238+
tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"]
239+
tx2 = tx_from_hex(tx2_raw)
229240
tx2.rehash()
230241

231242
self.nodes[0].sendrawtransaction(tx2_raw)
@@ -246,10 +257,10 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
246257

247258
if (orig_tx.hash in node.getrawmempool()):
248259
# sendrawtransaction should fail if the tx is in the mempool
249-
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))
260+
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, tx.serialize().hex())
250261
else:
251262
# sendrawtransaction should succeed if the tx is not in the mempool
252-
node.sendrawtransaction(ToHex(tx))
263+
node.sendrawtransaction(tx.serialize().hex())
253264

254265
return tx
255266

@@ -299,7 +310,7 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
299310
utxos = self.nodes[0].listunspent()
300311
tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1))
301312
tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
302-
raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"]
313+
raw_tx5 = self.nodes[0].signrawtransactionwithwallet(tx5.serialize().hex())["hex"]
303314

304315
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)
305316

@@ -325,7 +336,7 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
325336
block.rehash()
326337
block.solve()
327338
tip = block.sha256
328-
assert_equal(None if i == 1 else 'inconclusive', self.nodes[0].submitblock(ToHex(block)))
339+
assert_equal(None if i == 1 else 'inconclusive', self.nodes[0].submitblock(block.serialize().hex()))
329340
tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
330341
tmpl['previousblockhash'] = '%x' % tip
331342
tmpl['transactions'] = []
@@ -348,7 +359,7 @@ def test_bip68_not_consensus(self):
348359
assert not softfork_active(self.nodes[0], 'csv')
349360
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
350361

351-
tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
362+
tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid))
352363
tx1.rehash()
353364

354365
# Make an anyone-can-spend transaction
@@ -358,11 +369,11 @@ def test_bip68_not_consensus(self):
358369
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
359370

360371
# sign tx2
361-
tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
362-
tx2 = FromHex(tx2, tx2_raw)
372+
tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"]
373+
tx2 = tx_from_hex(tx2_raw)
363374
tx2.rehash()
364375

365-
self.nodes[0].sendrawtransaction(ToHex(tx2))
376+
self.nodes[0].sendrawtransaction(tx2.serialize().hex())
366377

367378
# Now make an invalid spend of tx2 according to BIP68
368379
sequence_value = 100 # 100 block relative locktime
@@ -373,7 +384,7 @@ def test_bip68_not_consensus(self):
373384
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
374385
tx3.rehash()
375386

376-
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
387+
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex())
377388

378389
# make a block that violates bip68; ensure that the tip updates
379390
block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
@@ -404,9 +415,9 @@ def test_version2_relay(self):
404415
outputs = { self.nodes[1].getnewaddress() : 1.0 }
405416
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
406417
rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex']
407-
tx = FromHex(CTransaction(), rawtxfund)
418+
tx = tx_from_hex(rawtxfund)
408419
tx.nVersion = 2
409-
tx_signed = self.nodes[1].signrawtransactionwithwallet(ToHex(tx))["hex"]
420+
tx_signed = self.nodes[1].signrawtransactionwithwallet(tx.serialize().hex())["hex"]
410421
self.nodes[1].sendrawtransaction(tx_signed)
411422

412423
if __name__ == '__main__':

test/functional/feature_coinstatsindex.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
CTransaction,
2323
CTxIn,
2424
CTxOut,
25-
ToHex,
2625
)
2726
from test_framework.script import (
2827
CScript,
@@ -170,7 +169,7 @@ def _test_coin_stats_index(self):
170169
tx2 = CTransaction()
171170
tx2.vin.append(CTxIn(COutPoint(int(tx1_txid, 16), n), b''))
172171
tx2.vout.append(CTxOut(int(20.99 * COIN), CScript([OP_RETURN] + [OP_FALSE]*30)))
173-
tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))['hex']
172+
tx2_hex = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())['hex']
174173
self.nodes[0].sendrawtransaction(tx2_hex)
175174

176175
# Include both txs in a block
@@ -207,7 +206,7 @@ def _test_coin_stats_index(self):
207206
block_time = self.nodes[0].getblock(tip)['time'] + 1
208207
block = create_block(int(tip, 16), cb, block_time)
209208
block.solve()
210-
self.nodes[0].submitblock(ToHex(block))
209+
self.nodes[0].submitblock(block.serialize().hex())
211210
self.sync_all()
212211

213212
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, 'muhash'))

test/functional/feature_dbcrash.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
CTransaction,
3737
CTxIn,
3838
CTxOut,
39-
ToHex,
4039
)
4140
from test_framework.test_framework import BitcoinTestFramework
4241
from test_framework.util import (
@@ -208,7 +207,7 @@ def generate_small_transactions(self, node, count, utxo_list):
208207
tx.vout.append(CTxOut(output_amount, hex_str_to_bytes(utxo['scriptPubKey'])))
209208

210209
# Sign and send the transaction to get into the mempool
211-
tx_signed_hex = node.signrawtransactionwithwallet(ToHex(tx))['hex']
210+
tx_signed_hex = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
212211
node.sendrawtransaction(tx_signed_hex)
213212
num_transactions += 1
214213

test/functional/feature_fee_estimation.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,23 @@
66
from decimal import Decimal
77
import random
88

9-
from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN
10-
from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE
9+
from test_framework.messages import (
10+
COIN,
11+
COutPoint,
12+
CTransaction,
13+
CTxIn,
14+
CTxOut,
15+
)
16+
from test_framework.script import (
17+
CScript,
18+
OP_1,
19+
OP_2,
20+
OP_DROP,
21+
OP_EQUAL,
22+
OP_HASH160,
23+
OP_TRUE,
24+
hash160,
25+
)
1126
from test_framework.test_framework import BitcoinTestFramework
1227
from test_framework.util import (
1328
assert_equal,
@@ -64,11 +79,11 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
6479
# the ScriptSig that will satisfy the ScriptPubKey.
6580
for inp in tx.vin:
6681
inp.scriptSig = SCRIPT_SIG[inp.prevout.n]
67-
txid = from_node.sendrawtransaction(hexstring=ToHex(tx), maxfeerate=0)
82+
txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
6883
unconflist.append({"txid": txid, "vout": 0, "amount": total_in - amount - fee})
6984
unconflist.append({"txid": txid, "vout": 1, "amount": amount})
7085

71-
return (ToHex(tx), fee)
86+
return (tx.serialize().hex(), fee)
7287

7388

7489
def split_inputs(from_node, txins, txouts, initial_split=False):
@@ -91,10 +106,10 @@ def split_inputs(from_node, txins, txouts, initial_split=False):
91106
# If this is the initial split we actually need to sign the transaction
92107
# Otherwise we just need to insert the proper ScriptSig
93108
if (initial_split):
94-
completetx = from_node.signrawtransactionwithwallet(ToHex(tx))["hex"]
109+
completetx = from_node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
95110
else:
96111
tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]]
97-
completetx = ToHex(tx)
112+
completetx = tx.serialize().hex()
98113
txid = from_node.sendrawtransaction(hexstring=completetx, maxfeerate=0)
99114
txouts.append({"txid": txid, "vout": 0, "amount": half_change})
100115
txouts.append({"txid": txid, "vout": 1, "amount": rem_change})

test/functional/feature_pruning.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
import os
1212

1313
from test_framework.blocktools import create_coinbase
14-
from test_framework.messages import CBlock, ToHex
15-
from test_framework.script import CScript, OP_RETURN, OP_NOP
14+
from test_framework.messages import CBlock
15+
from test_framework.script import (
16+
CScript,
17+
OP_NOP,
18+
OP_RETURN,
19+
)
1620
from test_framework.test_framework import BitcoinTestFramework
1721
from test_framework.util import (
1822
assert_equal,
@@ -62,7 +66,7 @@ def mine_large_blocks(node, n):
6266
block.solve()
6367

6468
# Submit to the node
65-
node.submitblock(ToHex(block))
69+
node.submitblock(block.serialize().hex())
6670

6771
previousblockhash = block.sha256
6872
height += 1

0 commit comments

Comments
 (0)