Merge pull request #4429 from Roasbeef/i-wumbo-you-wumbo-he-she-wumbo
multi: I wumbo, you wumbo, he she wumbo
This commit is contained in:
commit
2f0ccaead1
@ -47,4 +47,8 @@ var defaultSetDesc = setDesc{
|
|||||||
SetInit: {}, // I
|
SetInit: {}, // I
|
||||||
SetNodeAnn: {}, // N
|
SetNodeAnn: {}, // N
|
||||||
},
|
},
|
||||||
|
lnwire.WumboChannelsOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@ type Config struct {
|
|||||||
|
|
||||||
// NoAnchors unsets any bits signaling support for anchor outputs.
|
// NoAnchors unsets any bits signaling support for anchor outputs.
|
||||||
NoAnchors bool
|
NoAnchors bool
|
||||||
|
|
||||||
|
// NoWumbo unsets any bits signalling support for wumbo channels.
|
||||||
|
NoWumbo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager is responsible for generating feature vectors for different requested
|
// Manager is responsible for generating feature vectors for different requested
|
||||||
@ -36,7 +39,7 @@ func NewManager(cfg Config) (*Manager, error) {
|
|||||||
return newManager(cfg, defaultSetDesc)
|
return newManager(cfg, defaultSetDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newManager creates a new feeature Manager, applying any custom modifications
|
// newManager creates a new feature Manager, applying any custom modifications
|
||||||
// to its feature sets before returning. This method accepts the setDesc as its
|
// to its feature sets before returning. This method accepts the setDesc as its
|
||||||
// own parameter so that it can be unit tested.
|
// own parameter so that it can be unit tested.
|
||||||
func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
||||||
@ -83,6 +86,10 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
|||||||
raw.Unset(lnwire.AnchorsOptional)
|
raw.Unset(lnwire.AnchorsOptional)
|
||||||
raw.Unset(lnwire.AnchorsRequired)
|
raw.Unset(lnwire.AnchorsRequired)
|
||||||
}
|
}
|
||||||
|
if cfg.NoWumbo {
|
||||||
|
raw.Unset(lnwire.WumboChannelsOptional)
|
||||||
|
raw.Unset(lnwire.WumboChannelsRequired)
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that all of our feature sets properly set any
|
// Ensure that all of our feature sets properly set any
|
||||||
// dependent features.
|
// dependent features.
|
||||||
|
@ -227,6 +227,10 @@ func newSerializedKey(pubKey *btcec.PublicKey) serializedPubKey {
|
|||||||
// within the configuration MUST be non-nil for the FundingManager to carry out
|
// within the configuration MUST be non-nil for the FundingManager to carry out
|
||||||
// its duties.
|
// its duties.
|
||||||
type fundingConfig struct {
|
type fundingConfig struct {
|
||||||
|
// NoWumboChans indicates if we're to reject all incoming wumbo channel
|
||||||
|
// requests, and also reject all outgoing wumbo channel requests.
|
||||||
|
NoWumboChans bool
|
||||||
|
|
||||||
// IDKey is the PublicKey that is used to identify this node within the
|
// IDKey is the PublicKey that is used to identify this node within the
|
||||||
// Lightning Network.
|
// Lightning Network.
|
||||||
IDKey *btcec.PublicKey
|
IDKey *btcec.PublicKey
|
||||||
@ -1236,8 +1240,9 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We'll reject any request to create a channel that's above the
|
// We'll reject any request to create a channel that's above the
|
||||||
// current soft-limit for channel size.
|
// current soft-limit for channel size, but only if we're rejecting all
|
||||||
if msg.FundingAmount > MaxFundingAmount {
|
// wumbo channel initiations.
|
||||||
|
if f.cfg.NoWumboChans && msg.FundingAmount > MaxFundingAmount {
|
||||||
f.failFundingFlow(
|
f.failFundingFlow(
|
||||||
fmsg.peer, fmsg.msg.PendingChannelID,
|
fmsg.peer, fmsg.msg.PendingChannelID,
|
||||||
lnwire.ErrChanTooLarge,
|
lnwire.ErrChanTooLarge,
|
||||||
|
@ -3176,3 +3176,84 @@ func TestGetUpfrontShutdownScript(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expectOpenChannelMsg(t *testing.T, msgChan chan lnwire.Message) *lnwire.OpenChannel {
|
||||||
|
var msg lnwire.Message
|
||||||
|
select {
|
||||||
|
case msg = <-msgChan:
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
t.Fatalf("node did not send OpenChannel message")
|
||||||
|
}
|
||||||
|
|
||||||
|
openChannelReq, ok := msg.(*lnwire.OpenChannel)
|
||||||
|
if !ok {
|
||||||
|
errorMsg, gotError := msg.(*lnwire.Error)
|
||||||
|
if gotError {
|
||||||
|
t.Fatalf("expected OpenChannel to be sent "+
|
||||||
|
"from bob, instead got error: %v",
|
||||||
|
errorMsg.Error())
|
||||||
|
}
|
||||||
|
t.Fatalf("expected OpenChannel to be sent, instead got %T",
|
||||||
|
msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return openChannelReq
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWumboChannelConfig tests that the funding manager will respect the wumbo
|
||||||
|
// channel config param when creating or accepting new channels.
|
||||||
|
func TestWumboChannelConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// First we'll create a set of funding managers that will reject wumbo
|
||||||
|
// channels.
|
||||||
|
alice, bob := setupFundingManagers(t, func(cfg *fundingConfig) {
|
||||||
|
cfg.NoWumboChans = true
|
||||||
|
})
|
||||||
|
|
||||||
|
// If we attempt to initiate a new funding open request to Alice,
|
||||||
|
// that's below the wumbo channel mark, we should be able to start the
|
||||||
|
// funding process w/o issue.
|
||||||
|
updateChan := make(chan *lnrpc.OpenStatusUpdate)
|
||||||
|
errChan := make(chan error, 1)
|
||||||
|
initReq := &openChanReq{
|
||||||
|
targetPubkey: bob.privKey.PubKey(),
|
||||||
|
chainHash: *activeNetParams.GenesisHash,
|
||||||
|
localFundingAmt: MaxFundingAmount,
|
||||||
|
pushAmt: lnwire.NewMSatFromSatoshis(0),
|
||||||
|
private: false,
|
||||||
|
updates: updateChan,
|
||||||
|
err: errChan,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect Bob to respond with an Accept channel message.
|
||||||
|
alice.fundingMgr.initFundingWorkflow(bob, initReq)
|
||||||
|
openChanMsg := expectOpenChannelMsg(t, alice.msgChan)
|
||||||
|
bob.fundingMgr.processFundingOpen(openChanMsg, alice)
|
||||||
|
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
|
||||||
|
|
||||||
|
// We'll now attempt to create a channel above the wumbo mark, which
|
||||||
|
// should be rejected.
|
||||||
|
initReq.localFundingAmt = btcutil.SatoshiPerBitcoin
|
||||||
|
|
||||||
|
// After processing the funding open message, bob should respond with
|
||||||
|
// an error rejecting the channel.
|
||||||
|
alice.fundingMgr.initFundingWorkflow(bob, initReq)
|
||||||
|
openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
|
||||||
|
bob.fundingMgr.processFundingOpen(openChanMsg, alice)
|
||||||
|
assertErrorSent(t, bob.msgChan)
|
||||||
|
|
||||||
|
// Next, we'll re-create the funding managers, but this time allowing
|
||||||
|
// wumbo channels explicitly.
|
||||||
|
tearDownFundingManagers(t, alice, bob)
|
||||||
|
alice, bob = setupFundingManagers(t, func(cfg *fundingConfig) {
|
||||||
|
cfg.NoWumboChans = false
|
||||||
|
})
|
||||||
|
|
||||||
|
// We should now be able to initiate a wumbo channel funding w/o any
|
||||||
|
// issues.
|
||||||
|
alice.fundingMgr.initFundingWorkflow(bob, initReq)
|
||||||
|
openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
|
||||||
|
bob.fundingMgr.processFundingOpen(openChanMsg, alice)
|
||||||
|
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
|
||||||
|
}
|
||||||
|
26
lncfg/protocol.go
Normal file
26
lncfg/protocol.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package lncfg
|
||||||
|
|
||||||
|
// ProtocolOptions is a struct that we use to be able to test backwards
|
||||||
|
// compatibility of protocol additions, while defaulting to the latest within
|
||||||
|
// lnd, or to enable experimental protocol changes.
|
||||||
|
type ProtocolOptions struct {
|
||||||
|
// LegacyProtocol is a sub-config that houses all the legacy protocol
|
||||||
|
// options. These are mostly used for integration tests as most modern
|
||||||
|
// nodes shuld always run with them on by default.
|
||||||
|
LegacyProtocol `group:"legacy" namespace:"legacy"`
|
||||||
|
|
||||||
|
// ExperimentalProtocol is a sub-config that houses any experimental
|
||||||
|
// protocol features that also require a build-tag to activate.
|
||||||
|
ExperimentalProtocol
|
||||||
|
|
||||||
|
// WumboChans should be set if we want to enable support for wumbo
|
||||||
|
// (channels larger than 0.16 BTC) channels, which is the opposite of
|
||||||
|
// mini.
|
||||||
|
WumboChans bool `long:"wumbo-channels" description:"if set, then lnd will create and accept requests for channels larger chan 0.16 BTC"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wumbo returns true if lnd should permit the creation and acceptance of wumbo
|
||||||
|
// channels.
|
||||||
|
func (l *ProtocolOptions) Wumbo() bool {
|
||||||
|
return l.WumboChans
|
||||||
|
}
|
14
lncfg/protocol_experimental_off.go
Normal file
14
lncfg/protocol_experimental_off.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// +build !dev
|
||||||
|
|
||||||
|
package lncfg
|
||||||
|
|
||||||
|
// ExperimentalProtocol is a sub-config that houses any experimental protocol
|
||||||
|
// features that also require a build-tag to activate.
|
||||||
|
type ExperimentalProtocol struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnchorCommitments returns true if support for the anchor commitment type
|
||||||
|
// should be signaled.
|
||||||
|
func (l *ExperimentalProtocol) AnchorCommitments() bool {
|
||||||
|
return false
|
||||||
|
}
|
17
lncfg/protocol_experimental_on.go
Normal file
17
lncfg/protocol_experimental_on.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// +build dev
|
||||||
|
|
||||||
|
package lncfg
|
||||||
|
|
||||||
|
// ExperimentalProtocol is a sub-config that houses any experimental protocol
|
||||||
|
// features that also require a build-tag to activate.
|
||||||
|
type ExperimentalProtocol struct {
|
||||||
|
// Anchors should be set if we want to support opening or accepting
|
||||||
|
// channels having the anchor commitment type.
|
||||||
|
Anchors bool `long:"anchors" description:"EXPERIMENTAL: enable experimental support for anchor commitments, won't work with watchtowers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnchorCommitments returns true if support for the anchor commitment type
|
||||||
|
// should be signaled.
|
||||||
|
func (l *ExperimentalProtocol) AnchorCommitments() bool {
|
||||||
|
return l.Anchors
|
||||||
|
}
|
@ -2,27 +2,21 @@
|
|||||||
|
|
||||||
package lncfg
|
package lncfg
|
||||||
|
|
||||||
// ProtocolOptions is a struct that we use to be able to test backwards
|
// Legacy is a sub-config that houses all the legacy protocol options. These
|
||||||
// compatibility of protocol additions, while defaulting to the latest within
|
// are mostly used for integration tests as most modern nodes shuld always run
|
||||||
// lnd, or to enable experimental protocol changes.
|
// with them on by default.
|
||||||
type ProtocolOptions struct {
|
type LegacyProtocol struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LegacyOnion returns true if the old legacy onion format should be used when
|
// LegacyOnion returns true if the old legacy onion format should be used when
|
||||||
// we're an intermediate or final hop. This controls if we set the
|
// we're an intermediate or final hop. This controls if we set the
|
||||||
// TLVOnionPayloadOptional bit or not.
|
// TLVOnionPayloadOptional bit or not.
|
||||||
func (l *ProtocolOptions) LegacyOnion() bool {
|
func (l *LegacyProtocol) LegacyOnion() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoStaticRemoteKey returns true if the old commitment format with a tweaked
|
// NoStaticRemoteKey returns true if the old commitment format with a tweaked
|
||||||
// remote key should be used for new funded channels.
|
// remote key should be used for new funded channels.
|
||||||
func (l *ProtocolOptions) NoStaticRemoteKey() bool {
|
func (l *LegacyProtocol) NoStaticRemoteKey() bool {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnchorCommitments returns true if support for the the anchor commitment type
|
|
||||||
// should be signaled.
|
|
||||||
func (l *ProtocolOptions) AnchorCommitments() bool {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -2,41 +2,31 @@
|
|||||||
|
|
||||||
package lncfg
|
package lncfg
|
||||||
|
|
||||||
// ProtocolOptions is a struct that we use to be able to test backwards
|
// Legacy is a sub-config that houses all the legacy protocol options. These
|
||||||
// compatibility of protocol additions, while defaulting to the latest within
|
// are mostly used for integration tests as most modern nodes shuld always run
|
||||||
// lnd, or to enable experimental protocol changes.
|
// with them on by default.
|
||||||
type ProtocolOptions struct {
|
type LegacyProtocol struct {
|
||||||
// LegacyOnionFormat if set to true, then we won't signal
|
// LegacyOnionFormat if set to true, then we won't signal
|
||||||
// TLVOnionPayloadOptional. As a result, nodes that include us in the
|
// TLVOnionPayloadOptional. As a result, nodes that include us in the
|
||||||
// route won't use the new modern onion framing.
|
// route won't use the new modern onion framing.
|
||||||
LegacyOnionFormat bool `long:"legacyonion" description:"force node to not advertise the new modern TLV onion format"`
|
LegacyOnionFormat bool `long:"onion" description:"force node to not advertise the new modern TLV onion format"`
|
||||||
|
|
||||||
// CommitmentTweak guards if we should use the old legacy commitment
|
// CommitmentTweak guards if we should use the old legacy commitment
|
||||||
// protocol, or the newer variant that doesn't have a tweak for the
|
// protocol, or the newer variant that doesn't have a tweak for the
|
||||||
// remote party's output in the commitment. If set to true, then we
|
// remote party's output in the commitment. If set to true, then we
|
||||||
// won't signal StaticRemoteKeyOptional.
|
// won't signal StaticRemoteKeyOptional.
|
||||||
CommitmentTweak bool `long:"committweak" description:"force node to not advertise the new commitment format"`
|
CommitmentTweak bool `long:"committweak" description:"force node to not advertise the new commitment format"`
|
||||||
|
|
||||||
// Anchors should be set if we want to support opening or accepting
|
|
||||||
// channels having the anchor commitment type.
|
|
||||||
Anchors bool `long:"anchors" description:"EXPERIMENTAL: enable experimental support for anchor commitments, won't work with watchtowers"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LegacyOnion returns true if the old legacy onion format should be used when
|
// LegacyOnion returns true if the old legacy onion format should be used when
|
||||||
// we're an intermediate or final hop. This controls if we set the
|
// we're an intermediate or final hop. This controls if we set the
|
||||||
// TLVOnionPayloadOptional bit or not.
|
// TLVOnionPayloadOptional bit or not.
|
||||||
func (l *ProtocolOptions) LegacyOnion() bool {
|
func (l *LegacyProtocol) LegacyOnion() bool {
|
||||||
return l.LegacyOnionFormat
|
return l.LegacyOnionFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoStaticRemoteKey returns true if the old commitment format with a tweaked
|
// NoStaticRemoteKey returns true if the old commitment format with a tweaked
|
||||||
// remote key should be used for new funded channels.
|
// remote key should be used for new funded channels.
|
||||||
func (l *ProtocolOptions) NoStaticRemoteKey() bool {
|
func (l *LegacyProtocol) NoStaticRemoteKey() bool {
|
||||||
return l.CommitmentTweak
|
return l.CommitmentTweak
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnchorCommitments returns true if support for the anchor commitment type
|
|
||||||
// should be signaled.
|
|
||||||
func (l *ProtocolOptions) AnchorCommitments() bool {
|
|
||||||
return l.Anchors
|
|
||||||
}
|
|
||||||
|
@ -48,7 +48,7 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
//
|
//
|
||||||
// First, we'll create Dave and establish a channel to Alice. Dave will
|
// First, we'll create Dave and establish a channel to Alice. Dave will
|
||||||
// be running an older node that requires the legacy onion payload.
|
// be running an older node that requires the legacy onion payload.
|
||||||
daveArgs := []string{"--protocol.legacyonion"}
|
daveArgs := []string{"--protocol.legacy.onion"}
|
||||||
dave, err := net.NewNode("Dave", daveArgs)
|
dave, err := net.NewNode("Dave", daveArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create new nodes: %v", err)
|
t.Fatalf("unable to create new nodes: %v", err)
|
||||||
|
@ -1178,7 +1178,7 @@ func (c commitType) String() string {
|
|||||||
func (c commitType) Args() []string {
|
func (c commitType) Args() []string {
|
||||||
switch c {
|
switch c {
|
||||||
case commitTypeLegacy:
|
case commitTypeLegacy:
|
||||||
return []string{"--protocol.committweak"}
|
return []string{"--protocol.legacy.committweak"}
|
||||||
case commitTypeTweakless:
|
case commitTypeTweakless:
|
||||||
return []string{}
|
return []string{}
|
||||||
case commitTypeAnchors:
|
case commitTypeAnchors:
|
||||||
@ -1457,9 +1457,14 @@ test:
|
|||||||
// Check that the signalled type matches what we
|
// Check that the signalled type matches what we
|
||||||
// expect.
|
// expect.
|
||||||
switch {
|
switch {
|
||||||
case expType == commitTypeAnchors && chansCommitType == lnrpc.CommitmentType_ANCHORS:
|
case expType == commitTypeAnchors &&
|
||||||
case expType == commitTypeTweakless && chansCommitType == lnrpc.CommitmentType_STATIC_REMOTE_KEY:
|
chansCommitType == lnrpc.CommitmentType_ANCHORS:
|
||||||
case expType == commitTypeLegacy && chansCommitType == lnrpc.CommitmentType_LEGACY:
|
|
||||||
|
case expType == commitTypeTweakless &&
|
||||||
|
chansCommitType == lnrpc.CommitmentType_STATIC_REMOTE_KEY:
|
||||||
|
|
||||||
|
case expType == commitTypeLegacy &&
|
||||||
|
chansCommitType == lnrpc.CommitmentType_LEGACY:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
t.Fatalf("expected nodes to signal "+
|
t.Fatalf("expected nodes to signal "+
|
||||||
@ -15195,6 +15200,10 @@ var testsCases = []*testCase{
|
|||||||
name: "intercept forwarded htlc packets",
|
name: "intercept forwarded htlc packets",
|
||||||
test: testForwardInterceptor,
|
test: testForwardInterceptor,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "wumbo channels",
|
||||||
|
test: testWumboChannels,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLightningNetworkDaemon performs a series of integration tests amongst a
|
// TestLightningNetworkDaemon performs a series of integration tests amongst a
|
||||||
|
92
lntest/itest/lnd_wumbo_channels_test.go
Normal file
92
lntest/itest/lnd_wumbo_channels_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// +build rpctest
|
||||||
|
|
||||||
|
package itest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/lightningnetwork/lnd"
|
||||||
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// testWumboChannels tests that only a node that signals wumbo channel
|
||||||
|
// acceptances will allow a wumbo channel to be created. Additionally, if a
|
||||||
|
// node is running with mini channels only enabled, then they should reject any
|
||||||
|
// inbound wumbo channel requests.
|
||||||
|
func testWumboChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
// With all the channel types exercised, we'll now make sure the wumbo
|
||||||
|
// signalling support works properly.
|
||||||
|
//
|
||||||
|
// We'll make two new nodes, with one of them signalling support for
|
||||||
|
// wumbo channels while the other doesn't.
|
||||||
|
wumboNode, err := net.NewNode(
|
||||||
|
"wumbo", []string{"--protocol.wumbo-channels"},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, t, wumboNode)
|
||||||
|
miniNode, err := net.NewNode("mini", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, t, miniNode)
|
||||||
|
|
||||||
|
// We'll send coins to the wumbo node, as it'll be the one imitating
|
||||||
|
// the channel funding.
|
||||||
|
ctxb := context.Background()
|
||||||
|
err = net.SendCoins(ctxb, btcutil.SatoshiPerBitcoin, wumboNode)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send coins to carol: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next we'll connect both nodes, then attempt to make a wumbo channel
|
||||||
|
// funding request to the mini node we created above. The wumbo request
|
||||||
|
// should fail as the node isn't advertising wumbo channels.
|
||||||
|
err = net.EnsureConnected(ctxb, wumboNode, miniNode)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to connect peers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chanAmt := lnd.MaxBtcFundingAmount + 1
|
||||||
|
_, err = net.OpenChannel(
|
||||||
|
ctxb, wumboNode, miniNode, lntest.OpenChannelParams{
|
||||||
|
Amt: chanAmt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected wumbo channel funding to fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test should indicate a failure due to the channel being too
|
||||||
|
// large.
|
||||||
|
if !strings.Contains(err.Error(), "channel too large") {
|
||||||
|
t.Fatalf("channel should be rejected due to size, instead "+
|
||||||
|
"error was: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll now make another wumbo node to accept our wumbo channel
|
||||||
|
// funding.
|
||||||
|
wumboNode2, err := net.NewNode(
|
||||||
|
"wumbo2", []string{"--protocol.wumbo-channels"},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create new node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, t, wumboNode2)
|
||||||
|
|
||||||
|
// Creating a wumbo channel between these two nodes should succeed.
|
||||||
|
err = net.EnsureConnected(ctxb, wumboNode, wumboNode2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to connect peers: %v", err)
|
||||||
|
}
|
||||||
|
chanPoint := openChannelAndAssert(
|
||||||
|
ctxb, t, net, wumboNode, wumboNode2,
|
||||||
|
lntest.OpenChannelParams{
|
||||||
|
Amt: chanAmt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
closeChannelAndAssert(ctxb, t, net, wumboNode, chanPoint, false)
|
||||||
|
}
|
@ -192,3 +192,6 @@
|
|||||||
<time> [ERR] PEER: unable to close channel, ChannelID(<hex>) is unknown
|
<time> [ERR] PEER: unable to close channel, ChannelID(<hex>) is unknown
|
||||||
<time> [ERR] HSWC: ChannelLink(<chan>): unable to update signals
|
<time> [ERR] HSWC: ChannelLink(<chan>): unable to update signals
|
||||||
<time> [ERR] RPCS: [/routerrpc.Router/HtlcInterceptor]: rpc error: code = Canceled desc = context canceled
|
<time> [ERR] RPCS: [/routerrpc.Router/HtlcInterceptor]: rpc error: code = Canceled desc = context canceled
|
||||||
|
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=channel too large
|
||||||
|
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=channel too large
|
||||||
|
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=channel too large
|
||||||
|
@ -101,6 +101,14 @@ const (
|
|||||||
// HTLC.
|
// HTLC.
|
||||||
MPPOptional FeatureBit = 17
|
MPPOptional FeatureBit = 17
|
||||||
|
|
||||||
|
// WumboChannelsRequired is a required feature bit that signals that a
|
||||||
|
// node is willing to accept channels larger than 2^24 satoshis.
|
||||||
|
WumboChannelsRequired = 18
|
||||||
|
|
||||||
|
// WumboChannelsRequired is an optional feature bit that signals that a
|
||||||
|
// node is willing to accept channels larger than 2^24 satoshis.
|
||||||
|
WumboChannelsOptional = 19
|
||||||
|
|
||||||
// AnchorsRequired is a required feature bit that signals that the node
|
// AnchorsRequired is a required feature bit that signals that the node
|
||||||
// requires channels to be made using commitments having anchor
|
// requires channels to be made using commitments having anchor
|
||||||
// outputs.
|
// outputs.
|
||||||
@ -150,6 +158,8 @@ var Features = map[FeatureBit]string{
|
|||||||
MPPRequired: "multi-path-payments",
|
MPPRequired: "multi-path-payments",
|
||||||
AnchorsRequired: "anchor-commitments",
|
AnchorsRequired: "anchor-commitments",
|
||||||
AnchorsOptional: "anchor-commitments",
|
AnchorsOptional: "anchor-commitments",
|
||||||
|
WumboChannelsRequired: "wumbo-channels",
|
||||||
|
WumboChannelsOptional: "wumbo-channels",
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A
|
// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A
|
||||||
|
@ -1713,6 +1713,8 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
|||||||
remoteCsvDelay := uint16(in.RemoteCsvDelay)
|
remoteCsvDelay := uint16(in.RemoteCsvDelay)
|
||||||
maxValue := lnwire.MilliSatoshi(in.RemoteMaxValueInFlightMsat)
|
maxValue := lnwire.MilliSatoshi(in.RemoteMaxValueInFlightMsat)
|
||||||
|
|
||||||
|
globalFeatureSet := r.server.featureMgr.Get(feature.SetNodeAnn)
|
||||||
|
|
||||||
// Ensure that the initial balance of the remote party (if pushing
|
// Ensure that the initial balance of the remote party (if pushing
|
||||||
// satoshis) does not exceed the amount the local party has requested
|
// satoshis) does not exceed the amount the local party has requested
|
||||||
// for funding.
|
// for funding.
|
||||||
@ -1726,7 +1728,10 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
|||||||
// Ensure that the user doesn't exceed the current soft-limit for
|
// Ensure that the user doesn't exceed the current soft-limit for
|
||||||
// channel size. If the funding amount is above the soft-limit, then
|
// channel size. If the funding amount is above the soft-limit, then
|
||||||
// we'll reject the request.
|
// we'll reject the request.
|
||||||
if localFundingAmt > MaxFundingAmount {
|
wumboEnabled := globalFeatureSet.HasFeature(
|
||||||
|
lnwire.WumboChannelsOptional,
|
||||||
|
)
|
||||||
|
if !wumboEnabled && localFundingAmt > MaxFundingAmount {
|
||||||
return nil, fmt.Errorf("funding amount is too large, the max "+
|
return nil, fmt.Errorf("funding amount is too large, the max "+
|
||||||
"channel size is: %v", MaxFundingAmount)
|
"channel size is: %v", MaxFundingAmount)
|
||||||
}
|
}
|
||||||
|
40
server.go
40
server.go
@ -356,27 +356,6 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globalFeatures := lnwire.NewRawFeatureVector()
|
|
||||||
|
|
||||||
// Only if we're not being forced to use the legacy onion format, will
|
|
||||||
// we signal our knowledge of the new TLV onion format.
|
|
||||||
if !cfg.ProtocolOptions.LegacyOnion() {
|
|
||||||
globalFeatures.Set(lnwire.TLVOnionPayloadOptional)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similarly, we default to supporting the new modern commitment format
|
|
||||||
// where the remote key is static unless the protocol config is set to
|
|
||||||
// keep using the older format.
|
|
||||||
if !cfg.ProtocolOptions.NoStaticRemoteKey() {
|
|
||||||
globalFeatures.Set(lnwire.StaticRemoteKeyOptional)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only signal that we support the experimental anchor commitments
|
|
||||||
// if explicitly enabled in the config.
|
|
||||||
if cfg.ProtocolOptions.AnchorCommitments() {
|
|
||||||
globalFeatures.Set(lnwire.AnchorsOptional)
|
|
||||||
}
|
|
||||||
|
|
||||||
var serializedPubKey [33]byte
|
var serializedPubKey [33]byte
|
||||||
copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
@ -410,6 +389,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(),
|
NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(),
|
||||||
NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(),
|
NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(),
|
||||||
NoAnchors: !cfg.ProtocolOptions.AnchorCommitments(),
|
NoAnchors: !cfg.ProtocolOptions.AnchorCommitments(),
|
||||||
|
NoWumbo: !cfg.ProtocolOptions.Wumbo(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -987,6 +967,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.fundingMgr, err = newFundingManager(fundingConfig{
|
s.fundingMgr, err = newFundingManager(fundingConfig{
|
||||||
|
NoWumboChans: !cfg.ProtocolOptions.Wumbo(),
|
||||||
IDKey: nodeKeyECDH.PubKey(),
|
IDKey: nodeKeyECDH.PubKey(),
|
||||||
Wallet: cc.wallet,
|
Wallet: cc.wallet,
|
||||||
PublishTransaction: cc.wallet.PublishTransaction,
|
PublishTransaction: cc.wallet.PublishTransaction,
|
||||||
@ -1053,11 +1034,18 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
return defaultConf
|
return defaultConf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minConf := uint64(3)
|
||||||
|
maxConf := uint64(6)
|
||||||
|
|
||||||
|
// If this is a wumbo channel, then we'll require the
|
||||||
|
// max amount of confirmations.
|
||||||
|
if chanAmt > MaxFundingAmount {
|
||||||
|
return uint16(maxConf)
|
||||||
|
}
|
||||||
|
|
||||||
// If not we return a value scaled linearly
|
// If not we return a value scaled linearly
|
||||||
// between 3 and 6, depending on channel size.
|
// between 3 and 6, depending on channel size.
|
||||||
// TODO(halseth): Use 1 as minimum?
|
// TODO(halseth): Use 1 as minimum?
|
||||||
minConf := uint64(3)
|
|
||||||
maxConf := uint64(6)
|
|
||||||
maxChannelSize := uint64(
|
maxChannelSize := uint64(
|
||||||
lnwire.NewMSatFromSatoshis(MaxFundingAmount))
|
lnwire.NewMSatFromSatoshis(MaxFundingAmount))
|
||||||
stake := lnwire.NewMSatFromSatoshis(chanAmt) + pushAmt
|
stake := lnwire.NewMSatFromSatoshis(chanAmt) + pushAmt
|
||||||
@ -1086,6 +1074,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
return defaultDelay
|
return defaultDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a wumbo channel, then we'll require the
|
||||||
|
// max value.
|
||||||
|
if chanAmt > MaxFundingAmount {
|
||||||
|
return maxRemoteDelay
|
||||||
|
}
|
||||||
|
|
||||||
// If not we scale according to channel size.
|
// If not we scale according to channel size.
|
||||||
delay := uint16(btcutil.Amount(maxRemoteDelay) *
|
delay := uint16(btcutil.Amount(maxRemoteDelay) *
|
||||||
chanAmt / MaxFundingAmount)
|
chanAmt / MaxFundingAmount)
|
||||||
|
Loading…
Reference in New Issue
Block a user