diff --git a/src/cryptoadvance/specter/rpc.py b/src/cryptoadvance/specter/rpc.py index 1cd96ed9ad..cb17e6ead9 100644 --- a/src/cryptoadvance/specter/rpc.py +++ b/src/cryptoadvance/specter/rpc.py @@ -148,10 +148,14 @@ class RpcError(Exception): ''' def __init__(self, message, response): super(Exception, self).__init__(message) - self.status_code = response.status_code try: - error = json.loads(response.text) self.status_code = response.status_code + error = response.json() + except: + # ok already a dict + self.status_code = 500 + error = response + try: self.error_code = error['error']['code'] self.error_msg = error['error']['message'] except Exception as e: @@ -169,16 +173,16 @@ def __init__(self, user, passwd, host="127.0.0.1", port=8332, protocol="http", p self.path = path self.timeout = timeout self.r = None - def wallet(name=""): - return BitcoinCLI(user=self.user, - passwd=self.passwd, - port=self.port, - protocol=self.protocol, - host=self.host, - path="{}/wallet/{}".format(self.path, name), - timeout=self.timeout - ) - self.wallet = wallet + + def wallet(self, name=""): + return BitcoinCLI(user=self.user, + passwd=self.passwd, + port=self.port, + protocol=self.protocol, + host=self.host, + path="{}/wallet/{}".format(self.path, name), + timeout=self.timeout + ) @property def url(self): @@ -196,31 +200,34 @@ def clone(self): ''' returns a clone of self. Usefull if you want to mess with the properties ''' return BitcoinCLI(self.user, self.passwd, self.host, self.port, self.protocol, self.path, self.timeout) - def __getattr__(self, method): - # if hasattr(self, method): - # self. + def multi(self, calls:list, **kwargs): + """Makes batch request to Core""" headers = {'content-type': 'application/json'} + payload = [{ + "method": method, + "params": args, + "jsonrpc": "2.0", + "id": i, + } for i, (method, *args) in enumerate(calls)] + timeout = self.timeout + if "timeout" in kwargs: + timeout = kwargs["timeout"] + url = self.url + if "wallet" in kwargs: + url = url+"/wallet/{}".format(kwargs["wallet"]) + r = requests.post( + url, data=json.dumps(payload), headers=headers, timeout=timeout) + self.r = r + if r.status_code != 200: + raise RpcError("Server responded with error code %d: %s" % (r.status_code, r.text), r) + r = r.json() + return r + + def __getattr__(self, method): def fn(*args, **kwargs): - payload = { - "method": method, - "params": args, - "jsonrpc": "2.0", - "id": 0, - } - timeout = self.timeout - if "timeout" in kwargs: - timeout = kwargs["timeout"] - url = self.url - if "wallet" in kwargs: - url = url+"/wallet/{}".format(kwargs["wallet"]) - r = requests.post( - url, data=json.dumps(payload), headers=headers, timeout=timeout) - self.r = r - if r.status_code != 200: - raise RpcError("Server responded with error code %d: %s" % (r.status_code, r.text), r) - r = r.json() + r = self.multi([(method,*args)])[0] if r["error"] is not None: - raise Exception(r["error"]) + raise RpcError("Request error: %s" % r["error"]["message"], r) return r["result"] return fn diff --git a/src/cryptoadvance/specter/wallet.py b/src/cryptoadvance/specter/wallet.py index ccf9d6506c..12255eefd9 100644 --- a/src/cryptoadvance/specter/wallet.py +++ b/src/cryptoadvance/specter/wallet.py @@ -64,19 +64,31 @@ def __init__( if change_address == '': self.getnewaddress(change=True) - self.scan_addresses() + self.check_addresses() self.getdata() if old_format_detected: self.save_to_file() - def scan_addresses(self): - for tx in self.cli.listtransactions("*", 1000, 0, True): - address_info = self.cli.getaddressinfo(tx["address"]) - if "hdkeypath" in address_info: - path = address_info["hdkeypath"].split('/') - change = int(path[-2]) == 1 - while int(path[-1]) > (self.change_index if change else self.address_index): - self.getnewaddress(change=change) + def check_addresses(self): + """Checking the gap limit is still ok""" + txs = self.cli.listtransactions("*", 1000, 0, True) + addresses = [tx["address"] for tx in txs] + # remove duplicates + addresses = list(dict.fromkeys(addresses)) + # prepare rpc call + calls = [("getaddressinfo",addr) for addr in addresses] + # extract results + res = [r["result"] for r in self.cli.multi(calls)] + # extract last two indexes of hdkeypath + paths = [d["hdkeypath"].split("/")[-2:] for d in res if "hdkeypath" in d] + # get change and recv addresses + max_recv = max([int(p[1]) for p in paths if p[0]=="0"], default=-1) + max_change = max([int(p[1]) for p in paths if p[0]=="1"], default=-1) + # these calls will happen only if current addresses are used + while max_recv >= self.address_index: + self.getnewaddress(change=False) + while max_change >= self.change_index: + self.getnewaddress(change=True) @staticmethod def parse_old_format(wallet_dict, device_manager):