autodetect json-rpc including cookies

This commit is contained in:
Stepan Snigirev 2019-09-27 13:20:18 +02:00
parent 56cc976bbd
commit 43d165df54
3 changed files with 148 additions and 102 deletions

123
rpc.py
View file

@ -1,9 +1,132 @@
import requests, json, os
import os, sys, errno
# TODO: redefine __dir__ and help
RPC_PORTS = { "test": 18332, "regtest": 18443, "main": 8332, 'signet': 38332 }
def get_default_datadir():
datadir = None
if sys.platform == 'darwin':
datadir = os.path.join(os.environ['HOME'], "Library/Application Support/Bitcoin/")
elif sys.platform == 'win32':
datadir = os.path.join(os.environ['HOME'], "Bitcoin")
else:
datadir = os.path.join(os.environ['HOME'], ".bitcoin")
return datadir
def get_rpcconfig():
path = get_default_datadir()
config = {
"bitcoin.conf": {},
"cookies": [],
}
if not os.path.isdir(path): # we don't know where to search for files
return config
# load content from bitcoin.conf
bitcoin_conf_file = os.path.join(path, "bitcoin.conf")
if os.path.exists(bitcoin_conf_file):
try:
with open(bitcoin_conf_file, 'r') as f:
for line in f.readlines():
line = line.split("#")[0]
if '=' not in line:
continue
k, v = line.split('=', 1)
config["bitcoin.conf"][k.strip()] = v.strip()
except:
print("Can't open %s file" % bitcoin_conf_file)
folders = {
"main": "",
"test": "testnet3",
"regtest": "regtest",
"signet": "signet",
}
for chain in folders:
fname = os.path.join(path, folders[chain], ".cookie")
if os.path.exists(fname):
try:
with open(fname, 'r') as f:
content = f.read()
user, passwd = content.split(":")
obj = {
"user": user,
"passwd": passwd,
"port": RPC_PORTS[chain]
}
config["cookies"].append(obj)
except:
print("Can't open %s file" % fname)
return config
def get_configs(config=None):
if config is None:
config = get_rpcconfig()
confs = []
default = {}
if "rpcuser" in config["bitcoin.conf"]:
default["user"] = config["bitcoin.conf"]["rpcuser"]
if "rpcpassword" in config["bitcoin.conf"]:
default["passwd"] = config["bitcoin.conf"]["rpcpassword"]
if "rpchost" in config["bitcoin.conf"]:
default["host"] = config["bitcoin.conf"]["rpchost"]
if "rpcport" in config["bitcoin.conf"]:
default["port"] = int(config["bitcoin.conf"]["rpcport"])
if "user" in default and "passwd" in default:
if "port" in default: # only one bitcoin-cli makes sense in this case
confs.append(default)
return confs
else:
for network in RPC_PORTS:
o = {"port": RPC_PORTS[network]}
o.update(default)
confs.append(o)
return confs
# try cookies now
for cookie in config["cookies"]:
o = {}
o.update(default)
print(cookie)
o.update(cookie)
confs.append(o)
return confs
def detect_cli(config=None):
if config is None:
config = get_rpcconfig()
rpcconfs = get_configs(config)
cli_arr = []
for conf in rpcconfs:
print(conf)
cli_arr.append(BitcoinCLI(**conf))
return cli_arr
def autodetect_cli(port=None):
if port == "":
port = None
if port is not None:
port = int(port)
cli_arr = detect_cli()
available_cli_arr = []
if len(cli_arr) > 0:
print("trying %d different configs" % len(cli_arr))
for cli in cli_arr:
if port is not None:
if int(cli.port) != port:
continue
try:
print(cli.getmininginfo())
print("Yey! Bitcoin-cli found!")
available_cli_arr.append(cli)
except requests.exceptions.RequestException:
print("can't connect")
except Exception as e:
print("fail...", e)
else:
print("Bitcoin-cli not found :(")
print("Detected %d bitcoin daemons" % len(available_cli_arr))
return available_cli_arr
class BitcoinCLI:
def __init__(self, user, passwd, host="127.0.0.1", port=8332, protocol="http", path="", timeout=30, **kwargs):
path = path.replace("//","/") # just in case

View file

@ -2,100 +2,6 @@ import os, sys, errno
from rpc import *
import requests
def get_default_datadir():
datadir = None
if sys.platform == 'darwin':
datadir = os.path.join(os.environ['HOME'], "Library/Application Support/Bitcoin/")
elif sys.platform == 'win32':
datadir = os.path.join(os.environ['HOME'], "Bitcoin")
else:
datadir = os.path.join(os.environ['HOME'], ".bitcoin")
return datadir
def get_rpcconfig():
path = get_default_datadir()
config = {
"bitcoin.conf": {},
"cookies": [],
}
if not os.path.isdir(path): # we don't know where to search for files
return config
# load content from bitcoin.conf
bitcoin_conf_file = os.path.join(path, "bitcoin.conf")
if os.path.exists(bitcoin_conf_file):
try:
with open(bitcoin_conf_file, 'r') as f:
for line in f.readlines():
line = line.split("#")[0]
if '=' not in line:
continue
k, v = line.split('=', 1)
config["bitcoin.conf"][k.strip()] = v.strip()
except:
print("Can't open %s file" % bitcoin_conf_file)
folders = {
"main": "",
"test": "testnet3",
"regtest": "regtest",
"signet": "signet",
}
for chain in folders:
fname = os.path.join(path, folders[chain], ".cookie")
if os.path.exists(fname):
try:
with open(fname, 'r') as f:
content = f.read()
user, passwd = content.split(":")
obj = {
"user": user,
"passwd": passwd,
"port": RPC_PORTS[chain]
}
config["cookies"].append(obj)
except:
print("Can't open %s file" % fname)
return config
def get_configs(config):
confs = []
default = {}
if "rpcuser" in config["bitcoin.conf"]:
default["user"] = config["bitcoin.conf"]["rpcuser"]
if "rpcpassword" in config["bitcoin.conf"]:
default["passwd"] = config["bitcoin.conf"]["rpcpassword"]
if "rpchost" in config["bitcoin.conf"]:
default["host"] = config["bitcoin.conf"]["rpchost"]
if "rpcport" in config["bitcoin.conf"]:
default["port"] = int(config["bitcoin.conf"]["rpcport"])
if "user" in default and "passwd" in default:
if "port" in default: # only one bitcoin-cli makes sense in this case
confs.append(default)
return confs
else:
for network in RPC_PORTS:
o = {"port": RPC_PORTS[network]}
o.update(default)
confs.append(o)
return confs
# try cookies now
for cookie in config["cookies"]:
o = {}
o.update(default)
print(cookie)
o.update(cookie)
confs.append(o)
return confs
def detect_cli(config=None):
if config is None:
config = get_rpcconfig()
rpcconfs = get_configs(config)
cli_arr = []
for conf in rpcconfs:
print(conf)
cli_arr.append(BitcoinCLI(**conf))
return cli_arr
if __name__ == '__main__':
cli_arr = detect_cli()
available_cli_arr = []

View file

@ -1,4 +1,4 @@
from rpc import BitcoinCLI, RPC_PORTS
from rpc import BitcoinCLI, RPC_PORTS, autodetect_cli
import os, json, copy
from helpers import deep_update, load_jsons
from collections import OrderedDict
@ -59,6 +59,23 @@ def alias(name):
name = name.replace(" ", "_")
return "".join(x for x in name if x.isalnum() or x=="_").lower()
def get_cli(conf):
if "user" not in conf or conf["user"]=="":
conf["autodetect"] = True
if conf["autodetect"]:
if "port" in conf:
cli_arr = autodetect_cli(port=conf["port"])
else:
cli_arr = autodetect_cli()
if len(cli_arr) > 0:
cli = cli_arr[0]
else:
return None
else:
cli = BitcoinCLI(conf["user"], conf["password"],
host=conf["host"], port=conf["port"], protocol=conf["protocol"])
return cli
class Specter:
def __init__(self, data_folder="./data", config={}):
if data_folder.startswith("~"):
@ -74,6 +91,7 @@ class Specter:
# default config
self.config = {
"rpc": {
"autodetect": True,
"user": None,
"password": None,
"port": RPC_PORTS["main"],
@ -107,12 +125,11 @@ class Specter:
# init arguments
deep_update(self.config, self.arg_config) # override loaded config
# check if we have user, password and can connect
self._is_configured = bool(self.config["rpc"]["user"] and self.config["rpc"]["password"])
self.cli = get_cli(self.config["rpc"])
print(self.cli)
self._is_configured = (self.cli is not None)
self._is_running = False
if self._is_configured:
self.cli = BitcoinCLI(self.config["rpc"]["user"], self.config["rpc"]["password"],
host=self.config["rpc"]["host"], port=self.config["rpc"]["port"], protocol=self.config["rpc"]["protocol"])
try:
self._info = self.cli.getmininginfo()
self._is_running = True
@ -140,12 +157,12 @@ class Specter:
except Exception as e:
print("can't load wallets...", e)
def test_rpc(self, **kwargs):
conf = copy.deepcopy(self.config["rpc"])
conf.update(kwargs)
cli = BitcoinCLI(conf["user"], conf["password"],
host=conf["host"], port=conf["port"], protocol=conf["protocol"])
cli = get_cli(conf)
if cli is None:
return {"out": "", "err": "autodetect failed", "code": -1}
r = {}
try:
r["out"] = json.dumps(cli.getmininginfo(),indent=4)