aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py51
-rwxr-xr-xtest/functional/p2p_blockfilters.py52
-rwxr-xr-xtest/functional/test_framework/messages.py53
-rwxr-xr-xtest/functional/test_framework/mininode.py3
4 files changed, 142 insertions, 17 deletions
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index 1c94305220..7530e7daf6 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -67,6 +67,7 @@ class TestBitcoinCli(BitcoinTestFramework):
if self.is_wallet_compiled():
self.log.info("Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info")
assert_equal(cli_get_info['balance'], BALANCE)
+ assert 'balances' not in cli_get_info.keys()
wallet_info = self.nodes[0].getwalletinfo()
assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
assert_equal(cli_get_info['unlocked_until'], wallet_info['unlocked_until'])
@@ -76,42 +77,60 @@ class TestBitcoinCli(BitcoinTestFramework):
# Setup to test -getinfo and -rpcwallet= with multiple wallets.
wallets = ['', 'Encrypted', 'secret']
- amounts = [Decimal('59.999928'), Decimal(9), Decimal(31)]
+ amounts = [BALANCE + Decimal('9.999928'), Decimal(9), Decimal(31)]
self.nodes[0].createwallet(wallet_name=wallets[1])
self.nodes[0].createwallet(wallet_name=wallets[2])
w1 = self.nodes[0].get_wallet_rpc(wallets[0])
w2 = self.nodes[0].get_wallet_rpc(wallets[1])
w3 = self.nodes[0].get_wallet_rpc(wallets[2])
w1.walletpassphrase(password, self.rpc_timeout)
+ w2.encryptwallet(password)
w1.sendtoaddress(w2.getnewaddress(), amounts[1])
w1.sendtoaddress(w3.getnewaddress(), amounts[2])
# Mine a block to confirm; adds a block reward (50 BTC) to the default wallet.
self.nodes[0].generate(1)
- self.log.info("Test -getinfo with multiple wallets loaded returns no balance")
- assert_equal(set(self.nodes[0].listwallets()), set(wallets))
- assert 'balance' not in self.nodes[0].cli('-getinfo').send_cli().keys()
-
self.log.info("Test -getinfo with multiple wallets and -rpcwallet returns specified wallet balance")
for i in range(len(wallets)):
- cli_get_info = self.nodes[0].cli('-getinfo').send_cli('-rpcwallet={}'.format(wallets[i]))
+ cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[i])).send_cli()
+ assert 'balances' not in cli_get_info.keys()
assert_equal(cli_get_info['balance'], amounts[i])
- self.log.info("Test -getinfo with multiple wallets and -rpcwallet=non-existing-wallet returns no balance")
- assert 'balance' not in self.nodes[0].cli('-getinfo').send_cli('-rpcwallet=does-not-exist').keys()
+ self.log.info("Test -getinfo with multiple wallets and -rpcwallet=non-existing-wallet returns no balances")
+ cli_get_info_keys = self.nodes[0].cli('-getinfo', '-rpcwallet=does-not-exist').send_cli().keys()
+ assert 'balance' not in cli_get_info_keys
+ assert 'balances' not in cli_get_info_keys
- self.log.info("Test -getinfo after unloading all wallets except a non-default one returns its balance")
+ self.log.info("Test -getinfo with multiple wallets returns all loaded wallet names and balances")
+ assert_equal(set(self.nodes[0].listwallets()), set(wallets))
+ cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
+ assert 'balance' not in cli_get_info.keys()
+ assert_equal(cli_get_info['balances'], {k: v for k, v in zip(wallets, amounts)})
+
+ # Unload the default wallet and re-verify.
self.nodes[0].unloadwallet(wallets[0])
+ assert wallets[0] not in self.nodes[0].listwallets()
+ cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
+ assert 'balance' not in cli_get_info.keys()
+ assert_equal(cli_get_info['balances'], {k: v for k, v in zip(wallets[1:], amounts[1:])})
+
+ self.log.info("Test -getinfo after unloading all wallets except a non-default one returns its balance")
self.nodes[0].unloadwallet(wallets[2])
assert_equal(self.nodes[0].listwallets(), [wallets[1]])
- assert_equal(self.nodes[0].cli('-getinfo').send_cli()['balance'], amounts[1])
-
- self.log.info("Test -getinfo -rpcwallet=remaining-non-default-wallet returns its balance")
- assert_equal(self.nodes[0].cli('-getinfo').send_cli('-rpcwallet={}'.format(wallets[1]))['balance'], amounts[1])
-
- self.log.info("Test -getinfo with -rpcwallet=unloaded wallet returns no balance")
- assert 'balance' not in self.nodes[0].cli('-getinfo').send_cli('-rpcwallet={}'.format(wallets[2])).keys()
+ cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
+ assert 'balances' not in cli_get_info.keys()
+ assert_equal(cli_get_info['balance'], amounts[1])
+
+ self.log.info("Test -getinfo with -rpcwallet=remaining-non-default-wallet returns only its balance")
+ cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[1])).send_cli()
+ assert 'balances' not in cli_get_info.keys()
+ assert_equal(cli_get_info['balance'], amounts[1])
+
+ self.log.info("Test -getinfo with -rpcwallet=unloaded wallet returns no balances")
+ cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[2])).send_cli()
+ assert 'balance' not in cli_get_info_keys
+ assert 'balances' not in cli_get_info_keys
else:
self.log.info("*** Wallet not compiled; cli getwalletinfo and -getinfo wallet tests skipped")
self.nodes[0].generate(1) # maintain block parity with the wallet_compiled conditional branch
diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py
index 4d00a6dc07..9ff76b4b3d 100755
--- a/test/functional/p2p_blockfilters.py
+++ b/test/functional/p2p_blockfilters.py
@@ -5,12 +5,16 @@
"""Tests NODE_COMPACT_FILTERS (BIP 157/158).
Tests that a node configured with -blockfilterindex and -peerblockfilters can serve
-cfcheckpts.
+cfheaders and cfcheckpts.
"""
from test_framework.messages import (
FILTER_TYPE_BASIC,
+ hash256,
msg_getcfcheckpt,
+ msg_getcfheaders,
+ ser_uint256,
+ uint256_from_str,
)
from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
@@ -100,12 +104,45 @@ class CompactFiltersTest(BitcoinTestFramework):
[int(header, 16) for header in (stale_cfcheckpt,)]
)
+ self.log.info("Check that peers can fetch cfheaders on active chain.")
+ request = msg_getcfheaders(
+ filter_type=FILTER_TYPE_BASIC,
+ start_height=1,
+ stop_hash=int(main_block_hash, 16)
+ )
+ node0.send_and_ping(request)
+ response = node0.last_message['cfheaders']
+ assert_equal(len(response.hashes), 1000)
+ assert_equal(
+ compute_last_header(response.prev_header, response.hashes),
+ int(main_cfcheckpt, 16)
+ )
+
+ self.log.info("Check that peers can fetch cfheaders on stale chain.")
+ request = msg_getcfheaders(
+ filter_type=FILTER_TYPE_BASIC,
+ start_height=1,
+ stop_hash=int(stale_block_hash, 16)
+ )
+ node0.send_and_ping(request)
+ response = node0.last_message['cfheaders']
+ assert_equal(len(response.hashes), 1000)
+ assert_equal(
+ compute_last_header(response.prev_header, response.hashes),
+ int(stale_cfcheckpt, 16)
+ )
+
self.log.info("Requests to node 1 without NODE_COMPACT_FILTERS results in disconnection.")
requests = [
msg_getcfcheckpt(
filter_type=FILTER_TYPE_BASIC,
stop_hash=int(main_block_hash, 16)
),
+ msg_getcfheaders(
+ filter_type=FILTER_TYPE_BASIC,
+ start_height=1000,
+ stop_hash=int(main_block_hash, 16)
+ ),
]
for request in requests:
node1 = self.nodes[1].add_p2p_connection(P2PInterface())
@@ -114,6 +151,12 @@ class CompactFiltersTest(BitcoinTestFramework):
self.log.info("Check that invalid requests result in disconnection.")
requests = [
+ # Requesting too many filter headers results in disconnection.
+ msg_getcfheaders(
+ filter_type=FILTER_TYPE_BASIC,
+ start_height=0,
+ stop_hash=int(tip_hash, 16)
+ ),
# Requesting unknown filter type results in disconnection.
msg_getcfcheckpt(
filter_type=255,
@@ -130,5 +173,12 @@ class CompactFiltersTest(BitcoinTestFramework):
node0.send_message(request)
node0.wait_for_disconnect()
+def compute_last_header(prev_header, hashes):
+ """Compute the last filter header from a starting header and a sequence of filter hashes."""
+ header = ser_uint256(prev_header)
+ for filter_hash in hashes:
+ header = hash256(ser_uint256(filter_hash) + header)
+ return uint256_from_str(header)
+
if __name__ == '__main__':
CompactFiltersTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 6c9c8a7397..d178e79541 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1516,6 +1516,59 @@ class msg_no_witness_blocktxn(msg_blocktxn):
def serialize(self):
return self.block_transactions.serialize(with_witness=False)
+class msg_getcfheaders:
+ __slots__ = ("filter_type", "start_height", "stop_hash")
+ msgtype = b"getcfheaders"
+
+ def __init__(self, filter_type, start_height, stop_hash):
+ self.filter_type = filter_type
+ self.start_height = start_height
+ self.stop_hash = stop_hash
+
+ def deserialize(self, f):
+ self.filter_type = struct.unpack("<B", f.read(1))[0]
+ self.start_height = struct.unpack("<I", f.read(4))[0]
+ self.stop_hash = deser_uint256(f)
+
+ def serialize(self):
+ r = b""
+ r += struct.pack("<B", self.filter_type)
+ r += struct.pack("<I", self.start_height)
+ r += ser_uint256(self.stop_hash)
+ return r
+
+ def __repr__(self):
+ return "msg_getcfheaders(filter_type={:#x}, start_height={}, stop_hash={:x})".format(
+ self.filter_type, self.start_height, self.stop_hash)
+
+class msg_cfheaders:
+ __slots__ = ("filter_type", "stop_hash", "prev_header", "hashes")
+ msgtype = b"cfheaders"
+
+ def __init__(self, filter_type=None, stop_hash=None, prev_header=None, hashes=None):
+ self.filter_type = filter_type
+ self.stop_hash = stop_hash
+ self.prev_header = prev_header
+ self.hashes = hashes
+
+ def deserialize(self, f):
+ self.filter_type = struct.unpack("<B", f.read(1))[0]
+ self.stop_hash = deser_uint256(f)
+ self.prev_header = deser_uint256(f)
+ self.hashes = deser_uint256_vector(f)
+
+ def serialize(self):
+ r = b""
+ r += struct.pack("<B", self.filter_type)
+ r += ser_uint256(self.stop_hash)
+ r += ser_uint256(self.prev_header)
+ r += ser_uint256_vector(self.hashes)
+ return r
+
+ def __repr__(self):
+ return "msg_cfheaders(filter_type={:#x}, stop_hash={:x})".format(
+ self.filter_type, self.stop_hash)
+
class msg_getcfcheckpt:
__slots__ = ("filter_type", "stop_hash")
msgtype = b"getcfcheckpt"
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index 9fdd3cfe82..d1e982ac3e 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -31,6 +31,7 @@ from test_framework.messages import (
msg_block,
MSG_BLOCK,
msg_blocktxn,
+ msg_cfheaders,
msg_cfcheckpt,
msg_cmpctblock,
msg_feefilter,
@@ -68,6 +69,7 @@ MESSAGEMAP = {
b"addr": msg_addr,
b"block": msg_block,
b"blocktxn": msg_blocktxn,
+ b"cfheaders": msg_cfheaders,
b"cfcheckpt": msg_cfcheckpt,
b"cmpctblock": msg_cmpctblock,
b"feefilter": msg_feefilter,
@@ -330,6 +332,7 @@ class P2PInterface(P2PConnection):
def on_addr(self, message): pass
def on_block(self, message): pass
def on_blocktxn(self, message): pass
+ def on_cfheaders(self, message): pass
def on_cfcheckpt(self, message): pass
def on_cmpctblock(self, message): pass
def on_feefilter(self, message): pass