diff --git a/config.go b/config.go index 55f03509d..ab01e897c 100644 --- a/config.go +++ b/config.go @@ -400,19 +400,6 @@ func loadAndValidateConfig(interceptor signal.Interceptor) (*Config, error) { cfg.Lnd.RPCMiddleware.Enable = true } - // For the integration of tapd with lnd, we need to allow tapd to send - // custom error messages to peers through the SendCustomMessage RPC in - // lnd. Since the error messages aren't in the custom range, we - // explicitly need to allow them. This isn't currently needed in remote - // mode, because custom channels are only available if both lnd and tapd - // are running in integrated mode. - if !cfg.lndRemote { - cfg.Lnd.ProtocolOptions.CustomMessage = append( - cfg.Lnd.ProtocolOptions.CustomMessage, - lnwire.MsgError, - ) - } - // Validate the lightning-terminal config options. litDir := lnd.CleanAndExpandPath(preCfg.LitDir) cfg.LetsEncryptDir = lncfg.CleanAndExpandPath(cfg.LetsEncryptDir) @@ -620,6 +607,19 @@ func loadConfigFile(preCfg *Config, interceptor signal.Interceptor) (*Config, // configuration is fully valid. This also sets up the main logger that // logs to a sub-directory in the .lnd folder. case ModeIntegrated: + // For the integration of tapd with lnd, we need to allow tapd + // to send custom error messages to peers through the + // SendCustomMessage RPC in lnd. Since the error messages aren't + // in the custom range, we explicitly need to allow them. This + // isn't currently needed in remote mode, because custom + // channels are only available if both lnd and tapd are running + // in integrated mode. We need to set this value before we call + // lnd.ValidateConfig() below, because that's what's going to + // inject these values into the lnwire package. + cfg.Lnd.ProtocolOptions.CustomMessage = append( + cfg.Lnd.ProtocolOptions.CustomMessage, lnwire.MsgError, + ) + var err error cfg.Lnd, err = lnd.ValidateConfig( *cfg.Lnd, interceptor, fileParser, flagParser, diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index 1ded9f12f..4ba604bcf 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -6,6 +6,7 @@ import ( "slices" "time" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightninglabs/taproot-assets/itest" "github.com/lightninglabs/taproot-assets/proof" @@ -1160,6 +1161,36 @@ func testCustomChannelsForceClose(_ context.Context, net *NetworkHarness, syncUniverses(t.t, charlieTap, dave) t.Logf("Universes synced between all nodes, distributing assets...") + // Before we actually create the asset channel, we want to make sure + // that failed attempts of creating a channel (e.g. due to insufficient + // on-chain funds) are cleaned up properly on the recipient side. + // We do this by sending all of Charlie's coins to a burn address then + // just sending him 50k sats, which isn't enough to fund a channel. + _, err = charlie.LightningClient.SendCoins( + ctxb, &lnrpc.SendCoinsRequest{ + Addr: burnAddr, + SendAll: true, + MinConfs: 0, + SpendUnconfirmed: true, + }, + ) + require.NoError(t.t, err) + net.SendCoins(t.t, 50_000, charlie) + + // The attempt should fail. But the recipient should receive the error, + // clean up the state and allow Charlie to try again after acquiring + // more funds. + _, err = charlieTap.FundChannel(ctxb, &tchrpc.FundChannelRequest{ + AssetAmount: fundingAmount, + AssetId: assetID, + PeerPubkey: dave.PubKey[:], + FeeRateSatPerVbyte: 5, + }) + require.ErrorContains(t.t, err, "not enough witness outputs to create") + + // Now we'll fund the channel with the correct amount. + net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, charlie) + // Next we can open an asset channel from Charlie -> Dave, then kick // off the main scenario. t.Logf("Opening asset channels...")