Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/wallet.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2020 The Bitcoin Core developers | # Copyright (c) 2020 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""A limited-functionality wallet, which may replace a real wallet in tests""" | """A limited-functionality wallet, which may replace a real wallet in tests""" | ||||
from copy import deepcopy | |||||
from decimal import Decimal | from decimal import Decimal | ||||
from typing import Optional | from typing import Optional | ||||
from test_framework.address import ( | from test_framework.address import ( | ||||
ADDRESS_ECREG_P2SH_OP_TRUE, | ADDRESS_ECREG_P2SH_OP_TRUE, | ||||
SCRIPTSIG_OP_TRUE, | SCRIPTSIG_OP_TRUE, | ||||
) | ) | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
XEC, | XEC, | ||||
COutPoint, | COutPoint, | ||||
CTransaction, | CTransaction, | ||||
CTxIn, | CTxIn, | ||||
CTxOut, | CTxOut, | ||||
FromHex, | FromHex, | ||||
ToHex, | |||||
) | ) | ||||
from test_framework.txtools import pad_tx | from test_framework.txtools import pad_tx | ||||
from test_framework.util import assert_equal, satoshi_round | from test_framework.util import ( | ||||
assert_equal, | |||||
assert_greater_than_or_equal, | |||||
satoshi_round, | |||||
) | |||||
DEFAULT_FEE = Decimal("100.00") | |||||
class MiniWallet: | class MiniWallet: | ||||
def __init__(self, test_node): | def __init__(self, test_node): | ||||
self._test_node = test_node | self._test_node = test_node | ||||
self._utxos = [] | self._utxos = [] | ||||
self._address = ADDRESS_ECREG_P2SH_OP_TRUE | self._address = ADDRESS_ECREG_P2SH_OP_TRUE | ||||
self._scriptPubKey = bytes.fromhex( | self._scriptPubKey = bytes.fromhex( | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | def send_self_transfer(self, *, fee_rate=Decimal("3000.00"), from_node, | ||||
{'txid': tx_info['txid'], 'vout': 0, 'value': send_value}) | {'txid': tx_info['txid'], 'vout': 0, 'value': send_value}) | ||||
from_node.sendrawtransaction(tx_hex) | from_node.sendrawtransaction(tx_hex) | ||||
assert_equal(tx_info['size'], size) | assert_equal(tx_info['size'], size) | ||||
assert_equal(tx_info['fees']['base'], fee) | assert_equal(tx_info['fees']['base'], fee) | ||||
return {'txid': tx_info['txid'], 'hex': tx_hex} | return {'txid': tx_info['txid'], 'hex': tx_hex} | ||||
def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, | def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, | ||||
parent_locking_script=None): | parent_locking_script=None, fee=DEFAULT_FEE): | ||||
"""Build a transaction that spends parent_txid.vout[n] and produces one | """Build a transaction that spends parent_txid.vout[n] and produces one | ||||
output with amount = parent_value with a fee deducted. | output with amount = parent_value with a fee deducted. | ||||
Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the | Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the | ||||
output created). | output created). | ||||
""" | """ | ||||
inputs = [{"txid": parent_txid, "vout": n}] | inputs = [{"txid": parent_txid, "vout": n}] | ||||
my_value = parent_value - Decimal("100.00") | my_value = parent_value - fee | ||||
outputs = {address: my_value} | outputs = {address: my_value} | ||||
rawtx = node.createrawtransaction(inputs, outputs) | rawtx = node.createrawtransaction(inputs, outputs) | ||||
prevtxs = [{ | prevtxs = [{ | ||||
"txid": parent_txid, | "txid": parent_txid, | ||||
"vout": n, | "vout": n, | ||||
"scriptPubKey": parent_locking_script, | "scriptPubKey": parent_locking_script, | ||||
"amount": parent_value, | "amount": parent_value, | ||||
}] if parent_locking_script else None | }] if parent_locking_script else None | ||||
signedtx = node.signrawtransactionwithkey( | signedtx = node.signrawtransactionwithkey( | ||||
hexstring=rawtx, privkeys=privkeys, prevtxs=prevtxs) | hexstring=rawtx, privkeys=privkeys, prevtxs=prevtxs) | ||||
assert signedtx["complete"] | assert signedtx["complete"] | ||||
tx = FromHex(CTransaction(), signedtx["hex"]) | tx = FromHex(CTransaction(), signedtx["hex"]) | ||||
return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex()) | return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex()) | ||||
def create_child_with_parents(node, address, privkeys, parents_tx, values, | def create_child_with_parents(node, address, privkeys, parents_tx, values, | ||||
locking_scripts): | locking_scripts, fee=DEFAULT_FEE): | ||||
"""Creates a transaction that spends the first output of each parent in parents_tx.""" | """Creates a transaction that spends the first output of each parent in parents_tx.""" | ||||
num_parents = len(parents_tx) | num_parents = len(parents_tx) | ||||
total_value = sum(values) | total_value = sum(values) | ||||
inputs = [{"txid": tx.get_id(), "vout": 0} for tx in parents_tx] | inputs = [{"txid": tx.get_id(), "vout": 0} for tx in parents_tx] | ||||
outputs = {address: total_value - num_parents * Decimal("100.00")} | outputs = {address: total_value - fee} | ||||
rawtx_child = node.createrawtransaction(inputs, outputs) | rawtx_child = node.createrawtransaction(inputs, outputs) | ||||
prevtxs = [] | prevtxs = [] | ||||
for i in range(num_parents): | for i in range(num_parents): | ||||
prevtxs.append( | prevtxs.append( | ||||
{"txid": parents_tx[i].get_id(), "vout": 0, | {"txid": parents_tx[i].get_id(), "vout": 0, | ||||
"scriptPubKey": locking_scripts[i], "amount": values[i]}) | "scriptPubKey": locking_scripts[i], "amount": values[i]}) | ||||
signedtx_child = node.signrawtransactionwithkey( | signedtx_child = node.signrawtransactionwithkey( | ||||
hexstring=rawtx_child, privkeys=privkeys, prevtxs=prevtxs) | hexstring=rawtx_child, privkeys=privkeys, prevtxs=prevtxs) | ||||
Show All 15 Lines | def create_raw_chain(node, first_coin, address, privkeys, chain_length=50): | ||||
for _ in range(chain_length): | for _ in range(chain_length): | ||||
(tx, txhex, value, parent_locking_script) = make_chain( | (tx, txhex, value, parent_locking_script) = make_chain( | ||||
node, address, privkeys, txid, value, 0, parent_locking_script) | node, address, privkeys, txid, value, 0, parent_locking_script) | ||||
txid = tx.get_id() | txid = tx.get_id() | ||||
chain_hex.append(txhex) | chain_hex.append(txhex) | ||||
chain_txns.append(tx) | chain_txns.append(tx) | ||||
return (chain_hex, chain_txns) | return (chain_hex, chain_txns) | ||||
def bulk_transaction( | |||||
tx: CTransaction, node, target_size: int, privkeys=None, prevtxs=None | |||||
) -> CTransaction: | |||||
"""Return a padded and signed transaction. The original transaction is left | |||||
unaltered. | |||||
If privkeys is not specified, it is assumed that the transaction has an | |||||
anyone-can-spend output as unique output. | |||||
""" | |||||
tx_heavy = deepcopy(tx) | |||||
pad_tx(tx_heavy, target_size) | |||||
assert_greater_than_or_equal(tx_heavy.billable_size(), target_size) | |||||
if privkeys is not None: | |||||
signed_tx = node.signrawtransactionwithkey( | |||||
ToHex(tx_heavy), privkeys, prevtxs) | |||||
return FromHex(CTransaction(), signed_tx["hex"]) | |||||
# OP_TRUE | |||||
tx_heavy.vin[0].scriptSig = SCRIPTSIG_OP_TRUE | |||||
return tx_heavy |