2019-06-15 23:02:44 +00:00
|
|
|
from config import *
|
2021-11-07 04:40:57 +00:00
|
|
|
from utilities import *
|
2022-02-18 03:03:06 +00:00
|
|
|
from systemctl_info import *
|
2019-11-04 04:50:47 +00:00
|
|
|
from threading import Timer
|
2022-02-18 03:03:06 +00:00
|
|
|
import requests
|
2019-06-15 23:02:44 +00:00
|
|
|
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
2021-03-14 04:30:41 +00:00
|
|
|
import urllib
|
2019-06-15 23:02:44 +00:00
|
|
|
import subprocess
|
|
|
|
import copy
|
|
|
|
import time
|
|
|
|
import os
|
|
|
|
|
|
|
|
# Variables
|
|
|
|
bitcoin_block_height = 570000
|
|
|
|
mynode_block_height = 566000
|
|
|
|
bitcoin_blockchain_info = None
|
|
|
|
bitcoin_recent_blocks = None
|
2021-03-03 01:49:35 +00:00
|
|
|
bitcoin_recent_blocks_last_cache_height = 566000
|
2019-06-15 23:02:44 +00:00
|
|
|
bitcoin_peers = []
|
2020-04-21 01:19:56 +00:00
|
|
|
bitcoin_network_info = None
|
2021-03-14 04:30:41 +00:00
|
|
|
bitcoin_wallets = None
|
2019-06-15 23:02:44 +00:00
|
|
|
bitcoin_mempool = None
|
2022-02-18 03:03:06 +00:00
|
|
|
bitcoin_recommended_fees = None
|
2019-06-15 23:02:44 +00:00
|
|
|
bitcoin_version = None
|
2022-03-07 04:02:30 +00:00
|
|
|
BITCOIN_CACHE_FILE = "/tmp/bitcoin_info.json"
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
# Functions
|
|
|
|
def get_bitcoin_rpc_username():
|
|
|
|
return "mynode"
|
|
|
|
|
|
|
|
def get_bitcoin_rpc_password():
|
|
|
|
try:
|
2019-07-06 01:45:42 +00:00
|
|
|
with open("/mnt/hdd/mynode/settings/.btcrpcpw", "r") as f:
|
2019-06-15 23:02:44 +00:00
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "error_getting_password"
|
|
|
|
|
|
|
|
def get_bitcoin_version():
|
|
|
|
global bitcoin_version
|
|
|
|
if bitcoin_version == None:
|
2021-11-07 04:40:57 +00:00
|
|
|
bitcoin_version = to_string(subprocess.check_output("bitcoind --version | egrep -o 'v[0-9]+\\.[0-9]+\\.[0-9]+'", shell=True))
|
2019-06-15 23:02:44 +00:00
|
|
|
return bitcoin_version
|
|
|
|
|
2021-04-11 00:51:26 +00:00
|
|
|
def is_bitcoin_synced():
|
2019-06-15 23:02:44 +00:00
|
|
|
if os.path.isfile( BITCOIN_SYNCED_FILE ):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def update_bitcoin_main_info():
|
|
|
|
global bitcoin_block_height
|
|
|
|
global mynode_block_height
|
|
|
|
global bitcoin_blockchain_info
|
|
|
|
|
|
|
|
try:
|
|
|
|
rpc_user = get_bitcoin_rpc_username()
|
|
|
|
rpc_pass = get_bitcoin_rpc_password()
|
|
|
|
|
|
|
|
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%(rpc_user, rpc_pass), timeout=120)
|
|
|
|
|
|
|
|
# Basic Info
|
2022-03-07 04:02:30 +00:00
|
|
|
info = rpc_connection.getblockchaininfo()
|
|
|
|
if info != None:
|
|
|
|
# Save specific data
|
|
|
|
bitcoin_block_height = info['headers']
|
|
|
|
mynode_block_height = info['blocks']
|
|
|
|
# Data cleanup
|
|
|
|
if "difficulty" in info:
|
|
|
|
info["difficulty"] = "{:.3g}".format(info["difficulty"])
|
|
|
|
if "verificationprogress" in info:
|
|
|
|
info["verificationprogress"] = "{:.3g}".format(info["verificationprogress"])
|
|
|
|
|
|
|
|
bitcoin_blockchain_info = info
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
except Exception as e:
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("ERROR: In update_bitcoin_info - {} DATA: {}".format( str(e), str(info) ))
|
2019-06-15 23:02:44 +00:00
|
|
|
return False
|
|
|
|
|
2022-03-07 04:02:30 +00:00
|
|
|
update_bitcoin_json_cache()
|
2019-06-15 23:02:44 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
def update_bitcoin_other_info():
|
2021-03-03 01:49:35 +00:00
|
|
|
global mynode_block_height
|
2019-06-15 23:02:44 +00:00
|
|
|
global bitcoin_blockchain_info
|
|
|
|
global bitcoin_recent_blocks
|
2021-03-03 01:49:35 +00:00
|
|
|
global bitcoin_recent_blocks_last_cache_height
|
2019-06-15 23:02:44 +00:00
|
|
|
global bitcoin_peers
|
2020-04-21 01:19:56 +00:00
|
|
|
global bitcoin_network_info
|
2019-06-15 23:02:44 +00:00
|
|
|
global bitcoin_mempool
|
2022-02-18 03:03:06 +00:00
|
|
|
global bitcoin_recommended_fees
|
2021-03-14 04:30:41 +00:00
|
|
|
global bitcoin_wallets
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2020-10-08 02:59:44 +00:00
|
|
|
while bitcoin_blockchain_info == None:
|
|
|
|
# Wait until we have gotten the important info...
|
|
|
|
# Checking quickly helps the API get started faster
|
|
|
|
time.sleep(1)
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
rpc_user = get_bitcoin_rpc_username()
|
|
|
|
rpc_pass = get_bitcoin_rpc_password()
|
|
|
|
|
|
|
|
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%(rpc_user, rpc_pass), timeout=60)
|
|
|
|
|
|
|
|
# Get other less important info
|
|
|
|
try:
|
|
|
|
# Recent blocks
|
2021-03-03 01:49:35 +00:00
|
|
|
if mynode_block_height != bitcoin_recent_blocks_last_cache_height:
|
|
|
|
commands = [ [ "getblockhash", height] for height in range(mynode_block_height-9, mynode_block_height+1) ]
|
|
|
|
block_hashes = rpc_connection.batch_(commands)
|
|
|
|
bitcoin_recent_blocks = rpc_connection.batch_([ [ "getblock", h ] for h in block_hashes ])
|
|
|
|
bitcoin_recent_blocks_last_cache_height = mynode_block_height
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2022-03-07 04:02:30 +00:00
|
|
|
# Get peers and cleanup data
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("update_bitcoin_other_info - PEERS")
|
2022-03-07 04:02:30 +00:00
|
|
|
peerdata = rpc_connection.getpeerinfo()
|
|
|
|
peers = []
|
|
|
|
if peerdata != None:
|
|
|
|
for p in peerdata:
|
|
|
|
peer = p
|
|
|
|
|
|
|
|
peer["pingtime"] = int(p["pingtime"] * 1000) if ("pingtime" in p) else "N/A"
|
|
|
|
peer["tx"] = "{:.2f}".format(float(p["bytessent"]) / 1000 / 1000) if ("bytessent" in p) else "N/A"
|
|
|
|
peer["rx"] = "{:.2f}".format(float(p["bytesrecv"]) / 1000 / 1000) if ("bytesrecv" in p) else "N/A"
|
|
|
|
peer["minping"] = str(p["minping"]) if ("minping" in p) else "N/A"
|
|
|
|
peer["minfeefilter"] = str(p["minfeefilter"]) if ("minfeefilter" in p) else "N/A"
|
|
|
|
peer["pingwait"] = str(p["pingwait"]) if ("pingwait" in p) else "N/A"
|
|
|
|
|
|
|
|
peers.append(peer)
|
|
|
|
bitcoin_peers = peers
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2020-04-21 01:19:56 +00:00
|
|
|
# Get network info
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("update_bitcoin_other_info - NETWORK")
|
2022-03-07 04:02:30 +00:00
|
|
|
network_data = rpc_connection.getnetworkinfo()
|
|
|
|
if network_data != None:
|
|
|
|
network_data["relayfee"] = str(network_data["relayfee"])
|
|
|
|
network_data["incrementalfee"] = str(network_data["incrementalfee"])
|
|
|
|
bitcoin_network_info = network_data
|
2020-04-21 01:19:56 +00:00
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
# Get mempool
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("update_bitcoin_other_info - MEMPOOL")
|
2022-03-07 04:02:30 +00:00
|
|
|
mempool_data = rpc_connection.getmempoolinfo()
|
|
|
|
if mempool_data != None:
|
|
|
|
mempool_data["total_fee"] = str(mempool_data["total_fee"])
|
|
|
|
mempool_data["mempoolminfee"] = str(mempool_data["mempoolminfee"])
|
|
|
|
mempool_data["minrelaytxfee"] = str(mempool_data["minrelaytxfee"])
|
|
|
|
bitcoin_mempool = mempool_data
|
2020-02-17 06:14:57 +00:00
|
|
|
|
|
|
|
# Get wallet info
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("update_bitcoin_other_info - WALLETS")
|
2021-03-14 04:30:41 +00:00
|
|
|
wallets = rpc_connection.listwallets()
|
|
|
|
wallet_data = []
|
|
|
|
for w in wallets:
|
2022-02-10 04:28:46 +00:00
|
|
|
wallet_name = "FILL_IN"
|
|
|
|
if isPython3():
|
|
|
|
wallet_name = urllib.request.pathname2url(w)
|
|
|
|
else:
|
|
|
|
wallet_name = urllib.pathname2url(w)
|
|
|
|
|
2021-03-14 04:30:41 +00:00
|
|
|
wallet_rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332/wallet/%s"%(rpc_user, rpc_pass, wallet_name), timeout=60)
|
|
|
|
wallet_info = wallet_rpc_connection.getwalletinfo()
|
|
|
|
wallet_data.append(wallet_info)
|
|
|
|
bitcoin_wallets = wallet_data
|
2022-02-18 03:03:06 +00:00
|
|
|
|
|
|
|
# Get recommended fee info (from mempool on port 4080)
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("update_bitcoin_other_info - MEMPOOL")
|
2022-02-18 03:03:06 +00:00
|
|
|
if is_service_enabled("mempool"):
|
|
|
|
try:
|
|
|
|
r = requests.get("http://localhost:4080/api/v1/fees/recommended", timeout=1)
|
|
|
|
data = r.json()
|
|
|
|
bitcoin_recommended_fees = ""
|
|
|
|
bitcoin_recommended_fees += "Low priority: {} sat/vB".format(data["hourFee"])
|
|
|
|
bitcoin_recommended_fees += " "
|
|
|
|
bitcoin_recommended_fees += "Medium priority: {} sat/vB".format(data["halfHourFee"])
|
|
|
|
bitcoin_recommended_fees += " "
|
|
|
|
bitcoin_recommended_fees += "High priority: {} sat/vB".format(data["fastestFee"])
|
|
|
|
except Exception as e:
|
|
|
|
bitcoin_recommended_fees = "Fee error - " . str(e)
|
|
|
|
else:
|
|
|
|
bitcoin_recommended_fees = None
|
2022-02-10 04:28:46 +00:00
|
|
|
except Exception as e1:
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("ERROR: In update_bitcoin_other_info (1) - {} DATA: {}".format( str(e1), str() ))
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2022-02-10 04:28:46 +00:00
|
|
|
except Exception as e2:
|
2022-03-21 03:22:08 +00:00
|
|
|
log_message("ERROR: In update_bitcoin_other_info (2) - {} DATA: {}".format( str(e2), str() ))
|
2019-06-15 23:02:44 +00:00
|
|
|
return False
|
|
|
|
|
2022-03-07 04:02:30 +00:00
|
|
|
update_bitcoin_json_cache()
|
2019-06-15 23:02:44 +00:00
|
|
|
return True
|
|
|
|
|
2020-10-03 04:43:30 +00:00
|
|
|
def get_bitcoin_status():
|
|
|
|
height = get_bitcoin_block_height()
|
|
|
|
block = get_mynode_block_height()
|
|
|
|
status = "unknown"
|
|
|
|
|
|
|
|
if height != None and block != None:
|
|
|
|
remaining = height - block
|
|
|
|
if remaining == 0:
|
|
|
|
status = "Running"
|
|
|
|
else:
|
|
|
|
status = "Syncing<br/>{} blocks remaining...".format(remaining)
|
|
|
|
else:
|
|
|
|
status = "Waiting for info..."
|
|
|
|
return status
|
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_bitcoin_blockchain_info():
|
|
|
|
global bitcoin_blockchain_info
|
|
|
|
return copy.deepcopy(bitcoin_blockchain_info)
|
|
|
|
|
2020-10-01 00:55:24 +00:00
|
|
|
def get_bitcoin_difficulty():
|
|
|
|
info = get_bitcoin_blockchain_info()
|
|
|
|
if "difficulty" in info:
|
2022-03-07 04:02:30 +00:00
|
|
|
return info["difficulty"]
|
2020-10-01 00:55:24 +00:00
|
|
|
return "???"
|
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_bitcoin_block_height():
|
|
|
|
global bitcoin_block_height
|
|
|
|
return bitcoin_block_height
|
|
|
|
|
|
|
|
def get_mynode_block_height():
|
|
|
|
global mynode_block_height
|
|
|
|
return mynode_block_height
|
|
|
|
|
|
|
|
def get_bitcoin_recent_blocks():
|
|
|
|
global bitcoin_recent_blocks
|
|
|
|
return copy.deepcopy(bitcoin_recent_blocks)
|
|
|
|
|
|
|
|
def get_bitcoin_peers():
|
|
|
|
global bitcoin_peers
|
|
|
|
return copy.deepcopy(bitcoin_peers)
|
|
|
|
|
2020-10-01 00:55:24 +00:00
|
|
|
def get_bitcoin_peer_count():
|
|
|
|
peers = get_bitcoin_peers()
|
|
|
|
if peers != None:
|
|
|
|
return len(peers)
|
|
|
|
return 0
|
|
|
|
|
2020-04-21 01:19:56 +00:00
|
|
|
def get_bitcoin_network_info():
|
|
|
|
global bitcoin_network_info
|
|
|
|
return copy.deepcopy(bitcoin_network_info)
|
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_bitcoin_mempool():
|
|
|
|
global bitcoin_mempool
|
2019-11-04 04:50:47 +00:00
|
|
|
return copy.deepcopy(bitcoin_mempool)
|
|
|
|
|
2020-10-01 00:55:24 +00:00
|
|
|
def get_bitcoin_mempool_info():
|
|
|
|
mempooldata = get_bitcoin_mempool()
|
|
|
|
|
|
|
|
mempool = {}
|
|
|
|
mempool["size"] = "???"
|
2022-03-12 03:21:51 +00:00
|
|
|
mempool["count"] = "???"
|
2020-10-01 00:55:24 +00:00
|
|
|
mempool["bytes"] = "0"
|
2022-03-12 03:21:51 +00:00
|
|
|
mempool["display_bytes"] = "???"
|
2020-10-01 00:55:24 +00:00
|
|
|
if mempooldata != None:
|
2022-03-07 04:02:30 +00:00
|
|
|
mempool["display_size"] = "unknown"
|
2020-10-01 00:55:24 +00:00
|
|
|
if "size" in mempooldata:
|
|
|
|
mempool["size"] = mempooldata["size"]
|
2022-03-12 03:21:51 +00:00
|
|
|
mempool["count"] = mempooldata["size"]
|
2020-10-01 00:55:24 +00:00
|
|
|
if "bytes" in mempooldata:
|
|
|
|
mempool["bytes"] = mempooldata["bytes"]
|
2022-03-12 03:21:51 +00:00
|
|
|
mb = round(float(mempool["bytes"] / 1000 / 1000), 2)
|
|
|
|
mempool["display_bytes"] = "{0:.10} MB".format( mb )
|
2020-10-01 00:55:24 +00:00
|
|
|
|
|
|
|
return copy.deepcopy(mempool)
|
|
|
|
|
2022-03-07 04:02:30 +00:00
|
|
|
def get_bitcoin_disk_usage():
|
|
|
|
info = get_bitcoin_blockchain_info()
|
|
|
|
if "size_on_disk" in info:
|
|
|
|
usage = int(info["size_on_disk"]) / 1000 / 1000 / 1000
|
|
|
|
return "{:.0f}".format(usage)
|
|
|
|
else:
|
|
|
|
return "UNK"
|
2020-10-03 04:43:30 +00:00
|
|
|
|
2022-02-18 03:03:06 +00:00
|
|
|
def get_bitcoin_recommended_fees():
|
|
|
|
global bitcoin_recommended_fees
|
|
|
|
return bitcoin_recommended_fees
|
|
|
|
|
2021-03-14 04:30:41 +00:00
|
|
|
def get_bitcoin_wallets():
|
|
|
|
global bitcoin_wallets
|
|
|
|
return copy.deepcopy(bitcoin_wallets)
|
2020-02-17 06:14:57 +00:00
|
|
|
|
2019-11-04 04:50:47 +00:00
|
|
|
def get_default_bitcoin_config():
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/bitcoin.conf") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
|
|
|
|
def get_bitcoin_config():
|
|
|
|
try:
|
|
|
|
with open("/mnt/hdd/mynode/bitcoin/bitcoin.conf") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
|
2019-11-05 01:34:19 +00:00
|
|
|
def get_bitcoin_custom_config():
|
2019-11-04 04:50:47 +00:00
|
|
|
try:
|
2019-11-05 01:34:19 +00:00
|
|
|
with open("/mnt/hdd/mynode/settings/bitcoin_custom.conf") as f:
|
2019-11-04 04:50:47 +00:00
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
|
2019-11-05 01:34:19 +00:00
|
|
|
def set_bitcoin_custom_config(config):
|
2019-11-04 04:50:47 +00:00
|
|
|
try:
|
2019-11-05 01:34:19 +00:00
|
|
|
with open("/mnt/hdd/mynode/settings/bitcoin_custom.conf", "w") as f:
|
2019-11-04 04:50:47 +00:00
|
|
|
f.write(config)
|
|
|
|
os.system("sync")
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
|
2020-07-14 03:10:06 +00:00
|
|
|
def using_bitcoin_custom_config():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/bitcoin_custom.conf")
|
|
|
|
|
2019-11-05 01:34:19 +00:00
|
|
|
def delete_bitcoin_custom_config():
|
|
|
|
os.system("rm -f /mnt/hdd/mynode/settings/bitcoin_custom.conf")
|
|
|
|
|
2019-11-04 04:50:47 +00:00
|
|
|
def restart_bitcoin_actual():
|
2021-04-11 00:51:26 +00:00
|
|
|
os.system("systemctl restart bitcoin")
|
2019-11-04 04:50:47 +00:00
|
|
|
|
|
|
|
def restart_bitcoin():
|
|
|
|
t = Timer(1.0, restart_bitcoin_actual)
|
2021-11-17 05:43:12 +00:00
|
|
|
t.start()
|
|
|
|
|
2022-02-11 05:52:28 +00:00
|
|
|
def is_bip37_enabled():
|
|
|
|
if os.path.isfile("/mnt/hdd/mynode/settings/.bip37_enabled"):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
def enable_bip37():
|
|
|
|
touch("/mnt/hdd/mynode/settings/.bip37_enabled")
|
|
|
|
def disable_bip37():
|
|
|
|
delete_file("/mnt/hdd/mynode/settings/.bip37_enabled")
|
|
|
|
|
|
|
|
def is_bip157_enabled():
|
|
|
|
if os.path.isfile("/mnt/hdd/mynode/settings/.bip157_enabled"):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
def enable_bip157():
|
|
|
|
touch("/mnt/hdd/mynode/settings/.bip157_enabled")
|
|
|
|
def disable_bip157():
|
|
|
|
delete_file("/mnt/hdd/mynode/settings/.bip157_enabled")
|
|
|
|
|
2021-11-17 05:43:12 +00:00
|
|
|
def is_bip158_enabled():
|
|
|
|
if os.path.isfile("/mnt/hdd/mynode/settings/.bip158_enabled"):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
def enable_bip158():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/.bip158_enabled")
|
2021-11-17 05:43:12 +00:00
|
|
|
def disable_bip158():
|
2022-03-07 04:02:30 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/.bip158_enabled")
|
|
|
|
|
|
|
|
|
|
|
|
def update_bitcoin_json_cache():
|
|
|
|
global BITCOIN_CACHE_FILE
|
|
|
|
bitcoin_data = {}
|
|
|
|
bitcoin_data["current_block_height"] = mynode_block_height
|
|
|
|
bitcoin_data["blockchain_info"] = get_bitcoin_blockchain_info()
|
|
|
|
#bitcoin_data["recent_blocks"] = bitcoin_recent_blocks
|
|
|
|
bitcoin_data["peers"] = get_bitcoin_peers()
|
|
|
|
bitcoin_data["network_info"] = get_bitcoin_network_info()
|
|
|
|
bitcoin_data["mempool"] = get_bitcoin_mempool_info()
|
|
|
|
#bitcoin_data["recommended_fees"] = bitcoin_recommended_fees
|
|
|
|
bitcoin_data["disk_usage"] = get_bitcoin_disk_usage()
|
|
|
|
return set_dictionary_file_cache(bitcoin_data, BITCOIN_CACHE_FILE)
|
|
|
|
|
|
|
|
def get_bitcoin_json_cache():
|
|
|
|
global BITCOIN_CACHE_FILE
|
|
|
|
return get_dictionary_file_cache(BITCOIN_CACHE_FILE)
|