Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions chainfees/mempoolspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ const (
// wall-clock time but not the number of bytes read.
maxMempoolSpaceResponseBytes = 64 << 10

// The test networks default to Lightning Labs-operated mempool
// instances, matching the lwwallet Esplora defaults; only mainnet uses
// the public mempool.space endpoint.
mempoolSpaceMainnetURL = "https://mempool.space/api/v1/fees/recommended"
// All networks default to Lightning Labs-operated mempool instances,
// matching the lwwallet Esplora defaults.
mempoolSpaceMainnetURL = "https://mempool.staging." +
"lightningcluster.com/api/v1/fees/recommended"
mempoolSpaceTestnetURL = "https://mempool-testnet3.testnet." +
"lightningcluster.com/api/v1/fees/recommended"
mempoolSpaceTestnet4URL = "https://mempool-testnet4.testnet." +
Expand Down
2 changes: 1 addition & 1 deletion chainfees/mempoolspace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func TestMempoolSpaceEstimatorRejectsInsecureURL(t *testing.T) {
}{
{
name: "https ok",
url: "https://mempool.space/api/v1/fees/recommended",
url: mempoolSpaceMainnetURL,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 F3 (Minor) — Only positive https case in the validator test now tracks the constant · chainfees/mempoolspace_test.go:232

TestMempoolSpaceEstimatorRejectsInsecureURL's "https ok" row was the table's only fixed positive case for the https-accept path in validateMempoolSpaceURL; binding it to mempoolSpaceMainnetURL means the case's input now moves whenever the default moves, and the row's name stops describing what it pins. Keep the literal https:// case and add a separate row asserting the mainnet default also validates — that covers both the validator and the constant, instead of trading one for the other.

},
{
name: "loopback http ok",
Expand Down
2 changes: 1 addition & 1 deletion docs/signet.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ network defaults when left empty:

| Network config | lwwallet Esplora URL | btcwallet fee URL |
|----------------|-----------------------|--------------------|
| `mainnet` | `https://mempool.space/api` | `https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json` |
| `mainnet` | `https://mempool.staging.lightningcluster.com/api` | `https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json` |
| `testnet` | `https://mempool-testnet3.testnet.lightningcluster.com/api` | `https://nodes.lightning.computer/fees/v1/btctestnet-fee-estimates.json` |
| `testnet4` | `https://mempool-testnet4.testnet.lightningcluster.com/api` | `https://nodes.lightning.computer/fees/v1/btctestnet-fee-estimates.json` |
| `signet` | `https://mempool-signet.testnet.lightningcluster.com/api` | `https://nodes.lightning.computer/fees/v1/btctestnet-fee-estimates.json` |
Expand Down
6 changes: 3 additions & 3 deletions lwwallet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ type Config struct {
// uses it to bound recovery rescans instead of starting from genesis.
Birthday time.Time

// EsploraURL is the base URL of the Esplora/mempool.space REST API
// (e.g. "https://mempool.space/api" or "http://localhost:3000"). The
// wallet uses this for all chain data: blocks, transactions, UTXOs,
// EsploraURL is the base URL of the Esplora/mempool.space REST API.
// For example, DefaultEsploraURLMainnet or "http://localhost:3000".
// The wallet uses this for all chain data: blocks, transactions, UTXOs,
// fee estimates, and broadcasting.
EsploraURL string

Expand Down
7 changes: 4 additions & 3 deletions lwwallet/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
)

const (
// DefaultEsploraURLMainnet is the public mempool.space
// Esplora-compatible REST API for mainnet.
DefaultEsploraURLMainnet = "https://mempool.space/api"
// DefaultEsploraURLMainnet is the Esplora-compatible REST API for
// mainnet, backed by a Lightning Labs-operated mempool instance.
DefaultEsploraURLMainnet = "https://mempool.staging." +

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 F1 (Major) — Mainnet default points at a staging endpoint · lwwallet/defaults.go:13

The mainnet default for all lwwallet chain access is now a host explicitly named staging. If that instance is a staging deployment in the usual sense — lower capacity, no production SLA, redeployed at will — then every mainnet waved instance that leaves wallet.esploraurl empty loses tip polling, UTXO discovery, and transaction broadcast whenever it is cycled, and this is the network where real funds are at stake.

Why this matters

The same host lands in chainfees/mempoolspace.go:37 for the mainnet recommended-fee endpoint, so a staging outage degrades both chain data and fee estimation on mainnet simultaneously. Note the naming asymmetry against the other defaults in this same const block: testnet3, testnet4, and signet all use mempool-<net>.testnet.lightningcluster.com, a production-shaped name, while mainnet alone gets a staging subdomain. readme states mainnet operation is gated behind --allow-mainnet and that the project is under active development, which lowers the blast radius today but does not make a staging host the right value to bake in as the mainnet default. Either point mainnet at the production name, or, if mempool.staging.… is in fact the durable production endpoint that merely carries a legacy label, say so in the constant's doc comment so the next reader does not have to guess. I cannot tell from the diff or the loaded context which of the two it is.

"lightningcluster.com/api"

// DefaultEsploraURLTestnet3 is the Esplora-compatible REST API for
// testnet3, backed by a Lightning Labs-operated mempool instance.
Expand Down
4 changes: 2 additions & 2 deletions lwwallet/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
)

// TestDefaultEsploraURL verifies each supported network resolves to its
// public mempool.space Esplora endpoint, and unsupported networks error out
// instead of silently returning an empty URL.
// Esplora endpoint, and unsupported networks error out instead of silently
// returning an empty URL.
func TestDefaultEsploraURL(t *testing.T) {
t.Parallel()

Expand Down
7 changes: 4 additions & 3 deletions lwwallet/esplora.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ import (
// address UTXOs, tx confirmation status, mempool fee estimates) are
// never cached.
type EsploraClient struct {
// baseURL is the Esplora API root (e.g. "https://mempool.space/api").
// baseURL is the Esplora API root (e.g. the mainnet default in
// DefaultEsploraURLMainnet).
baseURL string

// httpClient is the underlying HTTP client with a configured timeout.
Expand Down Expand Up @@ -79,8 +80,8 @@ type EsploraClient struct {
}

// NewEsploraClient creates a new Esplora REST API client. The baseURL should
// point to the API root without a trailing slash (e.g.
// "https://mempool.space/api").
// point to the API root without a trailing slash (e.g. the mainnet default in
// DefaultEsploraURLMainnet).
func NewEsploraClient(baseURL string, logger btclog.Logger) *EsploraClient {
return &EsploraClient{
baseURL: strings.TrimRight(baseURL, "/"),
Expand Down
5 changes: 2 additions & 3 deletions sample-waved.conf
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,8 @@
# feeestimation.mempoolspace.enabled=false

# Override the network-default recommended-fee endpoint. Must be an absolute
# https URL. Empty uses the per-network default: public mempool.space on
# mainnet, Lightning Labs-operated mempool instances on testnet3, testnet4,
# and signet.
# https URL. Empty uses a Lightning Labs-operated mempool instance for the
# configured network.
Comment on lines 226 to +228

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 F2 (Minor) — Config comment claims a default for networks that have none · sample-waved.conf:228

The new text — "Empty uses a Lightning Labs-operated mempool instance for the configured network" — reads as though every network has a default, but DefaultMempoolSpaceURL (chainfees/mempoolspace.go) returns unsupported mempool.space network %q for regtest and simnet, so an empty URL there fails estimator construction rather than resolving to anything. The text this replaces enumerated the networks explicitly and did not have that gap; keeping the enumeration preserves the information the operator needs.

Suggested change
# configured network.
# configured network on mainnet, testnet3, testnet4, and signet.

# feeestimation.mempoolspace.url=

# Number of blocks after which unroll attempts a fee-bump rebroadcast. The zero
Expand Down
10 changes: 5 additions & 5 deletions waved/config_mempoolspace_fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func lndBaseConfig() *Config {
func TestMempoolSpaceFeeAccessorsAreNilSafe(t *testing.T) {
t.Parallel()

const mainnetURL = "https://mempool.staging.lightningcluster.com/" +

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 F4 (Nit) — Test duplicates the production mainnet URL it does not assert on · waved/config_mempoolspace_fee_test.go:26

TestMempoolSpaceFeeAccessorsAreNilSafe only checks that MempoolSpaceFeeURL() round-trips whatever was set, so the value is arbitrary; hardcoding a copy of the real mainnet endpoint (which the waved package cannot reference, since the chainfees constant is unexported) creates a literal that will silently drift from production without any test noticing. An obviously-synthetic URL makes the test's indifference to the value explicit.

"api/v1/fees/recommended"

cfg := &Config{}
require.False(t, cfg.MempoolSpaceFeeEnabled())
require.Empty(t, cfg.MempoolSpaceFeeURL())
Expand All @@ -33,13 +36,10 @@ func TestMempoolSpaceFeeAccessorsAreNilSafe(t *testing.T) {

cfg.FeeEstimation.MempoolSpace = &MempoolSpaceFeeConfig{
Enabled: true,
URL: "https://mempool.space/api/v1/fees/recommended",
URL: mainnetURL,
}
require.True(t, cfg.MempoolSpaceFeeEnabled())
require.Equal(
t, "https://mempool.space/api/v1/fees/recommended",
cfg.MempoolSpaceFeeURL(),
)
require.Equal(t, mainnetURL, cfg.MempoolSpaceFeeURL())
}

// TestDefaultConfigDisablesMempoolSpaceFee locks in that the provider is off by
Expand Down
Loading