Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_listsinceblock.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2017-2019 The Bitcoin Core developers | # Copyright (c) 2017-2019 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. | ||||
"""Test the listsincelast RPC.""" | """Test the listsinceblock RPC.""" | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import ( | from test_framework.util import ( | ||||
assert_array_result, | assert_array_result, | ||||
assert_equal, | assert_equal, | ||||
assert_raises_rpc_error, | assert_raises_rpc_error, | ||||
connect_nodes, | connect_nodes, | ||||
) | ) | ||||
Show All 16 Lines | def run_test(self): | ||||
self.test_no_blockhash() | self.test_no_blockhash() | ||||
self.test_invalid_blockhash() | self.test_invalid_blockhash() | ||||
self.test_reorg() | self.test_reorg() | ||||
self.test_double_spend() | self.test_double_spend() | ||||
self.test_double_send() | self.test_double_send() | ||||
def test_no_blockhash(self): | def test_no_blockhash(self): | ||||
self.log.info("Test no blockhash") | |||||
txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) | txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) | ||||
blockhash, = self.nodes[2].generate(1) | blockhash, = self.nodes[2].generate(1) | ||||
blockheight = self.nodes[2].getblockheader(blockhash)['height'] | blockheight = self.nodes[2].getblockheader(blockhash)['height'] | ||||
self.sync_all() | self.sync_all() | ||||
txs = self.nodes[0].listtransactions() | txs = self.nodes[0].listtransactions() | ||||
assert_array_result(txs, {"txid": txid}, { | assert_array_result(txs, {"txid": txid}, { | ||||
"category": "receive", | "category": "receive", | ||||
Show All 9 Lines | def test_no_blockhash(self): | ||||
"transactions": txs}) | "transactions": txs}) | ||||
assert_equal( | assert_equal( | ||||
self.nodes[0].listsinceblock(""), | self.nodes[0].listsinceblock(""), | ||||
{"lastblock": blockhash, | {"lastblock": blockhash, | ||||
"removed": [], | "removed": [], | ||||
"transactions": txs}) | "transactions": txs}) | ||||
def test_invalid_blockhash(self): | def test_invalid_blockhash(self): | ||||
self.log.info("Test invalid blockhash") | |||||
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, | assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, | ||||
"42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4") | "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4") | ||||
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, | assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, | ||||
"0000000000000000000000000000000000000000000000000000000000000000") | "0000000000000000000000000000000000000000000000000000000000000000") | ||||
assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock, | assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock, | ||||
"invalid-hex") | "invalid-hex") | ||||
assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock, | assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock, | ||||
"Z000000000000000000000000000000000000000000000000000000000000000") | "Z000000000000000000000000000000000000000000000000000000000000000") | ||||
Show All 21 Lines | def test_reorg(self): | ||||
this to height=5 for the tip of the chain (bb4). It would then return | this to height=5 for the tip of the chain (bb4). It would then return | ||||
results restricted to bb3-bb4. | results restricted to bb3-bb4. | ||||
Now: listsinceblock finds the fork at ab0 and returns results in the | Now: listsinceblock finds the fork at ab0 and returns results in the | ||||
range bb1-bb4. | range bb1-bb4. | ||||
This test only checks that [tx0] is present. | This test only checks that [tx0] is present. | ||||
''' | ''' | ||||
self.log.info("Test reorg") | |||||
# Split network into two | # Split network into two | ||||
self.split_network() | self.split_network() | ||||
# send to nodes[0] from nodes[2] | # send to nodes[0] from nodes[2] | ||||
senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) | senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) | ||||
# generate on both sides | # generate on both sides | ||||
lastblockhash = self.nodes[1].generate(6)[5] | lastblockhash = self.nodes[1].generate(6)[5] | ||||
self.nodes[2].generate(7) | self.nodes[2].generate(7) | ||||
self.log.info('lastblockhash={}'.format(lastblockhash)) | self.log.debug('lastblockhash={}'.format(lastblockhash)) | ||||
self.sync_all(self.nodes[:2]) | self.sync_all(self.nodes[:2]) | ||||
self.sync_all(self.nodes[2:]) | self.sync_all(self.nodes[2:]) | ||||
self.join_network() | self.join_network() | ||||
# listsinceblock(lastblockhash) should now include tx, as seen from | # listsinceblock(lastblockhash) should now include tx, as seen from | ||||
# nodes[0] | # nodes[0] | ||||
Show All 29 Lines | def test_double_spend(self): | ||||
5. User 1 asks `listsinceblock aa3` and does not see that tx1 is now | 5. User 1 asks `listsinceblock aa3` and does not see that tx1 is now | ||||
invalidated. | invalidated. | ||||
Currently the solution to this is to detect that a reorg'd block is | Currently the solution to this is to detect that a reorg'd block is | ||||
asked for in listsinceblock, and to iterate back over existing blocks up | asked for in listsinceblock, and to iterate back over existing blocks up | ||||
until the fork point, and to include all transactions that relate to the | until the fork point, and to include all transactions that relate to the | ||||
node wallet. | node wallet. | ||||
''' | ''' | ||||
self.log.info("Test double spend") | |||||
self.sync_all() | self.sync_all() | ||||
# Split network into two | # Split network into two | ||||
self.split_network() | self.split_network() | ||||
# share utxo between nodes[1] and nodes[2] | # share utxo between nodes[1] and nodes[2] | ||||
utxos = self.nodes[2].listunspent() | utxos = self.nodes[2].listunspent() | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | def test_double_send(self): | ||||
Asserted: | Asserted: | ||||
1. tx1 is listed in listsinceblock. | 1. tx1 is listed in listsinceblock. | ||||
2. It is included in 'removed' as it was removed, even though it is now | 2. It is included in 'removed' as it was removed, even though it is now | ||||
present in a different block. | present in a different block. | ||||
3. It is listed with a confirmation count of 2 (bb3, bb4), not | 3. It is listed with a confirmation count of 2 (bb3, bb4), not | ||||
3 (aa1, aa2, aa3). | 3 (aa1, aa2, aa3). | ||||
''' | ''' | ||||
self.log.info("Test double send") | |||||
self.sync_all() | self.sync_all() | ||||
# Split network into two | # Split network into two | ||||
self.split_network() | self.split_network() | ||||
# create and sign a transaction | # create and sign a transaction | ||||
utxos = self.nodes[2].listunspent() | utxos = self.nodes[2].listunspent() | ||||
▲ Show 20 Lines • Show All 61 Lines • Show Last 20 Lines |