mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-10 10:52:31 -05:00
Merge bitcoin/bitcoin#26414: test: Move tx creation to create_self_transfer_multi
0b78110f73
test: Move tx creation to create_self_transfer_multi (kouloumos) Pull request description: Two birds with one stone: replacement of https://github.com/bitcoin/bitcoin/pull/26278 with simplification of the MiniWallet's transaction creation logic. Currently the MiniWallet creates simple txns (1 input, 1 output) with `create_self_transfer`. https://github.com/bitcoin/bitcoin/pull/24637 introduced `create_self_transfer_multi` **which uses** `create_self_transfer` to create a "transaction template" which then adjusts (copy and mutate inputs and outputs) in order to create more complex multi-input multi-output transactions. This can more easily lead to issues such as https://github.com/bitcoin/bitcoin/pull/26278 and is more of a maintenance burden. This PR simplifies the logic by going the other way around. Now `create_self_transfer` **uses** `create_self_transfer_multi`. The transaction creation logic has been moved to `create_self_transfer_multi` which is being called by `create_self_transfer` to construct the simple case of 1 input 1 output transaction. ACKs for top commit: MarcoFalke: ACK0b78110f73
👒 Tree-SHA512: 147e577ed5444bee57865bd375b37c9b49d6539e9875c30c2667e70fcba27fe80bcb4552a4e6efb42760d34b40d5dad826883b778eaeefe29425ec081787b4bd
This commit is contained in:
commit
38cbf43dee
1 changed files with 27 additions and 40 deletions
|
@ -244,6 +244,7 @@ class MiniWallet:
|
||||||
utxos_to_spend: Optional[List[dict]] = None,
|
utxos_to_spend: Optional[List[dict]] = None,
|
||||||
num_outputs=1,
|
num_outputs=1,
|
||||||
amount_per_output=0,
|
amount_per_output=0,
|
||||||
|
locktime=0,
|
||||||
sequence=0,
|
sequence=0,
|
||||||
fee_per_output=1000,
|
fee_per_output=1000,
|
||||||
target_weight=0
|
target_weight=0
|
||||||
|
@ -256,27 +257,29 @@ class MiniWallet:
|
||||||
utxos_to_spend = utxos_to_spend or [self.get_utxo()]
|
utxos_to_spend = utxos_to_spend or [self.get_utxo()]
|
||||||
sequence = [sequence] * len(utxos_to_spend) if type(sequence) is int else sequence
|
sequence = [sequence] * len(utxos_to_spend) if type(sequence) is int else sequence
|
||||||
assert_equal(len(utxos_to_spend), len(sequence))
|
assert_equal(len(utxos_to_spend), len(sequence))
|
||||||
# create simple tx template (1 input, 1 output)
|
|
||||||
tx = self.create_self_transfer(
|
|
||||||
fee_rate=0,
|
|
||||||
utxo_to_spend=utxos_to_spend[0])["tx"]
|
|
||||||
|
|
||||||
# duplicate inputs, witnesses and outputs
|
# calculate output amount
|
||||||
tx.vin = [deepcopy(tx.vin[0]) for _ in range(len(utxos_to_spend))]
|
|
||||||
for txin, seq in zip(tx.vin, sequence):
|
|
||||||
txin.nSequence = seq
|
|
||||||
tx.wit.vtxinwit = [deepcopy(tx.wit.vtxinwit[0]) for _ in range(len(utxos_to_spend))]
|
|
||||||
tx.vout = [deepcopy(tx.vout[0]) for _ in range(num_outputs)]
|
|
||||||
|
|
||||||
# adapt input prevouts
|
|
||||||
for i, utxo in enumerate(utxos_to_spend):
|
|
||||||
tx.vin[i] = CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout']))
|
|
||||||
|
|
||||||
# adapt output amounts (use fixed fee per output)
|
|
||||||
inputs_value_total = sum([int(COIN * utxo['value']) for utxo in utxos_to_spend])
|
inputs_value_total = sum([int(COIN * utxo['value']) for utxo in utxos_to_spend])
|
||||||
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
|
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
|
||||||
for o in tx.vout:
|
amount_per_output = amount_per_output or (outputs_value_total // num_outputs)
|
||||||
o.nValue = amount_per_output or (outputs_value_total // num_outputs)
|
|
||||||
|
# create tx
|
||||||
|
tx = CTransaction()
|
||||||
|
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=seq) for utxo_to_spend,seq in zip(utxos_to_spend, sequence)]
|
||||||
|
tx.vout = [CTxOut(amount_per_output, bytearray(self._scriptPubKey)) for _ in range(num_outputs)]
|
||||||
|
tx.nLockTime = locktime
|
||||||
|
|
||||||
|
if self._mode == MiniWalletMode.RAW_P2PK:
|
||||||
|
self.sign_tx(tx)
|
||||||
|
elif self._mode == MiniWalletMode.RAW_OP_TRUE:
|
||||||
|
for i in range(len(utxos_to_spend)):
|
||||||
|
tx.vin[i].scriptSig = CScript([OP_NOP] * 43) # pad to identical size
|
||||||
|
elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE:
|
||||||
|
tx.wit.vtxinwit = [CTxInWitness()] * len(utxos_to_spend)
|
||||||
|
for i in range(len(utxos_to_spend)):
|
||||||
|
tx.wit.vtxinwit[i].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
if target_weight:
|
if target_weight:
|
||||||
self._bulk_tx(tx, target_weight)
|
self._bulk_tx(tx, target_weight)
|
||||||
|
@ -299,6 +302,7 @@ class MiniWallet:
|
||||||
utxo_to_spend = utxo_to_spend or self.get_utxo()
|
utxo_to_spend = utxo_to_spend or self.get_utxo()
|
||||||
assert fee_rate >= 0
|
assert fee_rate >= 0
|
||||||
assert fee >= 0
|
assert fee >= 0
|
||||||
|
# calculate fee
|
||||||
if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE):
|
if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE):
|
||||||
vsize = Decimal(104) # anyone-can-spend
|
vsize = Decimal(104) # anyone-can-spend
|
||||||
elif self._mode == MiniWalletMode.RAW_P2PK:
|
elif self._mode == MiniWalletMode.RAW_P2PK:
|
||||||
|
@ -308,29 +312,12 @@ class MiniWallet:
|
||||||
send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
|
send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
|
||||||
assert send_value > 0
|
assert send_value > 0
|
||||||
|
|
||||||
tx = CTransaction()
|
# create tx
|
||||||
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)]
|
tx = self.create_self_transfer_multi(utxos_to_spend=[utxo_to_spend], locktime=locktime, sequence=sequence, amount_per_output=int(COIN * send_value), target_weight=target_weight)
|
||||||
tx.vout = [CTxOut(int(COIN * send_value), bytearray(self._scriptPubKey))]
|
if not target_weight:
|
||||||
tx.nLockTime = locktime
|
assert_equal(tx["tx"].get_vsize(), vsize)
|
||||||
if self._mode == MiniWalletMode.RAW_P2PK:
|
|
||||||
self.sign_tx(tx)
|
|
||||||
elif self._mode == MiniWalletMode.RAW_OP_TRUE:
|
|
||||||
tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size
|
|
||||||
elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE:
|
|
||||||
tx.wit.vtxinwit = [CTxInWitness()]
|
|
||||||
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
assert_equal(tx.get_vsize(), vsize)
|
return {"txid": tx["txid"], "wtxid": tx["tx"].getwtxid(), "hex": tx["hex"], "tx": tx["tx"], "new_utxo": tx["new_utxos"][0]}
|
||||||
|
|
||||||
if target_weight:
|
|
||||||
self._bulk_tx(tx, target_weight)
|
|
||||||
|
|
||||||
tx_hex = tx.serialize().hex()
|
|
||||||
new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0)
|
|
||||||
|
|
||||||
return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo}
|
|
||||||
|
|
||||||
def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs):
|
def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs):
|
||||||
txid = from_node.sendrawtransaction(hexstring=tx_hex, maxfeerate=maxfeerate, **kwargs)
|
txid = from_node.sendrawtransaction(hexstring=tx_hex, maxfeerate=maxfeerate, **kwargs)
|
||||||
|
|
Loading…
Add table
Reference in a new issue