diff --git a/blockcache/blockcache.go b/blockcache/blockcache.go index 09d5d33955..532629febe 100644 --- a/blockcache/blockcache.go +++ b/blockcache/blockcache.go @@ -52,22 +52,26 @@ func (bc *BlockCache) GetBlock(hash *chainhash.Hash, } // Fetch the block from the chain backends. - block, err := getBlockImpl(hash) + msgBlock, err := getBlockImpl(hash) if err != nil { return nil, err } + // Make a copy of the block so it won't escape to the heap. + msgBlockCopy := msgBlock.Copy() + block := btcutil.NewBlock(msgBlockCopy) + // Add the new block to blockCache. If the Cache is at its maximum // capacity then the LFU item will be evicted in favour of this new // block. _, err = bc.Cache.Put( *inv, &neutrino.CacheableBlock{ - Block: btcutil.NewBlock(block), + Block: block, }, ) if err != nil { return nil, err } - return block, nil + return msgBlockCopy, nil } diff --git a/build/version.go b/build/version.go index 9ddb6b8c36..176d527ac9 100644 --- a/build/version.go +++ b/build/version.go @@ -43,11 +43,11 @@ const ( AppMinor uint = 17 // AppPatch defines the application patch for this binary. - AppPatch uint = 3 + AppPatch uint = 4 // AppPreRelease MUST only contain characters from semanticAlphabet per // the semantic versioning spec. - AppPreRelease = "beta" + AppPreRelease = "beta.rc1" ) func init() { diff --git a/chainreg/no_chain_backend.go b/chainreg/no_chain_backend.go index 7d601dadff..ce85b0a695 100644 --- a/chainreg/no_chain_backend.go +++ b/chainreg/no_chain_backend.go @@ -4,6 +4,7 @@ import ( "errors" "time" + "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -213,4 +214,10 @@ func (n *NoChainSource) BackEnd() string { return noChainBackendName } +func (n *NoChainSource) TestMempoolAccept([]*wire.MsgTx, + float64) ([]*btcjson.TestMempoolAcceptResult, error) { + + return nil, nil +} + var _ chain.Interface = (*NoChainSource)(nil) diff --git a/docs/release-notes/release-notes-0.17.4.md b/docs/release-notes/release-notes-0.17.4.md new file mode 100644 index 0000000000..ad88c8d093 --- /dev/null +++ b/docs/release-notes/release-notes-0.17.4.md @@ -0,0 +1,64 @@ +# Release Notes +- [Bug Fixes](#bug-fixes) +- [New Features](#new-features) + - [Functional Enhancements](#functional-enhancements) + - [RPC Additions](#rpc-additions) + - [lncli Additions](#lncli-additions) +- [Improvements](#improvements) + - [Functional Updates](#functional-updates) + - [RPC Updates](#rpc-updates) + - [lncli Updates](#lncli-updates) + - [Breaking Changes](#breaking-changes) + - [Performance Improvements](#performance-improvements) +- [Technical and Architectural Updates](#technical-and-architectural-updates) + - [BOLT Spec Updates](#bolt-spec-updates) + - [Testing](#testing) + - [Database](#database) + - [Code Health](#code-health) + - [Tooling and Documentation](#tooling-and-documentation) + +# Bug Fixes + +* [Fix the removal of failed + channels](https://github.com/lightningnetwork/lnd/pull/8406). When a pending + channel opening was pruned from memory no more channels were able to be + created nor accepted. This PR fixes this issue and enhances the test suite + for this behavior. + +* [Fix](https://github.com/lightningnetwork/lnd/pull/8401) an issue that + caused memory leak for users running `lnd` with `bitcoind.rpcpolling=1` + mode. + +* [Fix](https://github.com/lightningnetwork/lnd/pull/8428) an issue for pruned + nodes where the chain sync got lost because fetching of already pruned blocks + from our peers was not garbage collected when the request failed. + +* Let the REST proxy [skip TLS + verification](https://github.com/lightningnetwork/lnd/pull/8437) when + connecting to the gRPC server to prevent invalid cert use when the ephemeral + cert (used with the `--tlsencryptkey` flag) expires. + +# New Features +## Functional Enhancements +## RPC Additions +## lncli Additions + +# Improvements +## Functional Updates +## RPC Updates +## lncli Updates +## Code Health +## Breaking Changes +## Performance Improvements + +# Technical and Architectural Updates +## BOLT Spec Updates +## Testing +## Database +## Code Health +## Tooling and Documentation + +# Contributors (Alphabetical Order) +* Elle Mouton +* Yong Yu +* ziggie1984 diff --git a/go.mod b/go.mod index fcdab1c860..655ccede06 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module github.com/lightningnetwork/lnd require ( github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 - github.com/btcsuite/btcd v0.23.5-0.20230905170901-80f5a0ffdf36 + github.com/btcsuite/btcd v0.24.1-0.20240123000108-62e6af035ec5 github.com/btcsuite/btcd/btcec/v2 v2.3.2 - github.com/btcsuite/btcd/btcutil v1.1.4-0.20230904040416-d4f519f5dc05 + github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/btcutil/psbt v1.1.8 - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 + github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f - github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358 + github.com/btcsuite/btcwallet v0.16.10-0.20240127010340-16b422a2e8bf github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 github.com/btcsuite/btcwallet/walletdb v1.4.0 @@ -19,7 +19,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/go-errors/errors v1.0.1 github.com/golang-migrate/migrate/v4 v4.16.1 - github.com/gorilla/websocket v1.4.2 + github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 @@ -48,7 +48,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/ory/dockertest/v3 v3.10.0 github.com/prometheus/client_golang v1.11.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 github.com/urfave/cli v1.22.9 go.etcd.io/etcd/client/pkg/v3 v3.5.7 diff --git a/go.sum b/go.sum index 5d07264dcc..28c0047ac1 100644 --- a/go.sum +++ b/go.sum @@ -72,10 +72,10 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:osu7EoKiL36UThEgzYPqdRaxeo0NU8VoXqgcnwpey0g= -github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd v0.23.5-0.20230905170901-80f5a0ffdf36 h1:g/UbZ6iSzcUH9kEvC+rB8UBCqahmt69e8y6nCegczbg= -github.com/btcsuite/btcd v0.23.5-0.20230905170901-80f5a0ffdf36/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.1-0.20240123000108-62e6af035ec5 h1:8BHBWvtP6kkzvmCpyWEznq4eS0gfLOSVuXLesv413Xs= +github.com/btcsuite/btcd v0.24.1-0.20240123000108-62e6af035ec5/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= @@ -84,19 +84,19 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34= -github.com/btcsuite/btcd/btcutil v1.1.4-0.20230904040416-d4f519f5dc05 h1:aemxF+69pT9sYC5E6Qj71zQVHcF72m0BNcVhCl3/thU= -github.com/btcsuite/btcd/btcutil v1.1.4-0.20230904040416-d4f519f5dc05/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= github.com/btcsuite/btcd/btcutil/psbt v1.1.8 h1:4voqtT8UppT7nmKQkXV+T9K8UyQjKOn2z/ycpmJK8wg= github.com/btcsuite/btcd/btcutil/psbt v1.1.8/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358 h1:lZUSo6TISHUJQxpn/AniW5gqaN1iRNS87SDWvV3AHfg= -github.com/btcsuite/btcwallet v0.16.10-0.20231129183218-5df09dd43358/go.mod h1:WSKhOJWUmUOHKCKEzdt+jWAHFAE/t4RqVbCwL2pEdiU= +github.com/btcsuite/btcwallet v0.16.10-0.20240127010340-16b422a2e8bf h1:eNjj5R0tKP48NQxDkuKr+C9frZsdzTAemEwu75ZDQg0= +github.com/btcsuite/btcwallet v0.16.10-0.20240127010340-16b422a2e8bf/go.mod h1:LzcW/LYkQLgDufv6Ouw4cOIW0YsY+A60MTtc61/OZTU= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 h1:etuLgGEojecsDOYTII8rYiGHjGyV5xTqsXi+ZQ715UU= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2/go.mod h1:Zpk/LOb2sKqwP2lmHjaZT9AdaKsHPSbNLm2Uql5IQ/0= github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg= @@ -295,8 +295,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -602,8 +602,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= diff --git a/itest/list_on_test.go b/itest/list_on_test.go index d5664d3dfe..8bf8b0923b 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -550,4 +550,8 @@ var allTestCases = []*lntest.TestCase{ Name: "update pending open channels", TestFunc: testUpdateOnPendingOpenChannels, }, + { + Name: "fail funding flow psbt", + TestFunc: testPsbtChanFundingFailFlow, + }, } diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 3bf1cfa04f..6c9d92d603 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -21,6 +21,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/node" + "github.com/lightningnetwork/lnd/lnwallet/chanfunding" "github.com/stretchr/testify/require" ) @@ -1340,3 +1341,50 @@ func sendAllCoinsToAddrType(ht *lntest.HarnessTest, ht.MineBlocksAndAssertNumTxes(1, 1) ht.WaitForBlockchainSync(hn) } + +// testPsbtChanFundingFailFlow tests the failing of a funding flow by the +// remote peer and that the initiator receives the expected error and aborts +// the channel opening. The psbt funding flow is used to simulate this behavior +// because we can easily let the remote peer run into the timeout. +func testPsbtChanFundingFailFlow(ht *lntest.HarnessTest) { + const chanSize = funding.MaxBtcFundingAmount + + // Decrease the timeout window for the remote peer to accelerate the + // funding fail process. + args := []string{ + "--dev.reservationtimeout=1s", + "--dev.zombiesweeperinterval=1s", + } + ht.RestartNodeWithExtraArgs(ht.Bob, args) + + // Before we start the test, we'll ensure both sides are connected so + // the funding flow can be properly executed. + alice := ht.Alice + bob := ht.Bob + ht.EnsureConnected(alice, bob) + + // At this point, we can begin our PSBT channel funding workflow. We'll + // start by generating a pending channel ID externally that will be used + // to track this new funding type. + pendingChanID := ht.Random32Bytes() + + // Now that we have the pending channel ID, Alice will open the channel + // by specifying a PSBT shim. + chanUpdates, _ := ht.OpenChannelPsbt( + alice, bob, lntest.OpenChannelParams{ + Amt: chanSize, + FundingShim: &lnrpc.FundingShim{ + Shim: &lnrpc.FundingShim_PsbtShim{ + PsbtShim: &lnrpc.PsbtShim{ + PendingChanId: pendingChanID, + }, + }, + }, + }, + ) + + // We received the AcceptChannel msg from our peer but we are not going + // to fund this channel but instead wait for our peer to fail the + // funding workflow with an internal error. + ht.ReceiveOpenChannelError(chanUpdates, chanfunding.ErrRemoteCanceled) +} diff --git a/lncfg/config.go b/lncfg/config.go index 2f3e014c88..07c37875d0 100644 --- a/lncfg/config.go +++ b/lncfg/config.go @@ -5,6 +5,7 @@ import ( "os/user" "path/filepath" "strings" + "time" ) const ( @@ -67,6 +68,14 @@ const ( // peer and a block arriving during that round trip to trigger force // closure. DefaultOutgoingCltvRejectDelta = DefaultOutgoingBroadcastDelta + 3 + + // DefaultReservationTimeout is the default time we wait until we remove + // an unfinished (zombiestate) open channel flow from memory. + DefaultReservationTimeout = 10 * time.Minute + + // DefaultZombieSweeperInterval is the default time interval at which + // unfinished (zombiestate) open channel flows are purged from memory. + DefaultZombieSweeperInterval = 1 * time.Minute ) // CleanAndExpandPath expands environment variables and leading ~ in the diff --git a/lncfg/dev.go b/lncfg/dev.go index ac47b0f5ed..0bc305cff0 100644 --- a/lncfg/dev.go +++ b/lncfg/dev.go @@ -2,7 +2,9 @@ package lncfg -import "time" +import ( + "time" +) // IsDevBuild returns a bool to indicate whether we are in a development // environment. @@ -21,3 +23,13 @@ type DevConfig struct{} func (d *DevConfig) ChannelReadyWait() time.Duration { return 0 } + +// GetReservationTimeout returns the config value for `ReservationTimeout`. +func (d *DevConfig) GetReservationTimeout() time.Duration { + return DefaultReservationTimeout +} + +// GetZombieSweeperInterval returns the config value for`ZombieSweeperInterval`. +func (d *DevConfig) GetZombieSweeperInterval() time.Duration { + return DefaultZombieSweeperInterval +} diff --git a/lncfg/dev_integration.go b/lncfg/dev_integration.go index c55b2efa7f..526c86b6aa 100644 --- a/lncfg/dev_integration.go +++ b/lncfg/dev_integration.go @@ -2,7 +2,9 @@ package lncfg -import "time" +import ( + "time" +) // IsDevBuild returns a bool to indicate whether we are in a development // environment. @@ -18,9 +20,29 @@ func IsDevBuild() bool { //nolint:lll type DevConfig struct { ProcessChannelReadyWait time.Duration `long:"processchannelreadywait" description:"Time to sleep before processing remote node's channel_ready message."` + ReservationTimeout time.Duration `long:"reservationtimeout" description:"The maximum time we keep a pending channel open flow in memory."` + ZombieSweeperInterval time.Duration `long:"zombiesweeperinterval" description:"The time interval at which channel opening flows are evaluated for zombie status."` } // ChannelReadyWait returns the config value `ProcessChannelReadyWait`. func (d *DevConfig) ChannelReadyWait() time.Duration { return d.ProcessChannelReadyWait } + +// GetReservationTimeout returns the config value for `ReservationTimeout`. +func (d *DevConfig) GetReservationTimeout() time.Duration { + if d.ReservationTimeout == 0 { + return DefaultReservationTimeout + } + + return d.ReservationTimeout +} + +// GetZombieSweeperInterval returns the config value for`ZombieSweeperInterval`. +func (d *DevConfig) GetZombieSweeperInterval() time.Duration { + if d.ZombieSweeperInterval == 0 { + return DefaultZombieSweeperInterval + } + + return d.ZombieSweeperInterval +} diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 6ead7d2777..cb65d55a64 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -288,6 +288,16 @@ func (h *HarnessTest) ReceiveOpenChannelUpdate( return update } +// ReceiveOpenChannelError waits for the expected error during the open channel +// flow from the peer or times out. +func (h *HarnessTest) ReceiveOpenChannelError( + stream rpc.OpenChanClient, expectedErr error) { + + _, err := h.receiveOpenChannelUpdate(stream) + require.Contains(h, err.Error(), expectedErr.Error(), + "error not matched") +} + // receiveOpenChannelUpdate waits until a message or an error is received on // the stream or the timeout is reached. // diff --git a/peer/brontide.go b/peer/brontide.go index ecb3d4d590..57a6e28613 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -507,8 +507,9 @@ func NewBrontide(cfg Config) *Brontide { activeChannels: &lnutils.SyncMap[ lnwire.ChannelID, *lnwallet.LightningChannel, ]{}, - newActiveChannel: make(chan *newChannelMsg, 1), - newPendingChannel: make(chan *newChannelMsg, 1), + newActiveChannel: make(chan *newChannelMsg, 1), + newPendingChannel: make(chan *newChannelMsg, 1), + removePendingChannel: make(chan *newChannelMsg), activeMsgStreams: make(map[lnwire.ChannelID]*msgStream), activeChanCloses: make(map[lnwire.ChannelID]*chancloser.ChanCloser), diff --git a/peer/brontide_test.go b/peer/brontide_test.go index 103b59ea53..c6445e5899 100644 --- a/peer/brontide_test.go +++ b/peer/brontide_test.go @@ -2,6 +2,7 @@ package peer import ( "bytes" + "fmt" "testing" "time" @@ -16,6 +17,7 @@ import ( "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/lntest/mock" + "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chancloser" "github.com/lightningnetwork/lnd/lnwire" @@ -1446,3 +1448,88 @@ func TestStartupWriteMessageRace(t *testing.T) { } } } + +// TestRemovePendingChannel checks that we are able to remove a pending channel +// successfully from the peers channel map. This also makes sure the +// removePendingChannel is initialized so we don't send to a nil channel and +// get stuck. +func TestRemovePendingChannel(t *testing.T) { + t.Parallel() + + // Set up parameters for createTestPeer. + notifier := &mock.ChainNotifier{ + SpendChan: make(chan *chainntnfs.SpendDetail), + EpochChan: make(chan *chainntnfs.BlockEpoch), + ConfChan: make(chan *chainntnfs.TxConfirmation), + } + broadcastTxChan := make(chan *wire.MsgTx) + mockSwitch := &mockMessageSwitch{} + + // createTestPeer creates a peer and a channel with that peer. + peer, _, err := createTestPeer( + t, notifier, broadcastTxChan, noUpdate, mockSwitch, + ) + require.NoError(t, err, "unable to create test channel") + + // Add a pending channel to the peer Alice. + errChan := make(chan error, 1) + pendingChanID := lnwire.ChannelID{1} + req := &newChannelMsg{ + channelID: pendingChanID, + err: errChan, + } + + select { + case peer.newPendingChannel <- req: + // Operation completed successfully + case <-time.After(timeout): + t.Fatalf("not able to remove pending channel") + } + + // Make sure the channel was added as a pending channel. + // The peer was already created with one active channel therefore the + // `activeChannels` had already one channel prior to adding the new one. + // The `addedChannels` map only tracks new channels in the current life + // cycle therefore the initial channel is not part of it. + err = wait.NoError(func() error { + if peer.activeChannels.Len() == 2 && + peer.addedChannels.Len() == 1 { + + return nil + } + + return fmt.Errorf("pending channel not successfully added") + }, wait.DefaultTimeout) + + require.NoError(t, err) + + // Now try to remove it, the errChan needs to be reopened because it was + // closed during the pending channel registration above. + errChan = make(chan error, 1) + req = &newChannelMsg{ + channelID: pendingChanID, + err: errChan, + } + + select { + case peer.removePendingChannel <- req: + // Operation completed successfully + case <-time.After(timeout): + t.Fatalf("not able to remove pending channel") + } + + // Make sure the pending channel is successfully removed from both + // channel maps. + // The initial channel between the peer is still active at this point. + err = wait.NoError(func() error { + if peer.activeChannels.Len() == 1 && + peer.addedChannels.Len() == 0 { + + return nil + } + + return fmt.Errorf("pending channel not successfully removed") + }, wait.DefaultTimeout) + + require.NoError(t, err) +} diff --git a/server.go b/server.go index b59f873cf1..e371da5ac8 100644 --- a/server.go +++ b/server.go @@ -1277,6 +1277,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr, return ourPolicy, err } + // For the reservationTimeout and the zombieSweeperInterval different + // values are set in case we are in a dev environment so enhance test + // capacilities. + reservationTimeout := lncfg.DefaultReservationTimeout + zombieSweeperInterval := lncfg.DefaultZombieSweeperInterval + // Get the development config for funding manager. If we are not in // development mode, this would be nil. var devCfg *funding.DevConfig @@ -1284,6 +1290,13 @@ func newServer(cfg *Config, listenAddrs []net.Addr, devCfg = &funding.DevConfig{ ProcessChannelReadyWait: cfg.Dev.ChannelReadyWait(), } + + reservationTimeout = cfg.Dev.GetReservationTimeout() + zombieSweeperInterval = cfg.Dev.GetZombieSweeperInterval() + + srvrLog.Debugf("Using the dev config for the fundingMgr: %v, "+ + "reservationTimeout=%v, zombieSweeperInterval=%v", + devCfg, reservationTimeout, zombieSweeperInterval) } //nolint:lll @@ -1446,8 +1459,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, // channel bandwidth. return uint16(input.MaxHTLCNumber / 2) }, - ZombieSweeperInterval: 1 * time.Minute, - ReservationTimeout: 10 * time.Minute, + ZombieSweeperInterval: zombieSweeperInterval, + ReservationTimeout: reservationTimeout, MinChanSize: btcutil.Amount(cfg.MinChanSize), MaxChanSize: btcutil.Amount(cfg.MaxChanSize), MaxPendingChannels: cfg.MaxPendingChannels, diff --git a/tls_manager.go b/tls_manager.go index 577d2fc6db..7694e17780 100644 --- a/tls_manager.go +++ b/tls_manager.go @@ -132,32 +132,27 @@ func (t *TLSManager) getConfig() ([]grpc.ServerOption, []grpc.DialOption, // and override the TLS config's GetCertificate function. cleanUp := t.setUpLetsEncrypt(&certData, tlsCfg) - // If we're using the ephemeral certificate, we need to use the - // ephemeral cert path. - certPath := t.cfg.TLSCertPath - if t.ephemeralCertPath != "" { - certPath = t.ephemeralCertPath - } - // Now that we know that we have a certificate, let's generate the // required config options. - restCreds, err := credentials.NewClientTLSFromFile( - certPath, "", - ) - if err != nil { - return nil, nil, nil, nil, err - } - serverCreds := credentials.NewTLS(tlsCfg) serverOpts := []grpc.ServerOption{grpc.Creds(serverCreds)} - // For our REST dial options, we'll still use TLS, but also increase - // the max message size that we'll decode to allow clients to hit - // endpoints which return more data such as the DescribeGraph call. + // For our REST dial options, we skip TLS verification, and we also + // increase the max message size that we'll decode to allow clients to + // hit endpoints which return more data such as the DescribeGraph call. // We set this to 200MiB atm. Should be the same value as maxMsgRecvSize // in cmd/lncli/main.go. restDialOpts := []grpc.DialOption{ - grpc.WithTransportCredentials(restCreds), + // We are forwarding the requests directly to the address of our + // own local listener. To not need to mess with the TLS + // certificate (which might be tricky if we're using Let's + // Encrypt or if the ephemeral tls cert is being used), we just + // skip the certificate verification. Injecting a malicious + // hostname into the listener address will result in an error + // on startup so this should be quite safe. + grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{InsecureSkipVerify: true}, + )), grpc.WithDefaultCallOptions( grpc.MaxCallRecvMsgSize(lnrpc.MaxGrpcMsgSize), ),