commit 9cfeadea706dbbb46b1a4ab7b38ec11a4f527669
parent 4397767a5e1686da719dc1dcc04572f4bdbbfc70
Author: ThomasV <thomasv@electrum.org>
Date: Mon, 19 Aug 2019 12:46:31 +0200
Turn daemon subcommands into RPCs
Diffstat:
4 files changed, 106 insertions(+), 87 deletions(-)
diff --git a/electrum/commands.py b/electrum/commands.py
@@ -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.
diff --git a/electrum/daemon.py b/electrum/daemon.py
@@ -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)
diff --git a/electrum/tests/regtest/regtest.sh b/electrum/tests/regtest/regtest.sh
@@ -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"
diff --git a/run_electrum b/run_electrum
@@ -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)