diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index 59a092051897..dc57215668aa 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -15,6 +15,7 @@ sudo apt-get -qq install --no-install-recommends --allow-unauthenticated -yy \ build-essential \ clang \ cppcheck \ + curl \ docbook-xml \ eatmydata \ gcc-aarch64-linux-gnu \ diff --git a/CHANGELOG.md b/CHANGELOG.md index e1910f5048d8..be0bef790d11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## [v23.11rc2] - 2023-11-02: "Bitcoin Orangepaper" +## [v23.11rc3] - 2023-11-02: "Bitcoin Orangepaper" This release named by Shahana Farooqui @@ -74,6 +74,8 @@ Note: You should always set `allow-deprecated-apis=false` to test for changes. - Protocol: Implemented splicing restart logic for tx_signature and commitment_signed. Splice commitments are reworked in a manner incompatible with the last version. ([#6840]) - Wallet: close change outputs show up immediately in `listfunds` so you can CPFP. ([#6734]) - Restore any missing metadata that resource constrained signers stripped ([#6767]) + - JSON-RPC: Plugin notification `msat` fields in `invoice_payment` and `invoice_created` hooks now a number, not a string with "msat" suffix. ([#6884]) + - JSON-RPC: Plugin hook `payment` `msat` field is now a number, not a string with "msat" suffix. ([#6884]) - JSON-RPC: fix `checkrune` when `method` parameter is the empty string. ([#6759]) - JSON-RPC: `getroute` now documents that it ignores `fuzzpercent`. ([#6697]) - Rune: use runes table `id` instead `runes_uniqueid` from `vars` because it returns incorrect unique id if rune/s migrated from datastore. ([#6715]) @@ -122,6 +124,7 @@ Note: You should always set `allow-deprecated-apis=false` to test for changes. [#6857]: https://github.com/ElementsProject/lightning/pull/6857 [#6876]: https://github.com/ElementsProject/lightning/pull/6876 [#6840]: https://github.com/ElementsProject/lightning/pull/6840 +[#6884]: https://github.com/ElementsProject/lightning/pull/6884 ## [23.08.1] - 2023-09-12: "Satoshi's Successor II" diff --git a/Makefile b/Makefile index fd2b38e41546..7ce942db0cbb 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ COMPAT_CFLAGS=-DCOMPAT_V052=1 -DCOMPAT_V060=1 -DCOMPAT_V061=1 -DCOMPAT_V062=1 -D endif # (method=thread to support xdist) -PYTEST_OPTS := -v -p no:logging $(PYTEST_OPTS) +PYTEST_OPTS := -v -p no:logging $(PYTEST_OPTS) $(PYTEST_MOREOPTS) MY_CHECK_PYTHONPATH=$${PYTHONPATH}$${PYTHONPATH:+:}$(shell pwd)/contrib/pyln-client:$(shell pwd)/contrib/pyln-testing:$(shell pwd)/contrib/pyln-proto/:$(shell pwd)/external/lnprototest:$(shell pwd)/contrib/pyln-spec/bolt1:$(shell pwd)/contrib/pyln-spec/bolt2:$(shell pwd)/contrib/pyln-spec/bolt4:$(shell pwd)/contrib/pyln-spec/bolt7 # Collect generated python files to be excluded from lint checks PYTHON_GENERATED= \ diff --git a/common/json_stream.c b/common/json_stream.c index 24ccf1291e20..59c7e895765c 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -614,7 +614,7 @@ void json_add_amount_msat(struct json_stream *result, const char *msatfieldname, struct amount_msat msat) { - assert(strends(msatfieldname, "_msat")); + assert(strends(msatfieldname, "_msat") || streq(msatfieldname, "msat")); json_add_u64(result, msatfieldname, msat.millisatoshis); /* Raw: low-level helper */ } diff --git a/common/utils.h b/common/utils.h index 982492245d0f..3b37661a153d 100644 --- a/common/utils.h +++ b/common/utils.h @@ -136,7 +136,7 @@ extern const tal_t *wally_tal_ctx; /* Like mkstemp but resolves template relative to $TMPDIR (or /tmp if unset). * Returns created temporary path name at *created if successful. */ -int tmpdir_mkstemp(const tal_t *ctx, const char *template TAKES, char **created); +int tmpdir_mkstemp(const tal_t *ctx, const char *tmplt TAKES, char **created); /** * tal_strlowering - return the same string by in lower case. diff --git a/contrib/pyln-testing/pyln/testing/fixtures.py b/contrib/pyln-testing/pyln/testing/fixtures.py index 4bfce3578d1d..17a7ec27a69e 100644 --- a/contrib/pyln-testing/pyln/testing/fixtures.py +++ b/contrib/pyln-testing/pyln/testing/fixtures.py @@ -1,6 +1,6 @@ from concurrent import futures from pyln.testing.db import SqliteDbProvider, PostgresDbProvider -from pyln.testing.utils import NodeFactory, BitcoinD, ElementsD, env, LightningNode, TEST_DEBUG +from pyln.testing.utils import NodeFactory, BitcoinD, ElementsD, env, LightningNode, TEST_DEBUG, LssD from pyln.client import Millisatoshi from typing import Dict @@ -31,6 +31,9 @@ def test_base_dir(): yield directory + if bool(int(os.getenv('TEST_KEEPDIR', '0'))): + return + # Now check if any test directory is left because the corresponding test # failed. If there are no such tests we can clean up the root test # directory. @@ -92,7 +95,7 @@ def directory(request, test_base_dir, test_name): outcome = 'passed' if rep_call is None else rep_call.outcome failed = not outcome or request.node.has_errors or outcome != 'passed' - if not failed: + if not failed and not bool(int(os.getenv('TEST_KEEPDIR', '0'))): try: shutil.rmtree(directory) except OSError: @@ -164,6 +167,25 @@ def bitcoind(directory, teardown_checks): bitcoind.proc.wait() +@pytest.fixture +def lssd(directory, teardown_checks): + lssd = LssD(directory) + + try: + lssd.start() + except Exception: + lssd.stop() + raise + + yield lssd + + try: + lssd.stop() + except Exception: + lssd.proc.kill() + lssd.proc.wait() + + class TeardownErrors(object): def __init__(self): self.errors = [] @@ -446,11 +468,12 @@ def jsonschemas(): @pytest.fixture -def node_factory(request, directory, test_name, bitcoind, executor, db_provider, teardown_checks, node_cls, jsonschemas): +def node_factory(request, directory, test_name, bitcoind, lssd, executor, db_provider, teardown_checks, node_cls, jsonschemas): nf = NodeFactory( request, test_name, bitcoind, + lssd, executor, directory=directory, db_provider=db_provider, diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 7f39637d2c76..5fca522c2829 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -78,6 +78,7 @@ def env(name, default=None): SLOW_MACHINE = env("SLOW_MACHINE", "0") == "1" DEPRECATED_APIS = env("DEPRECATED_APIS", "0") == "1" TIMEOUT = int(env("TIMEOUT", 180 if SLOW_MACHINE else 60)) +SUBDAEMON = env("SUBDAEMON", "") EXPERIMENTAL_DUAL_FUND = env("EXPERIMENTAL_DUAL_FUND", "0") == "1" EXPERIMENTAL_SPLICING = env("EXPERIMENTAL_SPLICING", "0") == "1" @@ -383,6 +384,45 @@ def f(*args): return f +class LssD(TailableProc): + def __init__(self, directory, rpcport=None): + lss_dir = os.path.join(directory, 'lss') + TailableProc.__init__(self, lss_dir, verbose=False) + + if rpcport is None: + self.reserved_rpcport = reserve_unused_port() + rpcport = self.reserved_rpcport + else: + self.reserved_rpcport = None + + self.rpcport = rpcport + self.prefix = 'lss' + + if not os.path.exists(lss_dir): + os.makedirs(lss_dir) + + self.cmd_line = [ + 'lssd', + '--datadir={}'.format(lss_dir), + '--port={}'.format(rpcport), + ] + + def __del__(self): + if self.reserved_rpcport is not None: + drop_unused_port(self.reserved_rpcport) + + def start(self): + self.env['RUST_LOG'] = 'debug' + TailableProc.start(self) + self.wait_for_log("ready on", timeout=TIMEOUT) + + logging.info("LssD started") + + def stop(self): + logging.info("Stopping LssD") + return TailableProc.stop(self) + + class BitcoinD(TailableProc): def __init__(self, bitcoin_dir="/tmp/bitcoind-test", rpcport=None): @@ -578,11 +618,49 @@ def getnewaddress(self): return info['unconfidential'] +class ValidatingLightningSignerD(TailableProc): + def __init__(self, vlsd_dir, vlsd_port, node_id, network): + TailableProc.__init__(self, vlsd_dir, verbose=True) + self.executable = env("REMOTE_SIGNER_CMD", 'vlsd2') + os.environ['ALLOWLIST'] = env( + 'REMOTE_SIGNER_ALLOWLIST', + 'contrib/remote_hsmd/TESTING_ALLOWLIST') + self.opts = [ + '--network={}'.format(network), + '--datadir={}'.format(vlsd_dir), + '--connect=http://localhost:{}'.format(vlsd_port), + '--integration-test', + ] + self.prefix = 'vlsd2-%d' % (node_id) + self.vlsd_port = vlsd_port + + @property + def cmd_line(self): + return [self.executable] + self.opts + + def start(self, stdin=None, stdout_redir=True, stderr_redir=True, + wait_for_initialized=True): + TailableProc.start(self, stdin, stdout_redir, stderr_redir) + # We need to always wait for initialization + self.wait_for_log("vlsd2 git_desc") + logging.info("vlsd2 started") + + def stop(self, timeout=10): + logging.info("stopping vlsd2") + rc = TailableProc.stop(self, timeout) + logging.info("vlsd2 stopped") + self.logs_catchup() + return rc + + def __del__(self): + self.logs_catchup() + class LightningD(TailableProc): def __init__( self, lightning_dir, bitcoindproxy, + lssd_port, port=9735, random_hsm=False, node_id=0, @@ -594,9 +672,16 @@ def __init__( self.lightning_dir = lightning_dir self.port = port self.cmd_prefix = [] + self.lightning_dir = lightning_dir + self.use_vlsd = False + self.vlsd_dir = os.path.join(lightning_dir, "vlsd") + self.vlsd_port = None + self.vlsd = None + self.node_id = node_id self.rpcproxy = bitcoindproxy self.env['CLN_PLUGIN_LOG'] = "cln_plugin=trace,cln_rpc=trace,cln_grpc=trace,debug" + self.lssd_port = lssd_port self.opts = LIGHTNINGD_CONFIG.copy() opts = { @@ -616,12 +701,38 @@ def __init__( if grpc_port is not None: opts['grpc-port'] = grpc_port + if SUBDAEMON: + assert node_id > 0 + subdaemons = SUBDAEMON.split(',') + # VLS_SERIAL_SELECT "swaps" the selected item with the first item + select = env("VLS_SERIAL_SELECT", '1') + if node_id == int(select): + ndx = 1 + elif node_id == 1: + ndx = int(select) + else: + ndx = node_id + if ndx > len(subdaemons): + # use the last element if not as many specifiers as nodes + opts['subdaemon'] = subdaemons[-1] + else: + # use the matching specifier + opts['subdaemon'] = subdaemons[ndx - 1] + + print(f"starting node {node_id} with subdaemon {opts['subdaemon']}") + if SUBDAEMON == 'hsmd:remote_hsmd_socket': + self.use_vlsd = True + for k, v in opts.items(): self.opts[k] = v if not os.path.exists(os.path.join(lightning_dir, TEST_NETWORK)): os.makedirs(os.path.join(lightning_dir, TEST_NETWORK)) + if self.use_vlsd: + if not os.path.exists(self.vlsd_dir): + os.makedirs(self.vlsd_dir) + # Last 32-bytes of final part of dir -> seed. seed = (bytes(re.search('([^/]+)/*$', lightning_dir).group(1), encoding='utf-8') + bytes(32))[:32] if not random_hsm: @@ -637,6 +748,10 @@ def __init__( self.early_opts = ['--developer'] def cleanup(self): + if self.use_vlsd: + # Make sure the remotesigner is shutdown + self.vlsd.stop() + # To force blackhole to exit, disconnect file must be truncated! if 'dev-disconnect' in self.opts: with open(self.opts['dev-disconnect'], "w") as f: @@ -657,12 +772,65 @@ def cmd_line(self): return self.cmd_prefix + [self.executable] + self.early_opts + opts + def __del__(self): + if self.vlsd_port is not None: + drop_unused_port(self.vlsd_port) + def start(self, stdin=None, wait_for_initialized=True, stderr_redir=False): - self.opts['bitcoin-rpcport'] = self.rpcproxy.rpcport - TailableProc.start(self, stdin, stdout_redir=False, stderr_redir=stderr_redir) - if wait_for_initialized: - self.wait_for_log("Server started with public key") - logging.info("LightningD started") + try: + self.env['VLS_LSS'] = f"http://localhost:{self.lssd_port}" + self.env['RUST_LOG'] = 'debug' + # Some of the remote hsmd proxies need a bitcoind RPC connection + self.env['BITCOIND_RPC_URL'] = 'http://{}:{}@localhost:{}'.format( + BITCOIND_CONFIG['rpcuser'], + BITCOIND_CONFIG['rpcpassword'], + BITCOIND_CONFIG['rpcport']) + + # The remote hsmd proxies need to know which network we are using + if 'network' in self.opts: + self.env['VLS_NETWORK'] = self.opts['network'] + + self.opts['bitcoin-rpcport'] = self.rpcproxy.rpcport + + if self.use_vlsd: + self.vlsd_port = reserve_unused_port() + # We can't do this in the constructor because we need a new port on each restart. + self.env['VLS_PORT'] = str(self.vlsd_port) + # Kill any previous vlsd (we may have been restarted) + if self.vlsd is not None: + logging.info("killing prior vlsd") + self.vlsd.kill() + + TailableProc.start(self, stdin, stdout_redir=False, stderr_redir=stderr_redir) + + if self.use_vlsd: + # Start the remote signer first + self.vlsd = ValidatingLightningSignerD( + self.vlsd_dir, self.vlsd_port, self.node_id, self.opts['network']) + self.vlsd.start( + stdin, stdout_redir=True, stderr_redir=True, + wait_for_initialized=wait_for_initialized) + + if wait_for_initialized: + self.wait_for_log("Server started with public key") + logging.info("LightningD started") + except Exception: + if self.use_vlsd: + # LightningD didn't start, stop the remotesigner + self.vlsd.stop() + raise + + def stop(self, timeout=10): + if self.use_vlsd: + # Stop the remote signer first + self.vlsd.stop(timeout) + return TailableProc.stop(self, timeout) + + def kill(self): + if self.use_vlsd: + # Kill the remote signer first + self.vlsd.kill() + TailableProc.kill(self) def wait(self, timeout=TIMEOUT): """Wait for the daemon to stop for up to timeout seconds @@ -745,7 +913,7 @@ def call(self, method, payload=None, cmdprefix=None, filter=None): class LightningNode(object): - def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fail=False, + def __init__(self, node_id, lightning_dir, bitcoind, lssd, executor, valgrind, may_fail=False, may_reconnect=False, allow_broken_log=False, allow_warning=False, @@ -755,6 +923,7 @@ def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fai valgrind_plugins=True, **kwargs): self.bitcoin = bitcoind + self.lssd = lssd self.executor = executor self.may_fail = may_fail self.may_reconnect = may_reconnect @@ -774,6 +943,7 @@ def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fai self.daemon = LightningD( lightning_dir, bitcoindproxy=bitcoind.get_proxy(), + lssd_port=lssd.rpcport, port=port, random_hsm=random_hsm, node_id=node_id, grpc_port=self.grpc_port, ) @@ -1222,6 +1392,9 @@ def pay(self, dst, amt, label=None, route=False): 'channel': scid } + # let the signer know this payment is coming + self.rpc.preapproveinvoice(bolt11=inv['bolt11']) + # sendpay is async now self.rpc.sendpay([routestep], rhash, payment_secret=psecret, bolt11=inv['bolt11']) # wait for sendpay to comply @@ -1478,7 +1651,7 @@ def flock(directory: Path): class NodeFactory(object): """A factory to setup and start `lightningd` daemons. """ - def __init__(self, request, testname, bitcoind, executor, directory, + def __init__(self, request, testname, bitcoind, lssd, executor, directory, db_provider, node_cls, jsonschemas): if request.node.get_closest_marker("slow_test") and SLOW_MACHINE: self.valgrind = False @@ -1490,6 +1663,7 @@ def __init__(self, request, testname, bitcoind, executor, directory, self.reserved_ports = [] self.executor = executor self.bitcoind = bitcoind + self.lssd = lssd self.directory = directory self.lock = threading.Lock() self.db_provider = db_provider @@ -1575,7 +1749,7 @@ def get_node(self, node_id=None, options=None, dbfile=None, db = self.db_provider.get_db(os.path.join(lightning_dir, TEST_NETWORK), self.testname, node_id) db.provider = self.db_provider node = self.node_cls( - node_id, lightning_dir, self.bitcoind, self.executor, self.valgrind, db=db, + node_id, lightning_dir, self.bitcoind, self.lssd, self.executor, self.valgrind, db=db, port=port, options=options, may_fail=may_fail or expect_fail, jsonschemas=self.jsonschemas, **kwargs diff --git a/lightningd/.gitignore b/lightningd/.gitignore index 4ba7a1a9cec2..576e635ee243 100644 --- a/lightningd/.gitignore +++ b/lightningd/.gitignore @@ -8,3 +8,5 @@ lightning_hsmd lightning_onchaind lightning_openingd lightning_websocketd +remote_hsmd_serial +remote_hsmd_socket diff --git a/lightningd/invoice.c b/lightningd/invoice.c index cf240e628b43..25df0a172bfc 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -223,9 +223,7 @@ invoice_payment_serialize(struct invoice_payment_hook_payload *payload, json_object_start(stream, "payment"); json_add_escaped_string(stream, "label", payload->label); json_add_preimage(stream, "preimage", &payload->preimage); - json_add_string(stream, "msat", - type_to_string(tmpctx, struct amount_msat, - &payload->msat)); + json_add_amount_msat(stream, "msat", payload->msat); if (payload->ld->developer && payload->set) invoice_payment_add_tlvs(stream, payload->set); diff --git a/lightningd/notification.c b/lightningd/notification.c index 9893bac93230..bbefa48fff56 100644 --- a/lightningd/notification.c +++ b/lightningd/notification.c @@ -165,8 +165,7 @@ static void invoice_payment_notification_serialize(struct json_stream *stream, const struct bitcoin_outpoint *outpoint) { json_object_start(stream, "invoice_payment"); - json_add_string(stream, "msat", - type_to_string(tmpctx, struct amount_msat, &amount)); + json_add_amount_msat(stream, "msat", amount); json_add_hex(stream, "preimage", &preimage, sizeof(preimage)); if (outpoint) json_add_outpoint(stream, "outpoint", outpoint); @@ -201,9 +200,7 @@ static void invoice_creation_notification_serialize(struct json_stream *stream, { json_object_start(stream, "invoice_creation"); if (amount != NULL) - json_add_string( - stream, "msat", - type_to_string(tmpctx, struct amount_msat, amount)); + json_add_amount_msat(stream, "msat", *amount); json_add_hex(stream, "preimage", &preimage, sizeof(preimage)); json_add_escaped_string(stream, "label", label); diff --git a/plugins/clnrest/clnrest.py b/plugins/clnrest/clnrest.py index 9da124e513d3..c2febea7f080 100755 --- a/plugins/clnrest/clnrest.py +++ b/plugins/clnrest/clnrest.py @@ -26,6 +26,7 @@ except ModuleNotFoundError as err: # OK, something is not installed? import json + import sys getmanifest = json.loads(sys.stdin.readline()) print(json.dumps({'jsonrpc': "2.0", 'id': getmanifest['id'], diff --git a/tests/fixtures.py b/tests/fixtures.py index ea23f10ad0a9..d9a6874080f6 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -1,5 +1,5 @@ from utils import TEST_NETWORK, VALGRIND # noqa: F401,F403 -from pyln.testing.fixtures import directory, test_base_dir, test_name, chainparams, node_factory, bitcoind, teardown_checks, db_provider, executor, setup_logging, jsonschemas # noqa: F401,F403 +from pyln.testing.fixtures import directory, test_base_dir, test_name, chainparams, node_factory, bitcoind, lssd, teardown_checks, db_provider, executor, setup_logging, jsonschemas # noqa: F401,F403 from pyln.testing import utils from utils import COMPAT from pathlib import Path diff --git a/tests/test_bookkeeper.py b/tests/test_bookkeeper.py index 9614942e863d..5b02ef7a32f9 100644 --- a/tests/test_bookkeeper.py +++ b/tests/test_bookkeeper.py @@ -332,6 +332,7 @@ def test_bookkeeping_rbf_withdraw(node_factory, bitcoind): assert len(fees) == 1 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "hsmd_sign_option_will_fund_offer not supported") @pytest.mark.openchannel('v2') @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "turns off bookkeeper at start") @unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded") @@ -408,6 +409,7 @@ def _check_events(node, channel_id, exp_events): @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "turns off bookkeeper at start") @unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "remote_hsmd doesn't allow push of non-trivial amount") @pytest.mark.openchannel('v1', 'Uses push-msat') def test_bookkeeping_missed_chans_pushed(node_factory, bitcoind): """ diff --git a/tests/test_clnrest.py b/tests/test_clnrest.py index 195880d026ea..e77c87e88247 100644 --- a/tests/test_clnrest.py +++ b/tests/test_clnrest.py @@ -252,7 +252,7 @@ def test_clnrest_large_response(node_factory): # to complain with the errors F811 like this "F811 redefinition of # unused 'message'". -def notifications_received_via_websocket(l1, base_url, http_session): +def notifications_received_via_websocket(l1, base_url, http_session, rpc_method='invoice', rpc_params=[100000, 'label', 'description']): """Return the list of notifications received by the websocket client. We try to connect to the websocket server running at `base_url` @@ -271,8 +271,9 @@ def message(data): notifications.append(data) sio.connect(base_url) time.sleep(2) - # trigger `invoice_creation` notification - l1.rpc.invoice(10000, "label", "description") + # trigger notification by calling method + rpc_call = getattr(l1.rpc, rpc_method) + rpc_call(*rpc_params) time.sleep(2) sio.disconnect() return notifications @@ -374,6 +375,28 @@ def test_clnrest_websocket_rune_no_listnotifications(node_factory): assert len([n for n in notifications if n.find('invoice_creation') > 0]) == 0 +def test_clnrest_numeric_msat_notification(node_factory): + """Test that msat fields are integers in notifications also.""" + # start a node with clnrest + rest_port = str(reserve()) + base_url = 'http://127.0.0.1:' + rest_port + l1, l2 = node_factory.get_nodes(2, opts=[{}, {'clnrest-port': rest_port, 'clnrest-protocol': 'http'}]) + node_factory.join_nodes([l1, l2], wait_for_announce=True) + http_session = http_session_with_retry() + + # create an invoice on l2 + inv = l2.rpc.invoice(5000000, 'test_invoice_payment_notification', 'test_invoice_payment_notification_description') + + # create rune authorizing listclnrest-notifications method + rune_clnrest_notifications = l2.rpc.createrune(restrictions=[["method=listclnrest-notifications"]])['rune'] + http_session.headers.update({"rune": rune_clnrest_notifications}) + notifications = notifications_received_via_websocket(l1, base_url, http_session, 'pay', [inv['bolt11']]) + filtered_notifications = [n for n in notifications if 'invoice_creation' in n] + + assert isinstance(filtered_notifications[0]['invoice_creation']['msat'], int) + assert filtered_notifications[0]['invoice_creation']['msat'] == 5000000 + + def test_clnrest_options(node_factory): """Test startup options `clnrest-host`, `clnrest-protocol` and `clnrest-certs`.""" # with invalid port diff --git a/tests/test_closing.py b/tests/test_closing.py index 28e40fac0944..3a5c9f1453b9 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -482,6 +482,7 @@ def test_closing_negotiation_step_700sat(node_factory, bitcoind, chainparams): closing_negotiation_step(node_factory, bitcoind, chainparams, opts) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "dev_sign_last_tx causes subsequent validate_holder_commitment_tx failure") @pytest.mark.parametrize("anchors", [False, True]) def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams, anchors): """Test penalty transaction with an incoming HTLC""" @@ -614,6 +615,7 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams, anchors): check_utxos_channel(l2, [channel_id], expected_2, tags) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "dev_sign_last_tx causes subsequent validate_holder_commitment_tx failure") @pytest.mark.parametrize("anchors", [False, True]) def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams, anchors): """Test penalty transaction with an outgoing HTLC""" @@ -750,6 +752,7 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams, anchors) @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') @pytest.mark.slow_test def test_channel_lease_falls_behind(node_factory, bitcoind): @@ -791,6 +794,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') @pytest.mark.slow_test def test_channel_lease_post_expiry(node_factory, bitcoind, chainparams): @@ -892,6 +896,7 @@ def test_channel_lease_post_expiry(node_factory, bitcoind, chainparams): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') @pytest.mark.slow_test def test_channel_lease_unilat_closes(node_factory, bitcoind): @@ -1004,6 +1009,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): @@ -1080,6 +1086,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams): @@ -1155,6 +1162,8 @@ def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams): 'Unknown spend of OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by']) +# VLS_PERMISSIVE generates invalid signature bassed on bad commitnum +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "invalid next holder commitment number: 4 != 6") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") @pytest.mark.slow_test @pytest.mark.parametrize("anchors", [False, True]) @@ -1339,6 +1348,8 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams, anchors): check_balance_snaps(l2, expected_bals_2) +# VLS_PERMISSIVE generates invalid signature bassed on bad commitnum +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "invalid next holder commitment number: 4 != 6") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") @pytest.mark.slow_test @pytest.mark.parametrize("anchors", [False, True]) @@ -1568,6 +1579,7 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams, anchors): assert acc['resolved_at_block'] > 0 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "exceeds max fee policy") @pytest.mark.parametrize("anchors", [False, True]) def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams, anchors): ''' @@ -1811,6 +1823,7 @@ def test_onchaind_replay(node_factory, bitcoind): 'delay': 101, 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([routestep], rhash, payment_secret=inv['payment_secret']) l1.daemon.wait_for_log('sendrawtx exit 0') bitcoind.generate_block(1, wait_for_mempool=1) @@ -1954,6 +1967,7 @@ def test_onchain_timeout(node_factory, bitcoind, executor, chainparams, anchors) 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([routestep], rhash, payment_secret=inv['payment_secret'], groupid=1) with pytest.raises(RpcError): l1.rpc.waitsendpay(rhash) @@ -2088,6 +2102,7 @@ def test_onchain_middleman_simple(node_factory, bitcoind, chainparams, anchors): q = queue.Queue() + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming def try_pay(): try: l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) @@ -2227,6 +2242,7 @@ def test_onchain_middleman_their_unilateral_in(node_factory, bitcoind, chainpara q = queue.Queue() + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming def try_pay(): try: l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) @@ -2339,6 +2355,8 @@ def try_pay(): try: # rhash is fake (so is payment_secret) rhash = 'B1' * 32 + # let the signer know this payment is coming + l1.rpc.preapprovekeysend(l2.info['id'], rhash, 10**8) l1.rpc.sendpay(route, rhash, payment_secret=rhash) q.put(None) except Exception as err: @@ -2479,6 +2497,7 @@ def test_onchain_feechange(node_factory, bitcoind, executor): 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming executor.submit(l1.rpc.sendpay, [routestep], rhash, payment_secret=inv['payment_secret']) # l2 will drop to chain. @@ -2559,6 +2578,7 @@ def test_onchain_all_dust(node_factory, bitcoind, executor): 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming executor.submit(l1.rpc.sendpay, [routestep], rhash, payment_secret=inv['payment_secret']) # l2 will drop to chain. @@ -2851,6 +2871,7 @@ def route_to_l1(src): @pytest.mark.slow_test +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "frequently flakes") def test_onchain_multihtlc_our_unilateral(node_factory, bitcoind): """Node pushes a channel onchain with multiple HTLCs with same payment_hash """ h, l1, l2, l3, l4, l5, l6, l7 = setup_multihtlc_test(node_factory, bitcoind) @@ -2906,6 +2927,7 @@ def test_onchain_multihtlc_our_unilateral(node_factory, bitcoind): @pytest.mark.slow_test +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "frequently flakes") def test_onchain_multihtlc_their_unilateral(node_factory, bitcoind): """Node pushes a channel onchain with multiple HTLCs with same payment_hash """ h, l1, l2, l3, l4, l5, l6, l7 = setup_multihtlc_test(node_factory, bitcoind) @@ -3168,6 +3190,7 @@ def test_shutdown(node_factory): l1.rpc.stop() +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "validate_setup_channel: holder_shutdown_script is not in wallet or allowlist") def test_option_upfront_shutdown_script(node_factory, bitcoind, executor, chainparams): l1 = node_factory.get_node(start=False, allow_warning=True) # Insist on upfront script we're not going to match. @@ -3740,6 +3763,7 @@ def test_closing_anchorspend_htlc_tx_rbf(node_factory, bitcoind): 'delay': 12, 'channel': first_scid(l1, l2) } + l1.rpc.preapprovekeysend(routestep['id'], rhash, routestep['amount_msat']) l1.rpc.sendpay([routestep], rhash, payment_secret=inv['payment_secret']) l2.daemon.wait_for_log('dev_disconnect') l2.stop() @@ -3807,6 +3831,7 @@ def test_htlc_no_force_close(node_factory, bitcoind, anchors): 'id': l3.info['id'], 'delay': 10, 'channel': first_scid(l2, l3)}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) l3.daemon.wait_for_log('dev_disconnect') @@ -3928,6 +3953,7 @@ def test_peer_anchor_push(node_factory, bitcoind, executor, chainparams): amt = 100_000_000 sticky_inv = l3.rpc.invoice(amt, 'sticky', 'sticky') route = l1.rpc.getroute(l3.info['id'], amt, 1)['route'] + l1.rpc.preapproveinvoice(bolt11=sticky_inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, sticky_inv['payment_hash'], payment_secret=sticky_inv['payment_secret']) l3.daemon.wait_for_log('dev_disconnect: -WIRE_UPDATE_FULFILL_HTLC') diff --git a/tests/test_connection.py b/tests/test_connection.py index 570faaa54bbc..0c7b40e1dcf2 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -584,6 +584,7 @@ def test_disconnect_fundee(node_factory): assert len(l2.rpc.listpeers()) == 1 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_disconnect_fundee_v2(node_factory): @@ -660,6 +661,7 @@ def test_disconnect_half_signed_v2(node_factory): assert len(l1.rpc.listpeerchannels(l2.info['id'])['channels']) == 1 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') def test_reconnect_signed(node_factory): @@ -844,6 +846,7 @@ def test_reconnect_sender_add1(node_factory): l1.daemon.wait_for_log('Already have funding locked in') # This will send commit, so will reconnect as required. + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) @@ -874,6 +877,7 @@ def test_reconnect_sender_add(node_factory): route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}] # This will send commit, so will reconnect as required. + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) # Should have printed this for every reconnect. for i in range(0, len(disconnects)): @@ -905,6 +909,7 @@ def test_reconnect_receiver_add(node_factory): assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid' route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) for i in range(len(disconnects)): l1.daemon.wait_for_log('Already have funding locked in') @@ -934,6 +939,7 @@ def test_reconnect_receiver_fulfill(node_factory): assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid' route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) for i in range(len(disconnects)): l1.daemon.wait_for_log('Already have funding locked in') @@ -1209,6 +1215,8 @@ def test_v2_open(node_factory, bitcoind, chainparams): assert(result['status'] == 'complete') +# policy failed: policy-onchain-no-channel-push validate_onchain_tx: channel push not allowed: dual-funding not supported yet +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') def test_funding_push(node_factory, bitcoind, chainparams): """ Try to push peer some sats """ @@ -1636,6 +1644,7 @@ def test_funding_v2_cancel_race(node_factory, bitcoind, executor): executor.map(lambda n: n.stop(), node_factory.nodes) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "validate_setup_channel: holder_shutdown_script is not in wallet or allowlist") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.") @@ -1832,6 +1841,7 @@ def test_multifunding_v1_v2_mixed(node_factory, bitcoind): l1.rpc.pay(inv) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_multifunding_v2_exclusive(node_factory, bitcoind): @@ -2047,6 +2057,7 @@ def test_multifunding_wumbo(node_factory): l1.rpc.multifundchannel(destinations) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "flakes too frequently w/ VLS") @unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Fees on elements are different") @pytest.mark.openchannel('v1') # v2 the weight calculation is off by 3 @pytest.mark.parametrize("anchors", [False, True]) @@ -2440,6 +2451,7 @@ def test_update_fee(node_factory, bitcoind): l2.daemon.wait_for_log('onchaind complete, forgetting peer') +@pytest.mark.developer def test_fee_limits(node_factory, bitcoind): l1, l2, l3, l4 = node_factory.get_nodes(4, opts=[{'dev-max-fee-multiplier': 5, 'may_reconnect': True, 'allow_warning': True}, @@ -3573,6 +3585,9 @@ def test_channel_features(node_factory, bitcoind, anchors): assert only_one(l2.rpc.listpeerchannels()['channels'])['features'] == chan['features'] +# Still fails w/ VLS_PERMISSIVE with "recomposed tx mismatch" +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "Legacy channel type not supported") +@pytest.mark.developer("need dev-force-features") def test_nonstatic_channel(node_factory, bitcoind): """Smoke test for a channel without option_static_remotekey""" l1, l2 = node_factory.line_graph(2, @@ -3688,6 +3703,8 @@ def test_openchannel_init_alternate(node_factory, executor): print("nothing to do") +# Still fails w/ VLS_PERMISSIVE with "recomposed tx mismatch" +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "Legacy channel type not supported") def test_upgrade_statickey(node_factory, executor): """l1 doesn't have option_static_remotekey, l2 offers it.""" l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, @@ -3718,6 +3735,8 @@ def test_upgrade_statickey(node_factory, executor): l2.daemon.wait_for_log(r"They sent desired_channel_type \[12\]") +# Still fails w/ VLS_PERMISSIVE with "recomposed tx mismatch" +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "Legacy channel type not supported") def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind): """We test penalty before/after, and unilateral before/after""" l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, @@ -3852,6 +3871,8 @@ def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind): wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0) +# Still fails w/ VLS_PERMISSIVE with "recomposed tx mismatch" +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "Legacy channel type not supported") def test_upgrade_statickey_fail(node_factory, executor, bitcoind): """We reconnect at all points during retransmit, and we won't upgrade.""" l1_disconnects = ['-WIRE_COMMITMENT_SIGNED', @@ -4165,6 +4186,7 @@ def test_multichan(node_factory, executor, bitcoind): before = l2.rpc.listpeerchannels(l3.info['id'])['channels'] inv1 = l3.rpc.invoice(100000000, "invoice", "invoice") + l1.rpc.preapproveinvoice(bolt11=inv1['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv1['payment_hash'], payment_secret=inv1['payment_secret']) l1.rpc.waitsendpay(inv1['payment_hash']) @@ -4192,6 +4214,7 @@ def test_multichan(node_factory, executor, bitcoind): before = l2.rpc.listpeerchannels(l3.info['id'])['channels'] route[1]['channel'] = scid23b inv2 = l3.rpc.invoice(100000000, "invoice2", "invoice2") + l1.rpc.preapproveinvoice(bolt11=inv2['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv2['payment_hash'], payment_secret=inv2['payment_secret']) l1.rpc.waitsendpay(inv2['payment_hash']) # Wait until HTLCs fully settled @@ -4236,6 +4259,7 @@ def test_multichan(node_factory, executor, bitcoind): # We can actually pay by *closed* scid (at least until it's completely forgotten) route[1]['channel'] = scid23a inv3 = l3.rpc.invoice(100000000, "invoice3", "invoice3") + l1.rpc.preapproveinvoice(bolt11=inv3['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv3['payment_hash'], payment_secret=inv3['payment_secret']) l1.rpc.waitsendpay(inv3['payment_hash']) diff --git a/tests/test_db.py b/tests/test_db.py index 82b3e3b5c930..aa881cd18a6e 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -136,6 +136,7 @@ def test_max_channel_id(node_factory, bitcoind): @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") @unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't like channel_nonce changing") def test_scid_upgrade(node_factory, bitcoind): bitcoind.generate_block(1) @@ -167,6 +168,7 @@ def test_scid_upgrade(node_factory, bitcoind): @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") @unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't like channel_nonce changing") def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): bitcoind.generate_block(12) @@ -185,6 +187,7 @@ def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") @unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't like channel_nonce changing") def test_last_tx_psbt_upgrade(node_factory, bitcoind): bitcoind.generate_block(12) @@ -219,6 +222,7 @@ def test_last_tx_psbt_upgrade(node_factory, bitcoind): @pytest.mark.slow_test @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") @unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support backfill yet") def test_backfill_scriptpubkeys(node_factory, bitcoind): bitcoind.generate_block(214) @@ -352,6 +356,7 @@ def get_dsn(self): os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot" ) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support DB migration") def test_local_basepoints_cache(bitcoind, node_factory): """XXX started caching the local basepoints as well as the remote ones. @@ -440,6 +445,7 @@ def test_sqlite3_builtin_backup(bitcoind, node_factory): @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Don't know how to swap dbs in Postgres") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "vlsd chokes on allowlist when started on wrong network") def test_db_sanity_checks(bitcoind, node_factory): l1, l2 = node_factory.get_nodes(2, opts=[{'allow_broken_log': True, 'may_fail': True}, {}]) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index cf8815cc00a8..8714c8e50731 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -182,6 +182,7 @@ def test_announce_dns_suppressed(node_factory, bitcoind): assert addresses[0]['port'] == 1236 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "trouble with IPv6 in VLS CI runner") def test_announce_and_connect_via_dns(node_factory, bitcoind): """ Test that DNS annoucements propagate and can be used when connecting. diff --git a/tests/test_invoices.py b/tests/test_invoices.py index 5d72725eea34..97464e739c63 100644 --- a/tests/test_invoices.py +++ b/tests/test_invoices.py @@ -130,6 +130,8 @@ def test_invoice_weirdstring(node_factory): l1.rpc.delinvoice(weird_label, "unpaid") +# Can't be filtered with VLS_PERMISSIVE, re-using preimage corrupts internal data ... +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "already have a different invoice for same secret") def test_invoice_preimage(node_factory): """Test explicit invoice 'preimage'. """ diff --git a/tests/test_misc.py b/tests/test_misc.py index 9bea5e75e3fd..d6f5734bc358 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1145,6 +1145,7 @@ def test_cli_commando(node_factory): assert only_one(j['invoices'])['label'] == 'l"[]{}' +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd integration test job control fails here") def test_daemon_option(node_factory): """ Make sure --daemon at least vaguely works! @@ -2173,6 +2174,7 @@ def test_bitcoind_feerate_floor(node_factory, bitcoind, anchors): @unittest.skipIf(TEST_NETWORK != 'regtest', "Addresses are network specific") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support forced secrets") def test_dev_force_bip32_seed(node_factory): l1 = node_factory.get_node(options={'dev-force-bip32-seed': '0000000000000000000000000000000000000000000000000000000000000001'}) # First is m/0/0/1 .. @@ -2511,6 +2513,7 @@ def test_regtest_upgrade(node_factory): @unittest.skipIf(VALGRIND, "valgrind files can't be written since we rmdir") @unittest.skipIf(TEST_NETWORK != "regtest", "needs bitcoin mainnet") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't create hsm_secret file") def test_new_node_is_mainnet(node_factory): """Test that an empty directory causes us to be on mainnet""" l1 = node_factory.get_node(start=False, may_fail=True) @@ -2549,13 +2552,13 @@ def test_unicode_rpc(node_factory, executor, bitcoind): @unittest.skipIf(VALGRIND, "Testing pyln doesn't exercise anything interesting in the c code.") -def test_unix_socket_path_length(node_factory, bitcoind, directory, executor, db_provider, test_base_dir): +def test_unix_socket_path_length(node_factory, bitcoind, lssd, directory, executor, db_provider, test_base_dir): lightning_dir = os.path.join(directory, "anode" + "far" * 30 + "away") os.makedirs(lightning_dir) db = db_provider.get_db(lightning_dir, "test_unix_socket_path_length", 1) db.provider = db_provider - l1 = LightningNode(1, lightning_dir, bitcoind, executor, VALGRIND, db=db, port=reserve()) + l1 = LightningNode(1, lightning_dir, bitcoind, lssd, executor, VALGRIND, db=db, port=reserve()) # `LightningNode.start()` internally calls `LightningRpc.getinfo()` which # exercises the socket logic, and raises an issue if it fails. @@ -2674,6 +2677,7 @@ def test_sendcustommsg(node_factory): ]) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support dev-force-privkey") def test_makesecret(node_factory): """ Test makesecret command. @@ -2711,6 +2715,7 @@ def test_staticbackup(node_factory): and l1.rpc.staticbackup()["scb"][0][16: 16 + 64] == _["channel_id"]) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd says no such channel") def test_recoverchannel(node_factory): """ Test recoverchannel @@ -3744,6 +3749,7 @@ def test_setconfig(node_factory, bitcoind): assert len(lines) == 3 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support this command") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "deletes database, which is assumed sqlite3") def test_recover_command(node_factory, bitcoind): l1, l2 = node_factory.get_nodes(2) diff --git a/tests/test_opening.py b/tests/test_opening.py index 25ff00fd1eb7..edbedf5742c5 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -7,6 +7,7 @@ from pathlib import Path from pprint import pprint +import os import pytest import re import unittest @@ -18,6 +19,7 @@ def find_next_feerate(node, peer): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') def test_queryrates(node_factory, bitcoind): @@ -172,6 +174,7 @@ def test_v2_open_sigs_reconnect_2(node_factory, bitcoind): l2.daemon.wait_for_log(r'to CHANNELD_NORMAL') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_v2_open_sigs_reconnect_1(node_factory, bitcoind): @@ -334,6 +337,7 @@ def test_v2_open_sigs_restart_while_dead(node_factory, bitcoind): l1.daemon.wait_for_log(r'to CHANNELD_NORMAL') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_v2_rbf_single(node_factory, bitcoind, chainparams): @@ -434,6 +438,7 @@ def test_v2_rbf_single(node_factory, bitcoind, chainparams): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') def test_v2_rbf_abort_retry(node_factory, bitcoind, chainparams): l1, l2 = node_factory.get_nodes(2, opts={'allow_warning': True}) @@ -515,6 +520,7 @@ def test_v2_rbf_abort_retry(node_factory, bitcoind, chainparams): assert not l2.daemon.is_in_log('WIRE_CHANNEL_REESTABLISH') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_v2_rbf_abort_channel_opens(node_factory, bitcoind, chainparams): @@ -574,6 +580,7 @@ def test_v2_rbf_abort_channel_opens(node_factory, bitcoind, chainparams): l1.daemon.wait_for_log(' to CHANNELD_NORMAL') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "handle_sign_option_will_fund_offer unimplemented") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_v2_rbf_liquidity_ad(node_factory, bitcoind, chainparams): @@ -670,6 +677,7 @@ def test_v2_rbf_liquidity_ad(node_factory, bitcoind, chainparams): l1.daemon.wait_for_log('State changed from CLOSINGD_SIGEXCHANGE to CLOSINGD_COMPLETE') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_v2_rbf_multi(node_factory, bitcoind, chainparams): @@ -860,6 +868,7 @@ def test_rbf_reconnect_ack(node_factory, bitcoind, chainparams): l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams): @@ -981,6 +990,7 @@ def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams): l2.daemon.wait_for_log(r'to CHANNELD_NORMAL') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_reconnect_tx_sigs(node_factory, bitcoind, chainparams): @@ -1062,6 +1072,7 @@ def test_rbf_reconnect_tx_sigs(node_factory, bitcoind, chainparams): assert l1_funding_txid == l2_funding_txid +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_to_chain_before_commit(node_factory, bitcoind, chainparams): @@ -1163,6 +1174,7 @@ def test_rbf_no_overlap(node_factory, bitcoind, chainparams): l1.rpc.openchannel_update(chan_id, bump['psbt']) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_fails_to_broadcast(node_factory, bitcoind, chainparams): @@ -1244,6 +1256,7 @@ def run_retry(): assert last_txs['tx'] +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_broadcast_close_inflights(node_factory, bitcoind, chainparams): @@ -1319,6 +1332,7 @@ def run_retry(): assert inflights[1]['scratch_txid'] not in bitcoind.rpc.getrawmempool() +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_rbf_non_last_mined(node_factory, bitcoind, chainparams): @@ -1419,6 +1433,7 @@ def censoring_sendrawtx(r): l1.daemon.wait_for_log(r'to ONCHAIN') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_funder_options(node_factory, bitcoind): @@ -1485,6 +1500,8 @@ def test_funder_options(node_factory, bitcoind): assert chan_info['funding']['local_funds_msat'] == Millisatoshi('1000000000msat') +# policy-onchain-no-fund-inbound validate_onchain_tx: can't sign for inbound channel: dual-funding not supported yet +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') def test_funder_contribution_limits(node_factory, bitcoind): opts = {'experimental-dual-fund': None, @@ -1547,6 +1564,7 @@ def test_funder_contribution_limits(node_factory, bitcoind): assert l3.daemon.is_in_log(r'calling `signpsbt` .* 6 inputs') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') def test_inflight_dbload(node_factory, bitcoind): """Bad db field access breaks Postgresql on startup with opening leases""" @@ -1625,6 +1643,7 @@ def test_zeroconf_mindepth(bitcoind, node_factory): wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['state'] == "CHANNELD_NORMAL") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "ensure_funding_buried_and_unspent: tried commitment 1 when funding is not buried at depth 0") def test_zeroconf_open(bitcoind, node_factory): """Let's open a zeroconf channel @@ -1689,6 +1708,7 @@ def test_zeroconf_open(bitcoind, node_factory): l2.rpc.pay(inv) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "missing WIRE_HSMD_CUPDATE_SIG_REQ log messages") def test_zeroconf_public(bitcoind, node_factory, chainparams): """Test that we transition correctly from zeroconf to public @@ -1792,6 +1812,7 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams): wait_for(lambda: only_one([x for x in n.rpc.bkpr_listbalances()['accounts'] if x['account'] == channel_id])['account_resolved']) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "tried commitment when funding is not buried ") def test_zeroconf_forward(node_factory, bitcoind): """Ensure that we can use zeroconf channels in forwards. @@ -1856,6 +1877,7 @@ def test_buy_liquidity_ad_no_v2(node_factory, bitcoind): compact_lease='029a002d000000004b2003e8') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') def test_v2_replay_bookkeeping(node_factory, bitcoind): """ Test that your bookkeeping for a liquidity ad is good @@ -1920,6 +1942,7 @@ def test_v2_replay_bookkeeping(node_factory, bitcoind): l1.rpc.bkpr_listbalances() +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "sign_option_will_fund_offer unimplemented") @pytest.mark.openchannel('v2') def test_buy_liquidity_ad_check_bookkeeping(node_factory, bitcoind): """ Test that your bookkeeping for a liquidity ad is good.""" @@ -2040,6 +2063,7 @@ def test_scid_alias_private(node_factory, bitcoind): l1.rpc.waitsendpay(inv['payment_hash']) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "tried commitment when funding is not buried ") def test_zeroconf_multichan_forward(node_factory): """The freedom to choose the forward channel bytes us when it is 0conf @@ -2325,6 +2349,7 @@ def _no_utxo_response(r): wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == []) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v2') def test_openchannel_no_unconfirmed_inputs_accepter(node_factory, bitcoind): """ If the accepter flags 'require-confirmed-inputs' for an open, diff --git a/tests/test_pay.py b/tests/test_pay.py index 919ac39c5836..a3c2d70e4c6a 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -552,6 +552,7 @@ def test_pay_maxfee_shadow(node_factory): assert pay_status["amount_msat"] == Millisatoshi(amount) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "fails multiple policy checks") def test_sendpay(node_factory): l1, l2 = node_factory.line_graph(2, fundamount=10**6) @@ -574,6 +575,7 @@ def invoice_unpaid(dst, label): with pytest.raises(RpcError): rs = copy.deepcopy(routestep) rs['amount_msat'] = rs['amount_msat'] - 1 + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([rs], rhash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(rhash) assert invoice_unpaid(l2, 'testpayment2') @@ -582,6 +584,7 @@ def invoice_unpaid(dst, label): with pytest.raises(RpcError): rs = copy.deepcopy(routestep) rs['amount_msat'] = rs['amount_msat'] * 2 + 1 + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([rs], rhash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(rhash) assert invoice_unpaid(l2, 'testpayment2') @@ -590,6 +593,7 @@ def invoice_unpaid(dst, label): with pytest.raises(RpcError): rs = copy.deepcopy(routestep) rs['delay'] = rs['delay'] - 2 + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([rs], rhash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(rhash) assert invoice_unpaid(l2, 'testpayment2') @@ -599,17 +603,20 @@ def invoice_unpaid(dst, label): with pytest.raises(RpcError): rs = copy.deepcopy(routestep) rs['id'] = '00000000000000000000000000000000' + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([rs], rhash, payment_secret=inv['payment_secret']) assert invoice_unpaid(l2, 'testpayment2') l1.rpc.check_request_schemas = True # Bad payment_secret + l1.rpc.preapprovekeysend(l2.info['id'], rhash, routestep['amount_msat']) l1.rpc.sendpay([routestep], rhash, payment_secret="00" * 32) with pytest.raises(RpcError): l1.rpc.waitsendpay(rhash) assert invoice_unpaid(l2, 'testpayment2') # Missing payment_secret + l1.rpc.preapprovekeysend(l2.info['id'], rhash, routestep['amount_msat']) l1.rpc.sendpay([routestep], rhash) with pytest.raises(RpcError): l1.rpc.waitsendpay(rhash) @@ -625,6 +632,7 @@ def invoice_unpaid(dst, label): # This works. before = int(time.time()) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming details = l1.rpc.sendpay([routestep], rhash, payment_secret=inv['payment_secret']) after = int(time.time()) preimage = l1.rpc.waitsendpay(rhash)['payment_preimage'] @@ -667,6 +675,7 @@ def check_balances(): rhash = inv['payment_hash'] assert only_one(l2.rpc.listinvoices('testpayment3')['invoices'])['status'] == 'unpaid' routestep = {'amount_msat': amt * 2, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)} + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([routestep], rhash, payment_secret=inv['payment_secret']) preimage3 = l1.rpc.waitsendpay(rhash)['payment_preimage'] assert only_one(l2.rpc.listinvoices('testpayment3')['invoices'])['status'] == 'paid' @@ -702,6 +711,7 @@ def test_repay(node_factory): 'delay': 5, 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([routestep], inv['payment_hash'], payment_secret=inv['payment_secret']) l1.daemon.wait_for_log("Sending 200000000msat over 1 hops to deliver 200000000msat") l1.rpc.waitsendpay(inv['payment_hash'])['payment_preimage'] @@ -730,6 +740,7 @@ def test_wait_sendpay(node_factory, executor): 'delay': 5, 'channel': first_scid(l1, l2) } + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay([routestep], inv['payment_hash'], payment_secret=inv['payment_secret']) assert wait_created.result(TIMEOUT) == {'subsystem': 'sendpays', 'created': 1, @@ -1157,6 +1168,7 @@ def test_forward(node_factory, bitcoind): # Unknown other peer route = copy.deepcopy(baseroute) route[1]['id'] = '031a8dc444e41bb989653a4501e11175a488a57439b0c4947704fd6e3de5dca607' + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret']) with pytest.raises(RpcError): l1.rpc.waitsendpay(rhash) @@ -1559,6 +1571,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): l2.rpc.close(c23, 1) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming with pytest.raises(RpcError): l1.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash) @@ -1584,6 +1597,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): 'delay': 6, 'channel': c24}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming with pytest.raises(RpcError): l1.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash) @@ -1610,6 +1624,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): 'delay': 6, 'channel': c25}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming with pytest.raises(RpcError): l1.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash) @@ -1633,6 +1648,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): # Replace id with a different pubkey, so onion encoded badly at l2 hop. route[1]['id'] = mangled_nodeid + l6.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming with pytest.raises(RpcError): l6.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) l6.rpc.waitsendpay(payment_hash) @@ -1660,6 +1676,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): 'delay': 5, 'channel': c24}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming executor.submit(l1.rpc.sendpay, route, payment_hash, payment_secret=inv['payment_secret']) l4.daemon.wait_for_log('permfail') @@ -1715,6 +1732,7 @@ def test_htlcs_cltv_only_difference(node_factory, bitcoind): # L2 tries to pay r = l2.rpc.getroute(l4.info['id'], 10**8, 1)["route"] + l2.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l2.rpc.sendpay(r, h, payment_secret=inv['payment_secret']) # Now increment CLTV @@ -1723,6 +1741,7 @@ def test_htlcs_cltv_only_difference(node_factory, bitcoind): # L1 tries to pay r = l1.rpc.getroute(l4.info['id'], 10**8, 1)["route"] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(r, h, payment_secret=inv['payment_secret']) # Now increment CLTV @@ -1731,6 +1750,7 @@ def test_htlcs_cltv_only_difference(node_factory, bitcoind): # L3 tries to pay r = l3.rpc.getroute(l4.info['id'], 10**8, 1)["route"] + l3.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l3.rpc.sendpay(r, h, payment_secret=inv['payment_secret']) # Give them time to go through. @@ -1796,6 +1816,7 @@ def exhaust_channel(opener, peer, scid, already_spent=0): 'delay': 10, 'channel': scid } + opener.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming opener.rpc.sendpay([routestep], inv['payment_hash'], payment_secret=inv['payment_secret']) opener.rpc.waitsendpay(inv['payment_hash']) @@ -2493,6 +2514,7 @@ def test_setchannel_startup_opts(node_factory, bitcoind): assert result[1]['htlc_maximum_msat'] == Millisatoshi(5) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "invoice with any amount") def test_channel_spendable(node_factory, bitcoind): """Test that spendable_msat is accurate""" sats = 10**6 @@ -2513,6 +2535,7 @@ def test_channel_spendable(node_factory, bitcoind): # Exact amount should succeed. route = l1.rpc.getroute(l2.info['id'], amount, riskfactor=1, fuzzpercent=0)['route'] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) # Amount should drop to 0 once HTLC is sent; we have time, thanks to @@ -2538,6 +2561,7 @@ def test_channel_spendable(node_factory, bitcoind): # Exact amount should succeed. route = l2.rpc.getroute(l1.info['id'], amount, riskfactor=1, fuzzpercent=0)['route'] + l2.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l2.rpc.sendpay(route, payment_hash, payment_secret=inv['payment_secret']) # Amount should drop to 0 once HTLC is sent; we have time, thanks to @@ -2547,6 +2571,7 @@ def test_channel_spendable(node_factory, bitcoind): l2.rpc.waitsendpay(payment_hash, TIMEOUT) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "invoice with any amount") def test_channel_receivable(node_factory, bitcoind): """Test that receivable_msat is accurate""" sats = 10**6 @@ -2602,6 +2627,7 @@ def test_channel_receivable(node_factory, bitcoind): l2.rpc.waitsendpay(payment_hash, TIMEOUT) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "invoice with any amount") def test_channel_spendable_large(node_factory, bitcoind): """Test that spendable_msat is accurate for large channels""" # This is almost the max allowable spend. @@ -2697,6 +2723,7 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams): route = l1.rpc.getroute(l2.info['id'], non_dust_htlc_val_sat * 1000, 1)['route'] for i in range(0, 3): inv = l2.rpc.invoice((non_dust_htlc_val_sat * 1000), str(i + 100), str(i + 100)) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs') res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments']) @@ -2706,6 +2733,7 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams): route = l1.rpc.getroute(l2.info['id'], htlc_val_msat, 1)['route'] for i in range(0, num_dusty_htlcs): inv = l2.rpc.invoice(htlc_val_msat, str(i), str(i)) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs') res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments']) @@ -2713,6 +2741,7 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams): # one more should tip it over, and return a payment failure inv = l2.rpc.invoice(htlc_val_msat, str(num_dusty_htlcs), str(num_dusty_htlcs)) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) l1.daemon.wait_for_log('CHANNEL_ERR_DUST_FAILURE') wait_for(lambda: only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])['status'] == 'failed') @@ -2720,6 +2749,7 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams): # but we can still add a non dust htlc route = l1.rpc.getroute(l2.info['id'], non_dust_htlc_val_sat * 1000, 1)['route'] inv = l2.rpc.invoice((10000 * 1000), str(120), str(120)) + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs') res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments']) @@ -2740,6 +2770,7 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams): l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "feerate above maximum (escalates)") def test_htlc_too_dusty_incoming(node_factory, bitcoind): """ Try to hit the 'too much dust' limit, should fail the HTLC """ feerate = 30000 @@ -2802,6 +2833,7 @@ def test_error_returns_blockheight(node_factory, bitcoind): == '400f{:016x}{:08x}'.format(100, bitcoind.rpc.getblockcount())) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "inv_nosecret: The invoice is missing the mandatory payment secret") @unittest.skipIf(TEST_NETWORK != 'regtest', "Invoice is network specific") def test_pay_no_secret(node_factory, bitcoind): l1, l2 = node_factory.line_graph(2, wait_for_announce=True) @@ -4179,6 +4211,7 @@ def test_mpp_interference_2(node_factory, bitcoind, executor): @pytest.mark.slow_test +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "remote_hsmd doesn't allow push of greater than 20k sat") def test_mpp_overload_payee(node_factory, bitcoind): """ We had a bug where if the payer is unusually well-connected compared @@ -4438,6 +4471,7 @@ def test_fetchinvoice_3hop(node_factory, bitcoind): l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']}) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "invoice not bolt12: InvalidSemantics(UnsupportedCurrency) and not bolt11: Bech32Error(InvalidChecksum)") def test_fetchinvoice(node_factory, bitcoind): # We remove the conversion plugin on l3, causing it to get upset. l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True, @@ -4563,6 +4597,7 @@ def test_fetchinvoice(node_factory, bitcoind): l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'timeout': 10}) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "invoice not bolt12: Decode(UnknownRequiredFeature) and not bolt11: Bech32Error(InvalidChecksum)") def test_fetchinvoice_recurrence(node_factory, bitcoind): """Test for our recurrence extension""" l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True, @@ -5170,6 +5205,7 @@ def test_payerkey(node_factory): assert n.rpc.decode(b12)['invreq_payer_id'] == k +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "tried commitment when funding is not buried ") def test_pay_multichannel_use_zeroconf(bitcoind, node_factory): """Check that we use the zeroconf direct channel to pay when we need to""" # 0. Setup normal channel, 200k sats. diff --git a/tests/test_plugin.py b/tests/test_plugin.py index e86bc18df052..112880fa5206 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -705,6 +705,7 @@ def test_openchannel_hook(node_factory, bitcoind): l1.rpc.fundchannel(l2.info['id'], 100001) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "this test frequently hangs w/ VLSD") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') def test_openchannel_hook_error_handling(node_factory, bitcoind): @@ -1269,7 +1270,7 @@ def test_invoice_payment_notification(node_factory): l1.dev_pay(inv1['bolt11'], dev_use_shadow=False) l2.daemon.wait_for_log(r"Received invoice_payment event for label {}," - " preimage {}, and amount of {}msat" + " preimage {}, and amount of {}" .format(label, preimage, msats)) @@ -1286,7 +1287,7 @@ def test_invoice_creation_notification(node_factory): l2.rpc.invoice(msats, label, 'description', preimage=preimage) l2.daemon.wait_for_log(r"Received invoice_creation event for label {}," - " preimage {}, and amount of {}msat" + " preimage {}, and amount of {}" .format(label, preimage, msats)) @@ -1341,12 +1342,14 @@ def test_forward_event_notification(node_factory, bitcoind, executor): route = l1.rpc.getroute(l3.info['id'], amount, 1)['route'] # status: offered -> settled + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash13, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash13) # status: offered -> failed route = l1.rpc.getroute(l4.info['id'], amount, 1)['route'] payment_hash14 = "f" * 64 + l1.rpc.preapprovekeysend(l4.info['id'], payment_hash14, amount) with pytest.raises(RpcError): l1.rpc.sendpay(route, payment_hash14, payment_secret="f" * 64) l1.rpc.waitsendpay(payment_hash14) @@ -1366,6 +1369,7 @@ def test_forward_event_notification(node_factory, bitcoind, executor): 'delay': 5, 'channel': c25}] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming executor.submit(l1.rpc.sendpay, route, payment_hash15, payment_secret=inv['payment_secret']) l5.daemon.wait_for_log('permfail') @@ -1452,11 +1456,13 @@ def test_sendpay_notifications(node_factory, bitcoind): payment_hash2 = inv2['payment_hash'] route = l1.rpc.getroute(l3.info['id'], amount, 1)['route'] + l1.rpc.preapproveinvoice(bolt11=inv1['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash1, payment_secret=inv1['payment_secret']) response1 = l1.rpc.waitsendpay(payment_hash1) l2.rpc.close(chanid23, 1) + l1.rpc.preapproveinvoice(bolt11=inv2['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash2, payment_secret=inv2['payment_secret']) with pytest.raises(RpcError) as err: l1.rpc.waitsendpay(payment_hash2) @@ -1483,11 +1489,13 @@ def test_sendpay_notifications_nowaiter(node_factory): payment_hash2 = inv2['payment_hash'] route = l1.rpc.getroute(l3.info['id'], amount, 1)['route'] + l1.rpc.preapproveinvoice(bolt11=inv1['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash1, payment_secret=inv1['payment_secret']) l1.daemon.wait_for_log(r'Received a sendpay_success') l2.rpc.close(chanid23, 1) + l1.rpc.preapproveinvoice(bolt11=inv2['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash2, payment_secret=inv2['payment_secret']) l1.daemon.wait_for_log(r'Received a sendpay_failure') @@ -1778,6 +1786,7 @@ def test_bitcoin_backend(node_factory, bitcoind): " bitcoind") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "channel too big, then feerate above maximum") def test_bitcoin_bad_estimatefee(node_factory, bitcoind): """ This tests that we don't crash if bitcoind backend gives bad estimatefees. @@ -1948,6 +1957,7 @@ def test_replacement_payload(node_factory): assert l2.daemon.wait_for_log("Attempt to pay.*with wrong secret") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "dev_sign_last_tx causes subsequent validate_holder_commitment_tx failure") def test_watchtower(node_factory, bitcoind, directory, chainparams): """Test watchtower hook. @@ -2087,12 +2097,14 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): route = l1.rpc.getroute(l3.info['id'], amount, 1)['route'] # status: offered -> settled + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash13, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash13) # status: offered -> failed route = l1.rpc.getroute(l3.info['id'], amount, 1)['route'] payment_hash13 = "f" * 64 + l1.rpc.preapprovekeysend(l3.info['id'], payment_hash13, amount) with pytest.raises(RpcError): l1.rpc.sendpay(route, payment_hash13, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash13) @@ -2101,6 +2113,7 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): inv = l1.rpc.invoice(amount // 2, "first", "desc") payment_hash31 = inv['payment_hash'] route = l3.rpc.getroute(l1.info['id'], amount // 2, 1)['route'] + l3.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l3.rpc.sendpay(route, payment_hash31, payment_secret=inv['payment_secret']) l3.rpc.waitsendpay(payment_hash31) @@ -2108,6 +2121,7 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): inv = l2.rpc.invoice(amount, "first", "desc") payment_hash12 = inv['payment_hash'] route = l1.rpc.getroute(l2.info['id'], amount, 1)['route'] + l1.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l1.rpc.sendpay(route, payment_hash12, payment_secret=inv['payment_secret']) l1.rpc.waitsendpay(payment_hash12) @@ -2117,6 +2131,7 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): # Make sure previous completely settled wait_for(lambda: only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['htlcs'] == []) route = l2.rpc.getroute(l1.info['id'], amount // 2, 1)['route'] + l2.rpc.preapproveinvoice(bolt11=inv['bolt11']) # let the signer know this payment is coming l2.rpc.sendpay(route, payment_hash21, payment_secret=inv['payment_secret']) l2.rpc.waitsendpay(payment_hash21) @@ -2161,6 +2176,7 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): check_coin_moves(l2, chanid_3, l2_l3_mvts, chainparams) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "trouble managing remotesigner when node killed this way") def test_important_plugin(node_factory): # Cache it here. pluginsdir = os.path.join(os.path.dirname(__file__), "plugins") @@ -3391,6 +3407,7 @@ def test_block_added_notifications(node_factory, bitcoind): assert len(ret) == 3 and ret[1] == next_l2_base + 1 and ret[2] == next_l2_base + 2 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "timeout waiting for hold_invoice plugin") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') def test_sql(node_factory, bitcoind): opts = {'experimental-offers': None, diff --git a/tests/test_reckless.py b/tests/test_reckless.py index ac4f0db19ee5..559a3084bf92 100644 --- a/tests/test_reckless.py +++ b/tests/test_reckless.py @@ -6,7 +6,7 @@ import os import shutil import time - +import unittest @pytest.fixture(autouse=True) def canned_github_server(directory): @@ -175,6 +175,7 @@ def test_local_dir_install(node_factory): assert os.path.exists(plugin_path) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "no canned github server in gitlab CI") def test_disable_enable(node_factory): """test search, git clone, and installation to folder.""" n = get_reckless_node(node_factory) diff --git a/tests/test_renepay.py b/tests/test_renepay.py index f2b8f76f8ce2..af4565ccbc55 100644 --- a/tests/test_renepay.py +++ b/tests/test_renepay.py @@ -6,6 +6,7 @@ import time import json import subprocess +import unittest def test_simple(node_factory): @@ -72,6 +73,8 @@ def test_mpp(node_factory): send_amount = Millisatoshi('1200000sat') inv = l6.rpc.invoice(send_amount, 'test_renepay', 'description')['bolt11'] + # FIXME - This shouldn't be necessary, renepay should automatically generate ... vls-hsmd:#6 + l1.rpc.preapproveinvoice(bolt11=inv) # let the signer know this payment is coming details = l1.rpc.call('renepay', {'invstring': inv}) assert details['status'] == 'complete' assert details['amount_msat'] == send_amount @@ -215,6 +218,7 @@ def test_amounts(node_factory): assert invoice['amount_received_msat'] >= Millisatoshi(123456) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "invoice with any amount") def test_limits(node_factory): ''' Topology: @@ -313,6 +317,7 @@ def start_channels(connections): wait_for(lambda: 'alias' in only_one(n.rpc.listnodes(n2.info['id'])['nodes'])) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "invoice with any amount") def test_hardmpp(node_factory): ''' Topology: diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 78e480571ac8..6c09bf7ba0ea 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -9,10 +9,12 @@ ) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') -@flaky +# incompatible w/ pytest-timeout +# @flaky def test_splice(node_factory, bitcoind): l1, l2 = node_factory.line_graph(2, fundamount=1000000, wait_for_announce=True, opts={'experimental-splicing': None}) @@ -47,6 +49,7 @@ def test_splice(node_factory, bitcoind): assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @@ -105,6 +108,7 @@ def test_splice_gossip(node_factory, bitcoind): assert not l2.daemon.is_in_log("invalid local_channel_announcement") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @@ -140,6 +144,7 @@ def test_splice_listnodes(node_factory, bitcoind): assert len(l2.rpc.listnodes()['nodes']) == 2 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @@ -176,6 +181,7 @@ def test_splice_out(node_factory, bitcoind): assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @@ -287,6 +293,7 @@ def test_commit_crash_splice(node_factory, bitcoind): assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') diff --git a/tests/test_splicing_disconnect.py b/tests/test_splicing_disconnect.py index 093afe296fec..b2249acd99f2 100644 --- a/tests/test_splicing_disconnect.py +++ b/tests/test_splicing_disconnect.py @@ -8,6 +8,7 @@ ) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @@ -63,6 +64,7 @@ def test_splice_disconnect_sig(node_factory, bitcoind): assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_SKIP_SPLICE_TESTS') == '1', "test expected to fail before VLS dual-funding / splicing support") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 40d078cd338d..aac20e8fd17a 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -782,6 +782,7 @@ def test_utxopsbt(node_factory, bitcoind, chainparams): reservedok=True) +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd') and os.getenv('VLS_PERMISSIVE') != '1', "non-beneficial value considered as fees is above maximum feerate") def test_sign_external_psbt(node_factory, bitcoind, chainparams): """ A PSBT w/ one of our inputs should be signable (we can fill @@ -1005,7 +1006,12 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams): # But it can sign all the valid ones at once. half_signed_psbt = l1.rpc.signpsbt(joint_psbt, signonly=sign_success)['signed_psbt'] for s in sign_success: - assert bitcoind.rpc.decodepsbt(half_signed_psbt)['inputs'][s]['partial_signatures'] is not None + decoded_input = bitcoind.rpc.decodepsbt(half_signed_psbt)['inputs'][s] + if 'partial_signatures' in decoded_input: + assert decoded_input['partial_signatures'] is not None + else: + # VLS returns signatures in final_scriptwitness instead + assert decoded_input['final_scriptwitness'] is not None totally_signed = l2.rpc.signpsbt(half_signed_psbt)['signed_psbt'] @@ -1117,6 +1123,7 @@ def write_all(fd, bytestr): @unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support hsm_secret file") def test_hsm_secret_encryption(node_factory): l1 = node_factory.get_node(may_fail=True) # May fail when started without key password = "reckful&é🍕\n" @@ -1180,6 +1187,7 @@ def __init__(self, directory, *args): @unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.") +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support hsm_secret file") def test_hsmtool_secret_decryption(node_factory): l1 = node_factory.get_node() password = "reckless123#{ù}\n" @@ -1316,6 +1324,7 @@ def test_hsmtool_dump_descriptors(node_factory, bitcoind): assert res["total_amount"] == Decimal('0.00001000') +@unittest.skipIf(os.getenv('SUBDAEMON').startswith('hsmd:remote_hsmd'), "remote_hsmd doesn't support generatehsm") def test_hsmtool_generatehsm(node_factory): l1 = node_factory.get_node(start=False) hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK,