mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
6bee150e8e
Additionally, accept a "now" timestamp, to allow avoiding rescans for keys which are known never to have been used. Note that the behavior when "now" is specified is slightly different than the previous behavior when no timestamp was specified at all. Previously, when no timestamp was specified, it would avoid rescanning during the importmulti call, but set the key's nCreateTime value to 1, which would not prevent future block reads in later ScanForWalletTransactions calls. With this change, passing a "now" timestamp will set the key's nCreateTime to the current block time instead of 1. Fixes #9491
157 lines
6.9 KiB
Python
Executable File
157 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal)
|
|
from decimal import Decimal
|
|
|
|
import collections
|
|
import enum
|
|
import itertools
|
|
import functools
|
|
|
|
Call = enum.Enum("Call", "single multi")
|
|
Data = enum.Enum("Data", "address pub priv")
|
|
ImportNode = collections.namedtuple("ImportNode", "rescan")
|
|
|
|
|
|
def call_import_rpc(call, data, address, scriptPubKey, pubkey, key, label, node, rescan):
|
|
"""Helper that calls a wallet import RPC on a bitcoin node."""
|
|
watchonly = data != Data.priv
|
|
if call == Call.single:
|
|
if data == Data.address:
|
|
response = node.importaddress(address, label, rescan)
|
|
elif data == Data.pub:
|
|
response = node.importpubkey(pubkey, label, rescan)
|
|
elif data == Data.priv:
|
|
response = node.importprivkey(key, label, rescan)
|
|
assert_equal(response, None)
|
|
elif call == Call.multi:
|
|
response = node.importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address
|
|
},
|
|
"timestamp": "now",
|
|
"pubkeys": [pubkey] if data == Data.pub else [],
|
|
"keys": [key] if data == Data.priv else [],
|
|
"label": label,
|
|
"watchonly": watchonly
|
|
}], {"rescan": rescan})
|
|
assert_equal(response, [{"success": True}])
|
|
return watchonly
|
|
|
|
|
|
# List of RPCs that import a wallet key or address in various ways.
|
|
IMPORT_RPCS = [functools.partial(call_import_rpc, call, data) for call, data in itertools.product(Call, Data)]
|
|
|
|
# List of bitcoind nodes that will import keys.
|
|
IMPORT_NODES = [
|
|
ImportNode(rescan=True),
|
|
ImportNode(rescan=False),
|
|
]
|
|
|
|
|
|
class ImportRescanTest(BitcoinTestFramework):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.num_nodes = 1 + len(IMPORT_NODES)
|
|
|
|
def setup_network(self):
|
|
extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
|
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
|
|
for i in range(1, self.num_nodes):
|
|
connect_nodes(self.nodes[i], 0)
|
|
|
|
def run_test(self):
|
|
# Create one transaction on node 0 with a unique amount and label for
|
|
# each possible type of wallet import RPC.
|
|
import_rpc_variants = []
|
|
for i, import_rpc in enumerate(IMPORT_RPCS):
|
|
label = "label{}".format(i)
|
|
addr = self.nodes[0].validateaddress(self.nodes[0].getnewaddress(label))
|
|
key = self.nodes[0].dumpprivkey(addr["address"])
|
|
amount = 24.9375 - i * .0625
|
|
txid = self.nodes[0].sendtoaddress(addr["address"], amount)
|
|
import_rpc = functools.partial(import_rpc, addr["address"], addr["scriptPubKey"], addr["pubkey"], key,
|
|
label)
|
|
import_rpc_variants.append((import_rpc, label, amount, txid, addr))
|
|
|
|
self.nodes[0].generate(1)
|
|
assert_equal(self.nodes[0].getrawmempool(), [])
|
|
sync_blocks(self.nodes)
|
|
|
|
# For each importing node and variation of wallet import RPC, invoke
|
|
# the RPC and check the results from getbalance and listtransactions.
|
|
for node, import_node in zip(self.nodes[1:], IMPORT_NODES):
|
|
for import_rpc, label, amount, txid, addr in import_rpc_variants:
|
|
watchonly = import_rpc(node, import_node.rescan)
|
|
|
|
balance = node.getbalance(label, 0, False, True)
|
|
if import_node.rescan:
|
|
assert_equal(balance, amount)
|
|
else:
|
|
assert_equal(balance, 0)
|
|
|
|
txs = node.listtransactions(label, 10000, 0, True)
|
|
if import_node.rescan:
|
|
assert_equal(len(txs), 1)
|
|
assert_equal(txs[0]["account"], label)
|
|
assert_equal(txs[0]["address"], addr["address"])
|
|
assert_equal(txs[0]["amount"], amount)
|
|
assert_equal(txs[0]["category"], "receive")
|
|
assert_equal(txs[0]["label"], label)
|
|
assert_equal(txs[0]["txid"], txid)
|
|
assert_equal(txs[0]["confirmations"], 1)
|
|
assert_equal("trusted" not in txs[0], True)
|
|
if watchonly:
|
|
assert_equal(txs[0]["involvesWatchonly"], True)
|
|
else:
|
|
assert_equal("involvesWatchonly" not in txs[0], True)
|
|
else:
|
|
assert_equal(len(txs), 0)
|
|
|
|
# Create spends for all the imported addresses.
|
|
spend_txids = []
|
|
fee = self.nodes[0].getnetworkinfo()["relayfee"]
|
|
for import_rpc, label, amount, txid, addr in import_rpc_variants:
|
|
raw_tx = self.nodes[0].getrawtransaction(txid)
|
|
decoded_tx = self.nodes[0].decoderawtransaction(raw_tx)
|
|
input_vout = next(out["n"] for out in decoded_tx["vout"]
|
|
if out["scriptPubKey"]["addresses"] == [addr["address"]])
|
|
inputs = [{"txid": txid, "vout": input_vout}]
|
|
outputs = {self.nodes[0].getnewaddress(): Decimal(amount) - fee}
|
|
raw_spend_tx = self.nodes[0].createrawtransaction(inputs, outputs)
|
|
signed_spend_tx = self.nodes[0].signrawtransaction(raw_spend_tx)
|
|
spend_txid = self.nodes[0].sendrawtransaction(signed_spend_tx["hex"])
|
|
spend_txids.append(spend_txid)
|
|
|
|
self.nodes[0].generate(1)
|
|
assert_equal(self.nodes[0].getrawmempool(), [])
|
|
sync_blocks(self.nodes)
|
|
|
|
# Check the results from getbalance and listtransactions after the spends.
|
|
for node, import_node in zip(self.nodes[1:], IMPORT_NODES):
|
|
txs = node.listtransactions("*", 10000, 0, True)
|
|
for (import_rpc, label, amount, txid, addr), spend_txid in zip(import_rpc_variants, spend_txids):
|
|
balance = node.getbalance(label, 0, False, True)
|
|
spend_tx = [tx for tx in txs if tx["txid"] == spend_txid]
|
|
if import_node.rescan:
|
|
assert_equal(balance, amount)
|
|
assert_equal(len(spend_tx), 1)
|
|
assert_equal(spend_tx[0]["account"], "")
|
|
assert_equal(spend_tx[0]["amount"] + spend_tx[0]["fee"], -amount)
|
|
assert_equal(spend_tx[0]["category"], "send")
|
|
assert_equal("label" not in spend_tx[0], True)
|
|
assert_equal(spend_tx[0]["confirmations"], 1)
|
|
assert_equal("trusted" not in spend_tx[0], True)
|
|
assert_equal("involvesWatchonly" not in txs[0], True)
|
|
else:
|
|
assert_equal(balance, 0)
|
|
assert_equal(spend_tx, [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
ImportRescanTest().main()
|