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 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 XEC, COutPoint, CTransaction, CTxIn, CTxOut | from test_framework.messages import ( | ||||
XEC, | |||||
COutPoint, | |||||
CTransaction, | |||||
CTxIn, | |||||
CTxOut, | |||||
FromHex, | |||||
) | |||||
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, satoshi_round | ||||
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 = [] | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | def send_self_transfer(self, *, fee_rate=Decimal("3000.00"), from_node, | ||||
tx_info = from_node.testmempoolaccept([tx_hex])[0] | tx_info = from_node.testmempoolaccept([tx_hex])[0] | ||||
self._utxos.append( | self._utxos.append( | ||||
{'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, | |||||
parent_locking_script=None): | |||||
"""Build a transaction that spends parent_txid.vout[n] and produces one | |||||
output with amount = parent_value with a fee deducted. | |||||
Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the | |||||
output created). | |||||
""" | |||||
inputs = [{"txid": parent_txid, "vout": n}] | |||||
my_value = parent_value - Decimal("100.00") | |||||
outputs = {address: my_value} | |||||
rawtx = node.createrawtransaction(inputs, outputs) | |||||
prevtxs = [{ | |||||
"txid": parent_txid, | |||||
"vout": n, | |||||
"scriptPubKey": parent_locking_script, | |||||
"amount": parent_value, | |||||
}] if parent_locking_script else None | |||||
signedtx = node.signrawtransactionwithkey( | |||||
hexstring=rawtx, privkeys=privkeys, prevtxs=prevtxs) | |||||
assert signedtx["complete"] | |||||
tx = FromHex(CTransaction(), signedtx["hex"]) | |||||
return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex()) | |||||
def create_child_with_parents(node, address, privkeys, parents_tx, values, | |||||
locking_scripts): | |||||
"""Creates a transaction that spends the first output of each parent in parents_tx.""" | |||||
num_parents = len(parents_tx) | |||||
total_value = sum(values) | |||||
inputs = [{"txid": tx.get_id(), "vout": 0} for tx in parents_tx] | |||||
outputs = {address: total_value - num_parents * Decimal("100.00")} | |||||
rawtx_child = node.createrawtransaction(inputs, outputs) | |||||
prevtxs = [] | |||||
for i in range(num_parents): | |||||
prevtxs.append( | |||||
{"txid": parents_tx[i].get_id(), "vout": 0, | |||||
"scriptPubKey": locking_scripts[i], "amount": values[i]}) | |||||
signedtx_child = node.signrawtransactionwithkey( | |||||
hexstring=rawtx_child, privkeys=privkeys, prevtxs=prevtxs) | |||||
assert signedtx_child["complete"] | |||||
return signedtx_child["hex"] | |||||
def create_raw_chain(node, first_coin, address, privkeys, chain_length=50): | |||||
"""Helper function: create a "chain" of chain_length transactions. | |||||
The nth transaction in the chain is a child of the n-1th transaction and | |||||
parent of the n+1th transaction. | |||||
""" | |||||
parent_locking_script = None | |||||
txid = first_coin["txid"] | |||||
chain_hex = [] | |||||
chain_txns = [] | |||||
value = first_coin["amount"] | |||||
for _ in range(chain_length): | |||||
(tx, txhex, value, parent_locking_script) = make_chain( | |||||
node, address, privkeys, txid, value, 0, parent_locking_script) | |||||
txid = tx.get_id() | |||||
chain_hex.append(txhex) | |||||
chain_txns.append(tx) | |||||
return (chain_hex, chain_txns) |