mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-03 17:26:57 +01:00
multi: Add itest for funding timeout
This commit adds an integration test that verifies the funding timeout behavior in the funding manager, in dev/integration test. Signed-off-by: Nishant Bansal <nishant.bansal.282003@gmail.com>
This commit is contained in:
parent
5fe900d18d
commit
49d3fcf5b2
9 changed files with 131 additions and 22 deletions
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/labels"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnpeer"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
|
@ -101,11 +102,6 @@ const (
|
|||
|
||||
msgBufferSize = 50
|
||||
|
||||
// MaxWaitNumBlocksFundingConf is the maximum number of blocks to wait
|
||||
// for the funding transaction to be confirmed before forgetting
|
||||
// channels that aren't initiated by us. 2016 blocks is ~2 weeks.
|
||||
MaxWaitNumBlocksFundingConf = 2016
|
||||
|
||||
// pendingChansLimit is the maximum number of pending channels that we
|
||||
// can have. After this point, pending channel opens will start to be
|
||||
// rejected.
|
||||
|
@ -339,6 +335,11 @@ type DevConfig struct {
|
|||
// remote node's channel ready message once the channel as been marked
|
||||
// as `channelReadySent`.
|
||||
ProcessChannelReadyWait time.Duration
|
||||
|
||||
// MaxWaitNumBlocksFundingConf is the maximum number of blocks to wait
|
||||
// for the funding transaction to be confirmed before forgetting
|
||||
// channels that aren't initiated by us.
|
||||
MaxWaitNumBlocksFundingConf uint32
|
||||
}
|
||||
|
||||
// Config defines the configuration for the FundingManager. All elements
|
||||
|
@ -3164,9 +3165,20 @@ func (f *Manager) waitForTimeout(completeChan *channeldb.OpenChannel,
|
|||
|
||||
defer epochClient.Cancel()
|
||||
|
||||
// For the waitBlocksForFundingConf different values are set in case we
|
||||
// are in a dev environment so enhance test capabilities.
|
||||
var waitBlocksForFundingConf uint32 = lncfg.
|
||||
DefaultMaxWaitNumBlocksFundingConf
|
||||
|
||||
// Get the waitBlocksForFundingConf. If we are not in development mode,
|
||||
// this would be DefaultMaxWaitNumBlocksFundingConf.
|
||||
if lncfg.IsDevBuild() {
|
||||
waitBlocksForFundingConf = f.cfg.Dev.MaxWaitNumBlocksFundingConf
|
||||
}
|
||||
|
||||
// On block maxHeight we will cancel the funding confirmation wait.
|
||||
broadcastHeight := completeChan.BroadcastHeight()
|
||||
maxHeight := broadcastHeight + MaxWaitNumBlocksFundingConf
|
||||
maxHeight := broadcastHeight + waitBlocksForFundingConf
|
||||
for {
|
||||
select {
|
||||
case epoch, ok := <-epochClient.Epochs:
|
||||
|
@ -3182,7 +3194,7 @@ func (f *Manager) waitForTimeout(completeChan *channeldb.OpenChannel,
|
|||
log.Warnf("Waited for %v blocks without "+
|
||||
"seeing funding transaction confirmed,"+
|
||||
" cancelling.",
|
||||
MaxWaitNumBlocksFundingConf)
|
||||
waitBlocksForFundingConf)
|
||||
|
||||
// Notify the caller of the timeout.
|
||||
close(timeoutChan)
|
||||
|
|
|
@ -2334,14 +2334,15 @@ func TestFundingManagerFundingTimeout(t *testing.T) {
|
|||
// mine 2016-1, and check that it is still pending.
|
||||
bob.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight +
|
||||
MaxWaitNumBlocksFundingConf - 1,
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf - 1,
|
||||
}
|
||||
|
||||
// Bob should still be waiting for the channel to open.
|
||||
assertNumPendingChannelsRemains(t, bob, 1)
|
||||
|
||||
bob.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight + MaxWaitNumBlocksFundingConf,
|
||||
Height: fundingBroadcastHeight +
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf,
|
||||
}
|
||||
|
||||
// Bob should have sent an Error message to Alice.
|
||||
|
@ -2387,16 +2388,16 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
|
|||
t.Fatalf("alice did not publish funding tx")
|
||||
}
|
||||
|
||||
// Increase the height to 1 minus the MaxWaitNumBlocksFundingConf
|
||||
// Increase the height to 1 minus the DefaultMaxWaitNumBlocksFundingConf
|
||||
// height.
|
||||
alice.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight +
|
||||
MaxWaitNumBlocksFundingConf - 1,
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf - 1,
|
||||
}
|
||||
|
||||
bob.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight +
|
||||
MaxWaitNumBlocksFundingConf - 1,
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf - 1,
|
||||
}
|
||||
|
||||
// Assert both and Alice and Bob still have 1 pending channels.
|
||||
|
@ -2404,13 +2405,16 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
|
|||
|
||||
assertNumPendingChannelsRemains(t, bob, 1)
|
||||
|
||||
// Increase both Alice and Bob to MaxWaitNumBlocksFundingConf height.
|
||||
// Increase both Alice and Bob to DefaultMaxWaitNumBlocksFundingConf
|
||||
// height.
|
||||
alice.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight + MaxWaitNumBlocksFundingConf,
|
||||
Height: fundingBroadcastHeight +
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf,
|
||||
}
|
||||
|
||||
bob.mockNotifier.epochChan <- &chainntnfs.BlockEpoch{
|
||||
Height: fundingBroadcastHeight + MaxWaitNumBlocksFundingConf,
|
||||
Height: fundingBroadcastHeight +
|
||||
lncfg.DefaultMaxWaitNumBlocksFundingConf,
|
||||
}
|
||||
|
||||
// Since Alice was the initiator, the channel should not have timed out.
|
||||
|
|
|
@ -670,6 +670,10 @@ var allTestCases = []*lntest.TestCase{
|
|||
Name: "fee replacement",
|
||||
TestFunc: testFeeReplacement,
|
||||
},
|
||||
{
|
||||
Name: "funding manager funding timeout",
|
||||
TestFunc: testFundingManagerFundingTimeout,
|
||||
},
|
||||
}
|
||||
|
||||
// appendPrefixed is used to add a prefix to each test name in the subtests
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/chainreg"
|
||||
"github.com/lightningnetwork/lnd/funding"
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
|
@ -844,7 +845,7 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) {
|
|||
// blocks and verify the value of FundingExpiryBlock at each step.
|
||||
const numEmptyBlocks = 3
|
||||
for i := int32(0); i < numEmptyBlocks; i++ {
|
||||
expectedVal := funding.MaxWaitNumBlocksFundingConf - i
|
||||
expectedVal := lncfg.DefaultMaxWaitNumBlocksFundingConf - i
|
||||
pending := ht.AssertNumPendingOpenChannels(alice, 1)
|
||||
require.Equal(ht, expectedVal, pending[0].FundingExpiryBlocks)
|
||||
pending = ht.AssertNumPendingOpenChannels(bob, 1)
|
||||
|
@ -967,3 +968,55 @@ func testOpenChannelLockedBalance(ht *lntest.HarnessTest) {
|
|||
// Finally, we check to make sure the balance is unlocked again.
|
||||
ht.AssertWalletLockedBalance(alice, 0)
|
||||
}
|
||||
|
||||
// testFundingManagerFundingTimeout tests that after an OpenChannel, and before
|
||||
// the funding transaction is confirmed, if a user is not the channel initiator,
|
||||
// the channel is forgotten after waitBlocksForFundingConf.
|
||||
func testFundingManagerFundingTimeout(ht *lntest.HarnessTest) {
|
||||
// Set the maximum wait blocks for funding confirmation.
|
||||
waitBlocksForFundingConf := 10
|
||||
|
||||
// Create nodes for testing, ensuring Alice has sufficient initial
|
||||
// funds.
|
||||
alice := ht.NewNodeWithCoins("Alice", nil)
|
||||
bob := ht.NewNode("Bob", nil)
|
||||
|
||||
// Restart Bob with the custom configuration for funding confirmation
|
||||
// timeout.
|
||||
ht.RestartNodeWithExtraArgs(bob, []string{
|
||||
"--dev.maxwaitnumblocksfundingconf=10",
|
||||
})
|
||||
|
||||
// Ensure Alice and Bob are connected.
|
||||
ht.EnsureConnected(alice, bob)
|
||||
|
||||
// Open the channel between Alice and Bob. This runs through the process
|
||||
// up until the funding transaction is broadcasted.
|
||||
ht.OpenChannelAssertPending(alice, bob, lntest.OpenChannelParams{
|
||||
Amt: 500000,
|
||||
PushAmt: 0,
|
||||
})
|
||||
|
||||
// At this point, both nodes have a pending channel waiting for the
|
||||
// funding transaction to be confirmed.
|
||||
ht.AssertNumPendingOpenChannels(alice, 1)
|
||||
ht.AssertNumPendingOpenChannels(bob, 1)
|
||||
|
||||
// We expect Bob to forget the channel after waitBlocksForFundingConf
|
||||
// blocks, so mine waitBlocksForFundingConf-1, and check that it is
|
||||
// still pending.
|
||||
ht.MineEmptyBlocks(waitBlocksForFundingConf - 1)
|
||||
ht.AssertNumPendingOpenChannels(bob, 1)
|
||||
|
||||
// Now mine one additional block to reach waitBlocksForFundingConf.
|
||||
ht.MineEmptyBlocks(1)
|
||||
|
||||
// Bob should now have forgotten the channel.
|
||||
ht.AssertNumPendingOpenChannels(bob, 0)
|
||||
|
||||
// Since Alice was the initiator, her pending channel should remain.
|
||||
ht.AssertNumPendingOpenChannels(alice, 1)
|
||||
|
||||
// Cleanup the mempool by mining blocks.
|
||||
ht.MineBlocksAndAssertNumTxes(6, 1)
|
||||
}
|
||||
|
|
|
@ -72,6 +72,11 @@ const (
|
|||
// DefaultZombieSweeperInterval is the default time interval at which
|
||||
// unfinished (zombiestate) open channel flows are purged from memory.
|
||||
DefaultZombieSweeperInterval = 1 * time.Minute
|
||||
|
||||
// DefaultMaxWaitNumBlocksFundingConf is the maximum number of blocks to
|
||||
// wait for the funding transaction to confirm before forgetting
|
||||
// channels that aren't initiated by us. 2016 blocks is ~2 weeks.
|
||||
DefaultMaxWaitNumBlocksFundingConf = 2016
|
||||
)
|
||||
|
||||
// CleanAndExpandPath expands environment variables and leading ~ in the
|
||||
|
|
|
@ -46,3 +46,9 @@ func (d *DevConfig) GetReservationTimeout() time.Duration {
|
|||
func (d *DevConfig) GetZombieSweeperInterval() time.Duration {
|
||||
return DefaultZombieSweeperInterval
|
||||
}
|
||||
|
||||
// GetMaxWaitNumBlocksFundingConf returns the config value for
|
||||
// `MaxWaitNumBlocksFundingConf`.
|
||||
func (d *DevConfig) GetMaxWaitNumBlocksFundingConf() uint32 {
|
||||
return DefaultMaxWaitNumBlocksFundingConf
|
||||
}
|
||||
|
|
|
@ -21,10 +21,11 @@ func IsDevBuild() bool {
|
|||
//
|
||||
//nolint:ll
|
||||
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."`
|
||||
UnsafeDisconnect bool `long:"unsafedisconnect" description:"Allows the rpcserver to intentionally disconnect from peers with open channels."`
|
||||
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."`
|
||||
UnsafeDisconnect bool `long:"unsafedisconnect" description:"Allows the rpcserver to intentionally disconnect from peers with open channels."`
|
||||
MaxWaitNumBlocksFundingConf uint32 `long:"maxwaitnumblocksfundingconf" description:"Maximum blocks to wait for funding confirmation before discarding non-initiated channels."`
|
||||
}
|
||||
|
||||
// ChannelReadyWait returns the config value `ProcessChannelReadyWait`.
|
||||
|
@ -54,3 +55,13 @@ func (d *DevConfig) GetZombieSweeperInterval() time.Duration {
|
|||
func (d *DevConfig) GetUnsafeDisconnect() bool {
|
||||
return d.UnsafeDisconnect
|
||||
}
|
||||
|
||||
// GetMaxWaitNumBlocksFundingConf returns the config value for
|
||||
// `MaxWaitNumBlocksFundingConf`.
|
||||
func (d *DevConfig) GetMaxWaitNumBlocksFundingConf() uint32 {
|
||||
if d.MaxWaitNumBlocksFundingConf == 0 {
|
||||
return DefaultMaxWaitNumBlocksFundingConf
|
||||
}
|
||||
|
||||
return d.MaxWaitNumBlocksFundingConf
|
||||
}
|
||||
|
|
16
rpcserver.go
16
rpcserver.go
|
@ -3850,9 +3850,21 @@ func (r *rpcServer) fetchPendingOpenChannels() (pendingOpenChannels, error) {
|
|||
commitBaseWeight := blockchain.GetTransactionWeight(utx)
|
||||
commitWeight := commitBaseWeight + witnessWeight
|
||||
|
||||
// For the waitBlocksForFundingConf different values are set in
|
||||
// case we are in dev environment so enhance test capabilities.
|
||||
var waitBlocksForFundingConf uint32 = lncfg.
|
||||
DefaultMaxWaitNumBlocksFundingConf
|
||||
|
||||
// Get the waitBlocksForFundingConf. If we are not in
|
||||
// development mode, this would be nil.
|
||||
if lncfg.IsDevBuild() {
|
||||
waitBlocksForFundingConf = r.cfg.Dev.
|
||||
GetMaxWaitNumBlocksFundingConf()
|
||||
}
|
||||
|
||||
// FundingExpiryBlocks is the distance from the current block
|
||||
// height to the broadcast height + MaxWaitNumBlocksFundingConf.
|
||||
maxFundingHeight := funding.MaxWaitNumBlocksFundingConf +
|
||||
// height to the broadcast height + waitBlocksForFundingConf.
|
||||
maxFundingHeight := waitBlocksForFundingConf +
|
||||
pendingChan.BroadcastHeight()
|
||||
fundingExpiryBlocks := int32(maxFundingHeight) - currentHeight
|
||||
|
||||
|
|
|
@ -1449,6 +1449,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
if lncfg.IsDevBuild() {
|
||||
devCfg = &funding.DevConfig{
|
||||
ProcessChannelReadyWait: cfg.Dev.ChannelReadyWait(),
|
||||
MaxWaitNumBlocksFundingConf: cfg.Dev.
|
||||
GetMaxWaitNumBlocksFundingConf(),
|
||||
}
|
||||
|
||||
reservationTimeout = cfg.Dev.GetReservationTimeout()
|
||||
|
|
Loading…
Add table
Reference in a new issue