mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
Turn daemon subcommands into RPCs
This commit is contained in:
parent
4397767a5e
commit
9cfeadea70
4 changed files with 106 additions and 87 deletions
|
@ -50,6 +50,9 @@ from .address_synchronizer import TX_HEIGHT_LOCAL
|
|||
from .mnemonic import Mnemonic
|
||||
from .lnutil import SENT, RECEIVED
|
||||
from .lnpeer import channel_id_from_funding_tx
|
||||
from .plugin import run_hook
|
||||
from .version import ELECTRUM_VERSION
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .network import Network
|
||||
|
@ -105,10 +108,12 @@ def command(s):
|
|||
|
||||
class Commands:
|
||||
|
||||
def __init__(self, config: 'SimpleConfig', wallet: Abstract_Wallet,
|
||||
network: Optional['Network'], callback=None):
|
||||
def __init__(self, config: 'SimpleConfig',
|
||||
wallet: Abstract_Wallet,
|
||||
network: Optional['Network'], daemon=None, callback=None):
|
||||
self.config = config
|
||||
self.wallet = wallet
|
||||
self.daemon = daemon
|
||||
self.network = network
|
||||
self._callback = callback
|
||||
self.lnworker = self.wallet.lnworker if self.wallet else None
|
||||
|
@ -140,6 +145,58 @@ class Commands:
|
|||
"""List of commands"""
|
||||
return ' '.join(sorted(known_commands.keys()))
|
||||
|
||||
@command('n')
|
||||
async def getinfo(self):
|
||||
""" network info """
|
||||
net_params = self.network.get_parameters()
|
||||
response = {
|
||||
'path': self.network.config.path,
|
||||
'server': net_params.host,
|
||||
'blockchain_height': self.network.get_local_height(),
|
||||
'server_height': self.network.get_server_height(),
|
||||
'spv_nodes': len(self.network.get_interfaces()),
|
||||
'connected': self.network.is_connected(),
|
||||
'auto_connect': net_params.auto_connect,
|
||||
'version': ELECTRUM_VERSION,
|
||||
'default_wallet': self.config.get_wallet_path(),
|
||||
'fee_per_kb': self.config.fee_per_kb(),
|
||||
}
|
||||
return response
|
||||
|
||||
@command('n')
|
||||
async def stop(self):
|
||||
"""Stop daemon"""
|
||||
self.daemon.stop()
|
||||
return "Daemon stopped"
|
||||
|
||||
@command('n')
|
||||
async def list_wallets(self):
|
||||
"""List wallets open in daemon"""
|
||||
return [{'path':k, 'synchronized':w.is_up_to_date()} for k, w in self.daemon.wallets.items()]
|
||||
|
||||
@command('n')
|
||||
async def load_wallet(self):
|
||||
"""Open wallet in daemon"""
|
||||
path = self.config.get_wallet_path()
|
||||
wallet = self.daemon.load_wallet(path, self.config.get('password'))
|
||||
if wallet is not None:
|
||||
self.wallet = wallet
|
||||
run_hook('load_wallet', wallet, None)
|
||||
response = wallet is not None
|
||||
return response
|
||||
|
||||
@command('n')
|
||||
async def close_wallet(self):
|
||||
"""Close wallet"""
|
||||
path = self.config.get_wallet_path()
|
||||
path = standardize_path(path)
|
||||
if path in self.wallets:
|
||||
self.stop_wallet(path)
|
||||
response = True
|
||||
else:
|
||||
response = False
|
||||
return response
|
||||
|
||||
@command('')
|
||||
async def create(self, passphrase=None, password=None, encrypt_file=True, seed_type=None):
|
||||
"""Create a new wallet.
|
||||
|
|
|
@ -38,7 +38,6 @@ import jsonrpcclient
|
|||
import jsonrpcserver
|
||||
from jsonrpcclient.clients.aiohttp_client import AiohttpClient
|
||||
|
||||
from .version import ELECTRUM_VERSION
|
||||
from .network import Network
|
||||
from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare)
|
||||
from .wallet import Wallet, Abstract_Wallet
|
||||
|
@ -46,7 +45,6 @@ from .storage import WalletStorage
|
|||
from .commands import known_commands, Commands
|
||||
from .simple_config import SimpleConfig
|
||||
from .exchange_rate import FxThread
|
||||
from .plugin import run_hook
|
||||
from .logging import get_logger, Logger
|
||||
|
||||
|
||||
|
@ -243,7 +241,7 @@ class Daemon(Logger):
|
|||
self.methods.add(self.ping)
|
||||
self.methods.add(self.gui)
|
||||
self.methods.add(self.daemon)
|
||||
self.cmd_runner = Commands(self.config, None, self.network)
|
||||
self.cmd_runner = Commands(self.config, None, self.network, self)
|
||||
for cmdname in known_commands:
|
||||
self.methods.add(getattr(self.cmd_runner, cmdname))
|
||||
self.methods.add(self.run_cmdline)
|
||||
|
@ -263,46 +261,9 @@ class Daemon(Logger):
|
|||
async def daemon(self, config_options):
|
||||
config = SimpleConfig(config_options)
|
||||
sub = config.get('subcommand')
|
||||
assert sub in [None, 'start', 'stop', 'status', 'load_wallet', 'close_wallet']
|
||||
assert sub in [None, 'start', 'stop']
|
||||
if sub in [None, 'start']:
|
||||
response = "Daemon already running"
|
||||
elif sub == 'load_wallet':
|
||||
path = config.get_wallet_path()
|
||||
wallet = self.load_wallet(path, config.get('password'))
|
||||
if wallet is not None:
|
||||
self.cmd_runner.wallet = wallet
|
||||
run_hook('load_wallet', wallet, None)
|
||||
response = wallet is not None
|
||||
elif sub == 'close_wallet':
|
||||
path = config.get_wallet_path()
|
||||
path = standardize_path(path)
|
||||
if path in self.wallets:
|
||||
self.stop_wallet(path)
|
||||
response = True
|
||||
else:
|
||||
response = False
|
||||
elif sub == 'status':
|
||||
if self.network:
|
||||
net_params = self.network.get_parameters()
|
||||
current_wallet = self.cmd_runner.wallet
|
||||
current_wallet_path = current_wallet.storage.path \
|
||||
if current_wallet else None
|
||||
response = {
|
||||
'path': self.network.config.path,
|
||||
'server': net_params.host,
|
||||
'blockchain_height': self.network.get_local_height(),
|
||||
'server_height': self.network.get_server_height(),
|
||||
'spv_nodes': len(self.network.get_interfaces()),
|
||||
'connected': self.network.is_connected(),
|
||||
'auto_connect': net_params.auto_connect,
|
||||
'version': ELECTRUM_VERSION,
|
||||
'wallets': {k: w.is_up_to_date()
|
||||
for k, w in self.wallets.items()},
|
||||
'current_wallet': current_wallet_path,
|
||||
'fee_per_kb': self.config.fee_per_kb(),
|
||||
}
|
||||
else:
|
||||
response = "Daemon offline"
|
||||
elif sub == 'stop':
|
||||
self.stop()
|
||||
response = "Daemon stopped"
|
||||
|
@ -382,7 +343,7 @@ class Daemon(Logger):
|
|||
path = standardize_path(path)
|
||||
wallet = self.wallets.get(path)
|
||||
if wallet is None:
|
||||
return {'error': 'Wallet "%s" is not loaded. Use "electrum daemon load_wallet"'%os.path.basename(path) }
|
||||
return {'error': 'Wallet "%s" is not loaded. Use "electrum load_wallet"'%os.path.basename(path) }
|
||||
else:
|
||||
wallet = None
|
||||
# arguments passed to function
|
||||
|
@ -393,7 +354,7 @@ class Daemon(Logger):
|
|||
kwargs = {}
|
||||
for x in cmd.options:
|
||||
kwargs[x] = (config_options.get(x) if x in ['password', 'new_password'] else config.get(x))
|
||||
cmd_runner = Commands(config, wallet, self.network)
|
||||
cmd_runner = Commands(config, wallet, self.network, self)
|
||||
func = getattr(cmd_runner, cmd.name)
|
||||
try:
|
||||
result = await func(*args, **kwargs)
|
||||
|
|
|
@ -43,8 +43,11 @@ if [[ $1 == "init" ]]; then
|
|||
$bob create > /dev/null
|
||||
$carol create > /dev/null
|
||||
$alice setconfig log_to_file True
|
||||
$bob setconfig log_to_file True
|
||||
$bob setconfig log_to_file True
|
||||
$carol setconfig log_to_file True
|
||||
$alice setconfig server 127.0.0.1:51001:t
|
||||
$bob setconfig server 127.0.0.1:51001:t
|
||||
$carol setconfig server 127.0.0.1:51001:t
|
||||
$bob setconfig lightning_listen localhost:9735
|
||||
$bob setconfig lightning_forward_payments true
|
||||
echo "funding alice and carol"
|
||||
|
@ -55,20 +58,20 @@ fi
|
|||
|
||||
# start daemons. Bob is started first because he is listening
|
||||
if [[ $1 == "start" ]]; then
|
||||
$bob daemon -s 127.0.0.1:51001:t start
|
||||
$alice daemon -s 127.0.0.1:51001:t start
|
||||
$carol daemon -s 127.0.0.1:51001:t start
|
||||
$bob daemon start
|
||||
$alice daemon start
|
||||
$carol daemon start
|
||||
sleep 1 # time to accept commands
|
||||
$bob daemon load_wallet
|
||||
$alice daemon load_wallet
|
||||
$carol daemon load_wallet
|
||||
$bob load_wallet
|
||||
$alice load_wallet
|
||||
$carol load_wallet
|
||||
sleep 10 # give time to synchronize
|
||||
fi
|
||||
|
||||
if [[ $1 == "stop" ]]; then
|
||||
$alice daemon stop || true
|
||||
$bob daemon stop || true
|
||||
$carol daemon stop || true
|
||||
$alice stop || true
|
||||
$bob stop || true
|
||||
$carol stop || true
|
||||
fi
|
||||
|
||||
if [[ $1 == "open" ]]; then
|
||||
|
@ -129,10 +132,10 @@ if [[ $1 == "breach" ]]; then
|
|||
fi
|
||||
|
||||
if [[ $1 == "redeem_htlcs" ]]; then
|
||||
$bob daemon stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=10 $bob daemon -s 127.0.0.1:51001:t start
|
||||
$bob stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=10 $bob daemon start
|
||||
sleep 1
|
||||
$bob daemon load_wallet
|
||||
$bob load_wallet
|
||||
sleep 1
|
||||
# alice opens channel
|
||||
bob_node=$($bob nodeid)
|
||||
|
@ -149,7 +152,7 @@ if [[ $1 == "redeem_htlcs" ]]; then
|
|||
exit 1
|
||||
fi
|
||||
# bob goes away
|
||||
$bob daemon stop
|
||||
$bob stop
|
||||
echo "alice balance before closing channel:" $($alice getbalance)
|
||||
balance_before=$($alice getbalance | jq '[.confirmed, .unconfirmed, .lightning] | to_entries | map(select(.value != null).value) | map(tonumber) | add ')
|
||||
# alice force closes the channel
|
||||
|
@ -177,10 +180,10 @@ fi
|
|||
|
||||
|
||||
if [[ $1 == "breach_with_unspent_htlc" ]]; then
|
||||
$bob daemon stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=3 $bob daemon -s 127.0.0.1:51001:t start
|
||||
$bob stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=3 $bob daemon start
|
||||
sleep 1
|
||||
$bob daemon load_wallet
|
||||
$bob load_wallet
|
||||
wait_until_funded
|
||||
echo "alice opens channel"
|
||||
bob_node=$($bob nodeid)
|
||||
|
@ -205,24 +208,24 @@ if [[ $1 == "breach_with_unspent_htlc" ]]; then
|
|||
echo $($bob getbalance)
|
||||
echo "alice breaches with old ctx"
|
||||
echo $ctx
|
||||
height1=$($bob daemon status | jq '.blockchain_height')
|
||||
height1=$($bob getinfo | jq '.blockchain_height')
|
||||
$bitcoin_cli sendrawtransaction $ctx
|
||||
new_blocks 1
|
||||
# wait until breach is confirmed
|
||||
while height2=$($bob daemon status | jq '.blockchain_height') && [ $(($height2 - $height1)) -ne 1 ]; do
|
||||
while height2=$($bob getinfo | jq '.blockchain_height') && [ $(($height2 - $height1)) -ne 1 ]; do
|
||||
echo "waiting for block"
|
||||
sleep 1
|
||||
done
|
||||
new_blocks 1
|
||||
# wait until next block is confirmed, so that htlc tx and redeem tx are confirmed too
|
||||
while height3=$($bob daemon status | jq '.blockchain_height') && [ $(($height3 - $height2)) -ne 1 ]; do
|
||||
while height3=$($bob getinfo | jq '.blockchain_height') && [ $(($height3 - $height2)) -ne 1 ]; do
|
||||
echo "waiting for block"
|
||||
sleep 1
|
||||
done
|
||||
# wait until wallet is synchronized
|
||||
while b=$($bob daemon status | jq '.wallets | ."/tmp/bob/regtest/wallets/default_wallet"') && [ "$b" != "true" ]; do
|
||||
echo "waiting for wallet sync $b"
|
||||
sleep 1
|
||||
while b=$($bob list_wallets | jq '.[0]|.synchronized') && [ "$b" != "true" ]; do
|
||||
echo "waiting for wallet sync: $b"
|
||||
sleep 1
|
||||
done
|
||||
echo $($bob getbalance)
|
||||
balance_after=$($bob getbalance | jq '[.confirmed, .unconfirmed] | to_entries | map(select(.value != null).value) | map(tonumber) | add ')
|
||||
|
@ -234,10 +237,10 @@ fi
|
|||
|
||||
|
||||
if [[ $1 == "breach_with_spent_htlc" ]]; then
|
||||
$bob daemon stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=3 $bob daemon -s 127.0.0.1:51001:t start
|
||||
$bob stop
|
||||
ELECTRUM_DEBUG_LIGHTNING_SETTLE_DELAY=3 $bob daemon start
|
||||
sleep 1
|
||||
$bob daemon load_wallet
|
||||
$bob load_wallet
|
||||
wait_until_funded
|
||||
echo "alice opens channel"
|
||||
bob_node=$($bob nodeid)
|
||||
|
@ -262,7 +265,7 @@ if [[ $1 == "breach_with_spent_htlc" ]]; then
|
|||
fi
|
||||
echo $($bob getbalance)
|
||||
echo "bob goes offline"
|
||||
$bob daemon stop
|
||||
$bob stop
|
||||
ctx_id=$($bitcoin_cli sendrawtransaction $ctx)
|
||||
echo "alice breaches with old ctx:" $ctx_id
|
||||
new_blocks 1
|
||||
|
@ -275,11 +278,11 @@ if [[ $1 == "breach_with_spent_htlc" ]]; then
|
|||
# (to_local needs to_self_delay blocks; htlc needs whatever we put in invoice)
|
||||
new_blocks 150
|
||||
echo "alice spends to_local and htlc outputs"
|
||||
$alice daemon stop
|
||||
$alice stop
|
||||
cp /tmp/alice/regtest/wallets/toxic_wallet /tmp/alice/regtest/wallets/default_wallet
|
||||
$alice daemon -s 127.0.0.1:51001:t start
|
||||
$alice daemon start
|
||||
sleep 1
|
||||
$alice daemon load_wallet
|
||||
$alice load_wallet
|
||||
# wait until alice has spent both ctx outputs
|
||||
while [[ $($bitcoin_cli gettxout $ctx_id 0) ]]; do
|
||||
echo "waiting until alice spends ctx outputs"
|
||||
|
@ -291,9 +294,9 @@ if [[ $1 == "breach_with_spent_htlc" ]]; then
|
|||
done
|
||||
new_blocks 1
|
||||
echo "bob comes back"
|
||||
$bob daemon -s 127.0.0.1:51001:t start
|
||||
$bob daemon start
|
||||
sleep 1
|
||||
$bob daemon load_wallet
|
||||
$bob load_wallet
|
||||
while [[ $($bitcoin_cli getmempoolinfo | jq '.size') != "1" ]]; do
|
||||
echo "waiting for bob's transaction"
|
||||
sleep 1
|
||||
|
@ -311,15 +314,15 @@ fi
|
|||
|
||||
if [[ $1 == "watchtower" ]]; then
|
||||
# carol is a watchtower of alice
|
||||
$alice daemon stop
|
||||
$carol daemon stop
|
||||
$alice stop
|
||||
$carol stop
|
||||
$alice setconfig watchtower_url http://127.0.0.1:12345
|
||||
$carol setconfig watchtower_host 127.0.0.1
|
||||
$carol setconfig watchtower_port 12345
|
||||
$carol daemon -s 127.0.0.1:51001:t start
|
||||
$alice daemon -s 127.0.0.1:51001:t start
|
||||
$carol daemon start
|
||||
$alice daemon start
|
||||
sleep 1
|
||||
$alice daemon load_wallet
|
||||
$alice load_wallet
|
||||
echo "waiting until alice funded"
|
||||
wait_until_funded
|
||||
echo "alice opens channel"
|
||||
|
|
|
@ -159,8 +159,9 @@ def init_cmdline(config_options, server):
|
|||
print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.")
|
||||
|
||||
# commands needing password
|
||||
if (cmd.requires_wallet and storage.is_encrypted() and server is False)\
|
||||
or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())):
|
||||
if ( (cmd.requires_wallet and storage.is_encrypted() and server is False)\
|
||||
or (cmdname == 'load_wallet' and storage.is_encrypted())\
|
||||
or (cmd.requires_password and (storage.is_encrypted() or storage.get('use_encryption')))):
|
||||
if storage.is_encrypted_with_hw_device():
|
||||
# this case is handled later in the control flow
|
||||
password = None
|
||||
|
@ -392,9 +393,6 @@ if __name__ == '__main__':
|
|||
|
||||
elif cmdname == 'daemon':
|
||||
|
||||
if subcommand in ['load_wallet']:
|
||||
init_daemon(config_options)
|
||||
|
||||
if subcommand in [None, 'start']:
|
||||
configure_logging(config)
|
||||
fd = daemon.get_file_descriptor(config)
|
||||
|
|
Loading…
Add table
Reference in a new issue