diff options
Diffstat (limited to 'test/functional/test_framework/wallet.py')
-rw-r--r-- | test/functional/test_framework/wallet.py | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py new file mode 100644 index 0000000000..39b3bf2a5b --- /dev/null +++ b/test/functional/test_framework/wallet.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""A limited-functionality wallet, which may replace a real wallet in tests""" + +from decimal import Decimal +from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE +from test_framework.messages import ( + COIN, + COutPoint, + CTransaction, + CTxIn, + CTxInWitness, + CTxOut, +) +from test_framework.script import ( + CScript, + OP_TRUE, +) +from test_framework.util import ( + assert_equal, + hex_str_to_bytes, + satoshi_round, +) + + +class MiniWallet: + def __init__(self, test_node): + self._test_node = test_node + self._utxos = [] + self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE + self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey']) + + def generate(self, num_blocks): + """Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list""" + blocks = self._test_node.generatetoaddress(num_blocks, self._address) + for b in blocks: + cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0] + self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']}) + return blocks + + def get_utxo(self): + """Return the last utxo. Can be used to get the change output immediately after a send_self_transfer""" + return self._utxos.pop() + + def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None): + """Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" + self._utxos = sorted(self._utxos, key=lambda k: k['value']) + utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee + vsize = Decimal(96) + send_value = satoshi_round(utxo_to_spend['value'] - fee_rate * (vsize / 1000)) + fee = utxo_to_spend['value'] - send_value + assert send_value > 0 + + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))] + tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)] + tx.wit.vtxinwit = [CTxInWitness()] + tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx_hex = tx.serialize().hex() + + txid = from_node.sendrawtransaction(tx_hex) + self._utxos.append({'txid': txid, 'vout': 0, 'value': send_value}) + tx_info = from_node.getmempoolentry(txid) + assert_equal(tx_info['vsize'], vsize) + assert_equal(tx_info['fee'], fee) + return {'txid': txid, 'wtxid': tx_info['wtxid'], 'hex': tx_hex} |