Skip to content

Commit

Permalink
add multi rpc call support, reduce call count (#243)
Browse files Browse the repository at this point in the history
* add multi rpc call support, reduce call count

* fix rpcerror and test
  • Loading branch information
stepansnigirev authored Jul 17, 2020
1 parent e19d68c commit e5607df
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 43 deletions.
75 changes: 41 additions & 34 deletions src/cryptoadvance/specter/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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):
Expand All @@ -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

Expand Down
30 changes: 21 additions & 9 deletions src/cryptoadvance/specter/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit e5607df

Please sign in to comment.