Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/test_node.py
Show All 16 Lines | |||||
import sys | import sys | ||||
import tempfile | import tempfile | ||||
import time | import time | ||||
import urllib.parse | import urllib.parse | ||||
import collections | import collections | ||||
import shlex | import shlex | ||||
from .authproxy import JSONRPCException | from .authproxy import JSONRPCException | ||||
from .descriptors import descsum_create | |||||
from .messages import COIN, CTransaction, FromHex | from .messages import COIN, CTransaction, FromHex | ||||
from .util import ( | from .util import ( | ||||
MAX_NODES, | MAX_NODES, | ||||
append_config, | append_config, | ||||
delete_cookie_file, | delete_cookie_file, | ||||
get_rpc_proxy, | get_rpc_proxy, | ||||
p2p_port, | p2p_port, | ||||
rpc_url, | rpc_url, | ||||
▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | def __del__(self): | ||||
# Avoid using logger, as that may have already been shutdown when | # Avoid using logger, as that may have already been shutdown when | ||||
# this destructor is called. | # this destructor is called. | ||||
print(self._node_msg("Cleaning up leftover process")) | print(self._node_msg("Cleaning up leftover process")) | ||||
self.process.kill() | self.process.kill() | ||||
def __getattr__(self, name): | def __getattr__(self, name): | ||||
"""Dispatches any unrecognised messages to the RPC connection or a CLI instance.""" | """Dispatches any unrecognised messages to the RPC connection or a CLI instance.""" | ||||
if self.use_cli: | if self.use_cli: | ||||
return getattr(self.cli, name) | return getattr(RPCOverloadWrapper(self.cli, True), name) | ||||
else: | else: | ||||
assert self.rpc is not None, self._node_msg( | assert self.rpc is not None, self._node_msg( | ||||
"Error: RPC not initialized") | "Error: RPC not initialized") | ||||
assert self.rpc_connected, self._node_msg( | assert self.rpc_connected, self._node_msg( | ||||
"Error: No RPC connection") | "Error: No RPC connection") | ||||
return getattr(self.rpc, name) | return getattr(RPCOverloadWrapper(self.rpc), name) | ||||
def clear_default_args(self): | def clear_default_args(self): | ||||
self.default_args.clear() | self.default_args.clear() | ||||
def extend_default_args(self, args): | def extend_default_args(self, args): | ||||
self.default_args.extend(args) | self.default_args.extend(args) | ||||
def remove_default_args(self, args): | def remove_default_args(self, args): | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | class TestNode(): | ||||
def generate(self, nblocks, maxtries=1000000): | def generate(self, nblocks, maxtries=1000000): | ||||
self.log.debug( | self.log.debug( | ||||
"TestNode.generate() dispatches `generate` call to `generatetoaddress`") | "TestNode.generate() dispatches `generate` call to `generatetoaddress`") | ||||
return self.generatetoaddress( | return self.generatetoaddress( | ||||
nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries) | nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries) | ||||
def get_wallet_rpc(self, wallet_name): | def get_wallet_rpc(self, wallet_name): | ||||
if self.use_cli: | if self.use_cli: | ||||
return self.cli("-rpcwallet={}".format(wallet_name)) | return RPCOverloadWrapper( | ||||
self.cli("-rpcwallet={}".format(wallet_name)), True) | |||||
else: | else: | ||||
assert self.rpc is not None, self._node_msg( | assert self.rpc is not None, self._node_msg( | ||||
"Error: RPC not initialized") | "Error: RPC not initialized") | ||||
assert self.rpc_connected, self._node_msg( | assert self.rpc_connected, self._node_msg( | ||||
"Error: RPC not connected") | "Error: RPC not connected") | ||||
wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name)) | wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name)) | ||||
return self.rpc / wallet_path | return RPCOverloadWrapper(self.rpc / wallet_path) | ||||
def stop_node(self, expected_stderr='', wait=0): | def stop_node(self, expected_stderr='', wait=0): | ||||
"""Stop the node.""" | """Stop the node.""" | ||||
if not self.running: | if not self.running: | ||||
return | return | ||||
self.log.debug("Stopping node") | self.log.debug("Stopping node") | ||||
try: | try: | ||||
self.stop(wait=wait) | self.stop(wait=wait) | ||||
▲ Show 20 Lines • Show All 368 Lines • ▼ Show 20 Lines | def send_cli(self, command=None, *args, **kwargs): | ||||
raise JSONRPCException(dict(code=int(code), message=message)) | raise JSONRPCException(dict(code=int(code), message=message)) | ||||
# Ignore cli_stdout, raise with cli_stderr | # Ignore cli_stdout, raise with cli_stderr | ||||
raise subprocess.CalledProcessError( | raise subprocess.CalledProcessError( | ||||
returncode, self.binary, output=cli_stderr) | returncode, self.binary, output=cli_stderr) | ||||
try: | try: | ||||
return json.loads(cli_stdout, parse_float=decimal.Decimal) | return json.loads(cli_stdout, parse_float=decimal.Decimal) | ||||
except (json.JSONDecodeError, decimal.InvalidOperation): | except (json.JSONDecodeError, decimal.InvalidOperation): | ||||
return cli_stdout.rstrip("\n") | return cli_stdout.rstrip("\n") | ||||
class RPCOverloadWrapper(): | |||||
def __init__(self, rpc, cli=False): | |||||
self.rpc = rpc | |||||
self.is_cli = cli | |||||
def __getattr__(self, name): | |||||
return getattr(self.rpc, name) | |||||
def importprivkey(self, privkey, label=None, rescan=None): | |||||
wallet_info = self.getwalletinfo() | |||||
if self.is_cli: | |||||
if label is None: | |||||
label = 'null' | |||||
if rescan is None: | |||||
rescan = 'null' | |||||
if 'descriptors' not in wallet_info or ( | |||||
'descriptors' in wallet_info and not wallet_info['descriptors']): | |||||
return self.__getattr__('importprivkey')(privkey, label, rescan) | |||||
desc = descsum_create('combo(' + privkey + ')') | |||||
req = [{ | |||||
'desc': desc, | |||||
'timestamp': 0 if rescan else 'now', | |||||
'label': label if label else '' | |||||
}] | |||||
import_res = self.importdescriptors(req) | |||||
if not import_res[0]['success']: | |||||
raise JSONRPCException(import_res[0]['error']) | |||||
def addmultisigaddress(self, nrequired, keys, | |||||
label=None): | |||||
wallet_info = self.getwalletinfo() | |||||
if self.is_cli: | |||||
if label is None: | |||||
label = 'null' | |||||
if 'descriptors' not in wallet_info or ( | |||||
'descriptors' in wallet_info and not wallet_info['descriptors']): | |||||
return self.__getattr__('addmultisigaddress')( | |||||
nrequired, keys, label) | |||||
cms = self.createmultisig(nrequired, keys) | |||||
req = [{ | |||||
'desc': cms['descriptor'], | |||||
'timestamp': 0, | |||||
'label': label if label else '' | |||||
}] | |||||
import_res = self.importdescriptors(req) | |||||
if not import_res[0]['success']: | |||||
raise JSONRPCException(import_res[0]['error']) | |||||
return cms | |||||
def importpubkey(self, pubkey, label=None, rescan=None): | |||||
wallet_info = self.getwalletinfo() | |||||
if self.is_cli: | |||||
if label is None: | |||||
label = 'null' | |||||
if rescan is None: | |||||
rescan = 'null' | |||||
if 'descriptors' not in wallet_info or ( | |||||
'descriptors' in wallet_info and not wallet_info['descriptors']): | |||||
return self.__getattr__('importpubkey')(pubkey, label, rescan) | |||||
desc = descsum_create('combo(' + pubkey + ')') | |||||
req = [{ | |||||
'desc': desc, | |||||
'timestamp': 0 if rescan else 'now', | |||||
'label': label if label else '' | |||||
}] | |||||
import_res = self.importdescriptors(req) | |||||
if not import_res[0]['success']: | |||||
raise JSONRPCException(import_res[0]['error']) | |||||
def importaddress(self, address, label=None, rescan=None, p2sh=None): | |||||
wallet_info = self.getwalletinfo() | |||||
if self.is_cli: | |||||
if label is None: | |||||
label = 'null' | |||||
if rescan is None: | |||||
rescan = 'null' | |||||
if p2sh is None: | |||||
p2sh = 'null' | |||||
if 'descriptors' not in wallet_info or ( | |||||
'descriptors' in wallet_info and not wallet_info['descriptors']): | |||||
return self.__getattr__('importaddress')( | |||||
address, label, rescan, p2sh) | |||||
is_hex = False | |||||
try: | |||||
int(address, 16) | |||||
is_hex = True | |||||
desc = descsum_create('raw(' + address + ')') | |||||
except BaseException: | |||||
desc = descsum_create('addr(' + address + ')') | |||||
reqs = [{ | |||||
'desc': desc, | |||||
'timestamp': 0 if rescan else 'now', | |||||
'label': label if label else '' | |||||
}] | |||||
if is_hex and p2sh: | |||||
reqs.append({ | |||||
'desc': descsum_create('p2sh(raw(' + address + '))'), | |||||
'timestamp': 0 if rescan else 'now', | |||||
'label': label if label else '' | |||||
}) | |||||
import_res = self.importdescriptors(reqs) | |||||
for res in import_res: | |||||
if not res['success']: | |||||
raise JSONRPCException(res['error']) |