fix(pairing): default relay to the transport's nostrrelay, not nostrclient proxy
Some checks failed
ci.yml / fix(pairing): default relay to the transport's nostrrelay, not nostrclient proxy (pull_request) Failing after 0s
Some checks failed
ci.yml / fix(pairing): default relay to the transport's nostrrelay, not nostrclient proxy (pull_request) Failing after 0s
The nostrclient endpoint is a subscription MULTIPLEXER, not a full relay: its
router forwards a client's EVENT upstream but never returns an OK ack (see
nostrclient/router.py). A transport client that awaits OK on publish therefore
times out ("publish timed out"), so kind-21000 RPCs never complete — verified
on the Sintra: connect succeeded but list_wallets hung, and switching to the
nostrrelay endpoint made the whole flow work (wallet, balance, availability).
default_relay_endpoint now derives from settings.nostr_transport_relays — the
relay the transport actually listens on: use it as-is when already
machine-reachable, or re-home its path on lnbits_baseurl when it's a co-located
loopback relay (the bundled nostrrelay). Validation/localhost-reject and the
pair-dialog pre-fill/hint carry over; wording updated to "transport relay".
227 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
765b07737b
commit
0bb9939822
6 changed files with 89 additions and 49 deletions
|
|
@ -35,7 +35,9 @@ from ..pairing import (
|
|||
)
|
||||
|
||||
_BASEURL = "https://lnbits.example.com/"
|
||||
_NOSTRCLIENT_ENDPOINT = "wss://lnbits.example.com/nostrclient/api/v1/relay"
|
||||
_TRANSPORT_RELAY = "ws://localhost:5001/nostrrelay/test"
|
||||
# baseurl host (wss://lnbits.example.com) + transport relay path (/nostrrelay/test)
|
||||
_DEFAULT_RELAY = "wss://lnbits.example.com/nostrrelay/test"
|
||||
|
||||
_NOW = datetime(2026, 6, 16, tzinfo=timezone.utc)
|
||||
_SPIRE_HEX = "522a4538f1df96508d9ee8b14072344dd4a566acfe03c25a92a39179c6fca891"
|
||||
|
|
@ -53,11 +55,14 @@ def _set_transport_pubkey():
|
|||
# lnbits_npub in the seed (bitspire#70). Set it for every test; restore after.
|
||||
prev = settings.nostr_transport_public_key
|
||||
prev_base = settings.lnbits_baseurl
|
||||
prev_relays = settings.nostr_transport_relays
|
||||
settings.nostr_transport_public_key = _LNBITS_HEX
|
||||
settings.lnbits_baseurl = _BASEURL
|
||||
settings.nostr_transport_relays = [_TRANSPORT_RELAY]
|
||||
yield
|
||||
settings.nostr_transport_public_key = prev
|
||||
settings.lnbits_baseurl = prev_base
|
||||
settings.nostr_transport_relays = prev_relays
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
@ -327,8 +332,8 @@ def test_missing_passphrase_raises():
|
|||
)
|
||||
|
||||
|
||||
def test_relays_default_to_nostrclient_endpoint():
|
||||
# No relays given → derived from lnbits_baseurl → nostrclient proxy endpoint.
|
||||
def test_relays_default_to_transport_relay():
|
||||
# No relays given → derived from the transport relay, re-homed on baseurl.
|
||||
result = asyncio.run(
|
||||
pair_spire(
|
||||
_machine(),
|
||||
|
|
@ -336,34 +341,51 @@ def test_relays_default_to_nostrclient_endpoint():
|
|||
keystore_passphrase=_PASSPHRASE,
|
||||
)
|
||||
)
|
||||
assert _decode_seed(result.seed_url)["relays"] == [_NOSTRCLIENT_ENDPOINT]
|
||||
assert _decode_seed(result.seed_url)["relays"] == [_DEFAULT_RELAY]
|
||||
|
||||
|
||||
def test_default_relay_endpoint_scheme_map():
|
||||
prev = settings.lnbits_baseurl
|
||||
def test_default_relay_endpoint_rehomes_loopback_transport_relay():
|
||||
prev_base = settings.lnbits_baseurl
|
||||
prev_relays = settings.nostr_transport_relays
|
||||
try:
|
||||
# loopback transport relay → re-homed on the base URL host
|
||||
settings.nostr_transport_relays = ["ws://localhost:5001/nostrrelay/test"]
|
||||
settings.lnbits_baseurl = "http://192.168.0.32:5001"
|
||||
assert default_relay_endpoint() == "ws://192.168.0.32:5001/nostrclient/api/v1/relay"
|
||||
assert default_relay_endpoint() == "ws://192.168.0.32:5001/nostrrelay/test"
|
||||
settings.lnbits_baseurl = "https://lnbits.example.com/"
|
||||
assert default_relay_endpoint() == _NOSTRCLIENT_ENDPOINT
|
||||
assert default_relay_endpoint() == _DEFAULT_RELAY
|
||||
# loopback relay but no base URL → can't re-home → None
|
||||
settings.lnbits_baseurl = ""
|
||||
assert default_relay_endpoint() is None
|
||||
finally:
|
||||
settings.lnbits_baseurl = prev
|
||||
settings.lnbits_baseurl = prev_base
|
||||
settings.nostr_transport_relays = prev_relays
|
||||
|
||||
|
||||
def test_no_relays_and_no_baseurl_raises():
|
||||
prev = settings.lnbits_baseurl
|
||||
def test_default_relay_endpoint_passes_through_reachable_transport_relay():
|
||||
prev = settings.nostr_transport_relays
|
||||
try:
|
||||
settings.lnbits_baseurl = ""
|
||||
with pytest.raises(PairingError, match="cannot derive"):
|
||||
# already remote-reachable → used as-is, base URL irrelevant
|
||||
settings.nostr_transport_relays = ["wss://relay.aiolabs.dev"]
|
||||
assert default_relay_endpoint() == "wss://relay.aiolabs.dev"
|
||||
settings.nostr_transport_relays = []
|
||||
assert default_relay_endpoint() is None
|
||||
finally:
|
||||
settings.nostr_transport_relays = prev
|
||||
|
||||
|
||||
def test_no_relays_and_no_transport_relay_raises():
|
||||
prev = settings.nostr_transport_relays
|
||||
try:
|
||||
settings.nostr_transport_relays = []
|
||||
with pytest.raises(PairingError, match="none could be derived"):
|
||||
asyncio.run(
|
||||
pair_spire(
|
||||
_machine(), admin_client=FakeBunker(), keystore_passphrase=_PASSPHRASE
|
||||
)
|
||||
)
|
||||
finally:
|
||||
settings.lnbits_baseurl = prev
|
||||
settings.nostr_transport_relays = prev
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue