mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-28 16:01:30 +00:00
remote watchtower: initial commit
This commit is contained in:
parent
786ead4d83
commit
bdb54ef8ca
3 changed files with 67 additions and 11 deletions
|
@ -33,7 +33,7 @@ from typing import Dict, Optional, Tuple
|
|||
|
||||
import jsonrpclib
|
||||
|
||||
from .jsonrpc import VerifyingJSONRPCServer
|
||||
from .jsonrpc import SimpleJSONRPCServer, PasswordProtectedJSONRPCServer
|
||||
from .version import ELECTRUM_VERSION
|
||||
from .network import Network
|
||||
from .util import (json_decode, DaemonThread, print_error, to_string,
|
||||
|
@ -141,6 +141,8 @@ class Daemon(DaemonThread):
|
|||
self.server = None
|
||||
if listen_jsonrpc:
|
||||
self.init_server(config, fd)
|
||||
if config.get('watchtower_host'):
|
||||
self.init_watchtower()
|
||||
self.start()
|
||||
|
||||
def init_server(self, config: SimpleConfig, fd):
|
||||
|
@ -148,7 +150,8 @@ class Daemon(DaemonThread):
|
|||
port = config.get('rpcport', 0)
|
||||
rpc_user, rpc_password = get_rpc_credentials(config)
|
||||
try:
|
||||
server = VerifyingJSONRPCServer((host, port), logRequests=False,
|
||||
server = PasswordProtectedJSONRPCServer(
|
||||
(host, port), logRequests=False,
|
||||
rpc_user=rpc_user, rpc_password=rpc_password)
|
||||
except Exception as e:
|
||||
self.print_error('Warning: cannot initialize RPC server on host', host, e)
|
||||
|
@ -167,6 +170,12 @@ class Daemon(DaemonThread):
|
|||
server.register_function(getattr(self.cmd_runner, cmdname), cmdname)
|
||||
server.register_function(self.run_cmdline, 'run_cmdline')
|
||||
|
||||
def init_watchtower(self):
|
||||
host = self.config.get('watchtower_host')
|
||||
port = self.config.get('watchtower_port', 12345)
|
||||
server = SimpleJSONRPCServer((host, port), logRequests=False)
|
||||
server.register_function(self.network.lnwatcher, 'add_sweep_tx')
|
||||
|
||||
def ping(self):
|
||||
return True
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Electrum - lightweight Bitcoin client
|
||||
|
@ -47,13 +48,9 @@ class RPCAuthUnsupportedType(Exception):
|
|||
|
||||
|
||||
# based on http://acooke.org/cute/BasicHTTPA0.html by andrew cooke
|
||||
class VerifyingJSONRPCServer(SimpleJSONRPCServer):
|
||||
|
||||
def __init__(self, *args, rpc_user, rpc_password, **kargs):
|
||||
|
||||
self.rpc_user = rpc_user
|
||||
self.rpc_password = rpc_password
|
||||
class AuthenticatedJSONRPCServer(SimpleJSONRPCServer):
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
class VerifyingRequestHandler(SimpleJSONRPCRequestHandler):
|
||||
def parse_request(myself):
|
||||
# first, call the original implementation which returns
|
||||
|
@ -73,10 +70,20 @@ class VerifyingJSONRPCServer(SimpleJSONRPCServer):
|
|||
traceback.print_exc(file=sys.stderr)
|
||||
myself.send_error(500, str(e))
|
||||
return False
|
||||
|
||||
SimpleJSONRPCServer.__init__(
|
||||
self, requestHandler=VerifyingRequestHandler, *args, **kargs)
|
||||
|
||||
def authenticate(self, headers):
|
||||
raise Exception('undefined')
|
||||
|
||||
|
||||
class PasswordProtectedJSONRPCServer(AuthenticatedJSONRPCServer):
|
||||
|
||||
def __init__(self, *args, rpc_user, rpc_password, **kargs):
|
||||
self.rpc_user = rpc_user
|
||||
self.rpc_password = rpc_password
|
||||
AuthenticatedJSONRPCServer.__init__(self, *args, **kargs)
|
||||
|
||||
def authenticate(self, headers):
|
||||
if self.rpc_password == '':
|
||||
# RPC authentication is disabled
|
||||
|
@ -97,3 +104,21 @@ class VerifyingJSONRPCServer(SimpleJSONRPCServer):
|
|||
and util.constant_time_compare(password, self.rpc_password)):
|
||||
time.sleep(0.050)
|
||||
raise RPCAuthCredentialsInvalid()
|
||||
|
||||
|
||||
class AccountsJSONRPCServer(AuthenticatedJSONRPCServer):
|
||||
""" user accounts """
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
self.users = {}
|
||||
AuthenticatedJSONRPCServer.__init__(self, *args, **kargs)
|
||||
self.register_function(self.add_user, 'add_user')
|
||||
|
||||
def authenticate(self, headers):
|
||||
# todo: verify signature
|
||||
return
|
||||
|
||||
def add_user(self, pubkey):
|
||||
user_id = len(self.users)
|
||||
self.users[user_id] = pubkey
|
||||
return user_id
|
||||
|
|
|
@ -2,6 +2,8 @@ import threading
|
|||
from typing import NamedTuple, Iterable
|
||||
import os
|
||||
from collections import defaultdict
|
||||
import asyncio
|
||||
import jsonrpclib
|
||||
|
||||
from .util import PrintError, bh2u, bfh, NoDynamicFeeEstimates, aiosafe
|
||||
from .lnutil import EncumberedTransaction, Outpoint
|
||||
|
@ -20,7 +22,7 @@ class LNWatcher(PrintError):
|
|||
|
||||
def __init__(self, network):
|
||||
self.network = network
|
||||
|
||||
self.config = network.config
|
||||
path = os.path.join(network.config.path, "watcher_db")
|
||||
storage = WalletStorage(path)
|
||||
self.addr_sync = AddressSynchronizer(storage)
|
||||
|
@ -41,6 +43,25 @@ class LNWatcher(PrintError):
|
|||
|
||||
self.network.register_callback(self.on_network_update,
|
||||
['network_updated', 'blockchain_updated', 'verified', 'wallet_updated'])
|
||||
# remote watchtower
|
||||
watchtower_url = self.config.get('watchtower_url')
|
||||
self.watchtower = jsonrpclib.Server(watchtower_url) if watchtower_url else None
|
||||
self.watchtower_queue = asyncio.Queue()
|
||||
asyncio.run_coroutine_threadsafe(self.watchtower_task(), self.network.asyncio_loop)
|
||||
|
||||
def with_watchtower(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if self.watchtower:
|
||||
self.watchtower_queue.put_nowait((func.__name__, args, kwargs))
|
||||
return func(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
async def watchtower_task(self):
|
||||
while True:
|
||||
name, args, kwargs = await self.watchtower_queue.get()
|
||||
self.print_error('sending to watchtower', name, args)
|
||||
func = getattr(self.watchtower, name)
|
||||
func(*args, **kwargs)
|
||||
|
||||
def write_to_disk(self):
|
||||
# FIXME: json => every update takes linear instead of constant disk write
|
||||
|
@ -151,6 +172,7 @@ class LNWatcher(PrintError):
|
|||
.format(num_conf, e_tx.csv_delay, funding_outpoint, ctx.txid()))
|
||||
return keep_watching_this
|
||||
|
||||
@with_watchtower
|
||||
def add_sweep_tx(self, funding_outpoint: str, ctx_txid: str, encumbered_sweeptx: EncumberedTransaction):
|
||||
if encumbered_sweeptx is None:
|
||||
return
|
||||
|
|
Loading…
Add table
Reference in a new issue