server+funding: allow scid-alias, zero-conf chantypes, scid-alias

feature-bit channels

This allows opening zero-conf chan-type, scid-alias chan-type, and
scid-alias feature-bit channels. scid-alias chan-type channels are
required to be private. Two paths are available for opening a zero-conf
channel:

* explicit chan-type negotiation
* LDK carve-out where chan-types are not used, LND is on the
  receiving end, and a ChannelAcceptor is used to enable zero-conf

When a zero-conf channel is negotiated, the funding manager:
* sends a FundingLocked with an alias
* waits for a FundingLocked from the remote peer
* calls addToRouterGraph to persist the channel using our alias in
  the graph. The peer's alias is used to send them a ChannelUpdate.
* wait for six confirmations. If public, the alias edge in the
  graph is deleted and replaced (not atomically) with the confirmed
  edge. Our policy is also read-and-replaced, but the counterparty's
  policy won't exist until they send it to us.

When a scid-alias-feature channel is negotiated, the funding manager:
* sends a FundingLocked with an alias:
* calls addToRouterGraph, sends ChannelUpdate with the confirmed SCID
  since it exists.
* when six confirmations occurs, the edge is deleted and re-inserted
  since the peer may have sent us an alias ChannelUpdate that we are
  storing in the graph.

Since it is possible for a user to toggle the scid-alias-feature-bit
to on while channels exist in the funding manager, care has been taken
to ensure that an alias is ALWAYS sent in the funding_locked message
if this happens.
This commit is contained in:
eugene
2022-04-04 16:47:05 -04:00
parent 13c15e8038
commit 1aa9626606
19 changed files with 3883 additions and 2697 deletions

View File

@@ -24,10 +24,12 @@ var (
// negotiateCommitmentType negotiates the commitment type of a newly opened
// channel. If a channelType is provided, explicit negotiation for said type
// will be attempted if the set of both local and remote features support it.
// Otherwise, implicit negotiation will be attempted.
func negotiateCommitmentType(channelType *lnwire.ChannelType,
local, remote *lnwire.FeatureVector, mustBeExplicit bool,
) (bool, *lnwire.ChannelType, lnwallet.CommitmentType, error) {
// Otherwise, implicit negotiation will be attempted. Two booleans are
// returned letting the caller know if the option-scid-alias or zero-conf
// channel types were negotiated.
func negotiateCommitmentType(channelType *lnwire.ChannelType, local,
remote *lnwire.FeatureVector, mustBeExplicit bool) (bool,
*lnwire.ChannelType, lnwallet.CommitmentType, error) {
if channelType != nil {
// If the peer does know explicit negotiation, let's attempt
@@ -57,12 +59,127 @@ func negotiateCommitmentType(channelType *lnwire.ChannelType,
// specific channel type. Since the channel type is comprised of a set of even
// feature bits, we also make sure each feature is supported by both peers. An
// error is returned if either peer does not support said channel type.
func explicitNegotiateCommitmentType(channelType lnwire.ChannelType,
local, remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) {
func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local,
remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) {
channelFeatures := lnwire.RawFeatureVector(channelType)
switch {
// Lease script enforcement + anchors zero fee + static remote key +
// zero conf + scid alias features only.
case channelFeatures.OnlyContains(
lnwire.ZeroConfRequired,
lnwire.ScidAliasRequired,
lnwire.ScriptEnforcedLeaseRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ZeroConfOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeScriptEnforcedLease, nil
// Anchors zero fee + static remote key + zero conf + scid alias
// features only.
case channelFeatures.OnlyContains(
lnwire.ZeroConfRequired,
lnwire.ScidAliasRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ZeroConfOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
// Lease script enforcement + anchors zero fee + static remote key +
// zero conf features only.
case channelFeatures.OnlyContains(
lnwire.ZeroConfRequired,
lnwire.ScriptEnforcedLeaseRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ZeroConfOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeScriptEnforcedLease, nil
// Anchors zero fee + static remote key + zero conf features only.
case channelFeatures.OnlyContains(
lnwire.ZeroConfRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ZeroConfOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
// Lease script enforcement + anchors zero fee + static remote key +
// option-scid-alias features only.
case channelFeatures.OnlyContains(
lnwire.ScidAliasRequired,
lnwire.ScriptEnforcedLeaseRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ScidAliasOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeScriptEnforcedLease, nil
// Anchors zero fee + static remote key + option-scid-alias features
// only.
case channelFeatures.OnlyContains(
lnwire.ScidAliasRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
):
if !hasFeatures(
local, remote,
lnwire.ScidAliasOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.StaticRemoteKeyOptional,
) {
return 0, errUnsupportedChannelType
}
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
// Lease script enforcement + anchors zero fee + static remote key
// features only.
case channelFeatures.OnlyContains(

View File

@@ -21,6 +21,8 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
remoteFeatures *lnwire.RawFeatureVector
expectsCommitType lnwallet.CommitmentType
expectsChanType lnwire.ChannelType
zeroConf bool
scidAlias bool
expectsErr error
}{
{
@@ -81,6 +83,134 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
),
expectsErr: errUnsupportedChannelType,
},
{
name: "explicit zero-conf script enforced",
channelFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.ScriptEnforcedLeaseRequired,
),
localFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.ExplicitChannelTypeOptional,
),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.ExplicitChannelTypeOptional,
),
expectsCommitType: lnwallet.CommitmentTypeScriptEnforcedLease,
expectsChanType: lnwire.ChannelType(
*lnwire.NewRawFeatureVector(
lnwire.ZeroConfRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.ScriptEnforcedLeaseRequired,
),
),
zeroConf: true,
expectsErr: nil,
},
{
name: "explicit zero-conf anchors",
channelFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
),
localFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional,
),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.ZeroConfOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional,
),
expectsCommitType: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsChanType: lnwire.ChannelType(
*lnwire.NewRawFeatureVector(
lnwire.ZeroConfRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
),
),
zeroConf: true,
expectsErr: nil,
},
{
name: "explicit scid-alias script enforced",
channelFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.ScriptEnforcedLeaseRequired,
),
localFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.ExplicitChannelTypeOptional,
),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ScriptEnforcedLeaseOptional,
lnwire.ExplicitChannelTypeOptional,
),
expectsCommitType: lnwallet.CommitmentTypeScriptEnforcedLease,
expectsChanType: lnwire.ChannelType(
*lnwire.NewRawFeatureVector(
lnwire.ScidAliasRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.ScriptEnforcedLeaseRequired,
),
),
scidAlias: true,
expectsErr: nil,
},
{
name: "explicit scid-alias anchors",
channelFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
),
localFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional,
),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.ScidAliasOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional,
),
expectsCommitType: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsChanType: lnwire.ChannelType(
*lnwire.NewRawFeatureVector(
lnwire.ScidAliasRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
),
),
scidAlias: true,
expectsErr: nil,
},
{
name: "explicit anchors",
channelFeatures: lnwire.NewRawFeatureVector(
@@ -212,16 +342,50 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
*testCase.channelFeatures,
)
}
_, localChanType, localCommitType, err := negotiateCommitmentType(
_, lChan, lCommit, err := negotiateCommitmentType(
channelType, localFeatures, remoteFeatures,
testCase.mustBeExplicit,
)
var (
localZc bool
localScid bool
remoteZc bool
remoteScid bool
)
if lChan != nil {
localFv := lnwire.RawFeatureVector(*lChan)
localZc = localFv.IsSet(
lnwire.ZeroConfRequired,
)
localScid = localFv.IsSet(
lnwire.ScidAliasRequired,
)
}
require.Equal(t, testCase.zeroConf, localZc)
require.Equal(t, testCase.scidAlias, localScid)
require.Equal(t, testCase.expectsErr, err)
_, remoteChanType, remoteCommitType, err := negotiateCommitmentType(
_, rChan, rCommit, err := negotiateCommitmentType(
channelType, remoteFeatures, localFeatures,
testCase.mustBeExplicit,
)
if rChan != nil {
remoteFv := lnwire.RawFeatureVector(*rChan)
remoteZc = remoteFv.IsSet(
lnwire.ZeroConfRequired,
)
remoteScid = remoteFv.IsSet(
lnwire.ScidAliasRequired,
)
}
require.Equal(t, testCase.zeroConf, remoteZc)
require.Equal(t, testCase.scidAlias, remoteScid)
require.Equal(t, testCase.expectsErr, err)
if testCase.expectsErr != nil {
@@ -229,20 +393,20 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
}
require.Equal(
t, testCase.expectsCommitType, localCommitType,
t, testCase.expectsCommitType, lCommit,
testCase.name,
)
require.Equal(
t, testCase.expectsCommitType, remoteCommitType,
t, testCase.expectsCommitType, rCommit,
testCase.name,
)
require.Equal(
t, testCase.expectsChanType, *localChanType,
t, testCase.expectsChanType, *lChan,
testCase.name,
)
require.Equal(
t, testCase.expectsChanType, *remoteChanType,
t, testCase.expectsChanType, *rChan,
testCase.name,
)
})

View File

@@ -19,3 +19,31 @@ type Controller interface {
// represents a pending channel in the Controller implementation.
IsPendingChannel([32]byte, lnpeer.Peer) bool
}
// aliasHandler is an interface that abstracts the managing of aliases.
type aliasHandler interface {
// RequestAlias lets the funding manager request a unique SCID alias to
// use in the funding_locked message.
RequestAlias() (lnwire.ShortChannelID, error)
// PutPeerAlias lets the funding manager store the received alias SCID
// in the funding_locked message.
PutPeerAlias(lnwire.ChannelID, lnwire.ShortChannelID) error
// GetPeerAlias lets the funding manager lookup the received alias SCID
// from the funding_locked message. This is not the same as GetAliases
// which retrieves OUR aliases for a given channel.
GetPeerAlias(lnwire.ChannelID) (lnwire.ShortChannelID, error)
// AddLocalAlias persists an alias to an underlying alias store.
AddLocalAlias(lnwire.ShortChannelID, lnwire.ShortChannelID, bool) error
// GetAliases returns the set of aliases given the main SCID of a
// channel. This SCID will be an alias for zero-conf channels and will
// be the confirmed SCID otherwise.
GetAliases(lnwire.ShortChannelID) []lnwire.ShortChannelID
// DeleteSixConfs removes the passed SCID from one of the underlying
// alias store's indices.
DeleteSixConfs(lnwire.ShortChannelID) error
}

File diff suppressed because it is too large Load Diff

View File

@@ -115,8 +115,48 @@ var (
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
fundingNetParams = chainreg.BitcoinTestNetParams
alias = lnwire.ShortChannelID{
BlockHeight: 16_000_000,
TxIndex: 0,
TxPosition: 0,
}
)
type mockAliasMgr struct{}
func (m *mockAliasMgr) RequestAlias() (lnwire.ShortChannelID, error) {
return alias, nil
}
func (m *mockAliasMgr) PutPeerAlias(lnwire.ChannelID,
lnwire.ShortChannelID) error {
return nil
}
func (m *mockAliasMgr) GetPeerAlias(lnwire.ChannelID) (lnwire.ShortChannelID,
error) {
return alias, nil
}
func (m *mockAliasMgr) AddLocalAlias(lnwire.ShortChannelID,
lnwire.ShortChannelID, bool) error {
return nil
}
func (m *mockAliasMgr) GetAliases(
lnwire.ShortChannelID) []lnwire.ShortChannelID {
return []lnwire.ShortChannelID{alias}
}
func (m *mockAliasMgr) DeleteSixConfs(lnwire.ShortChannelID) error {
return nil
}
type mockNotifier struct {
oneConfChannel chan *chainntnfs.TxConfirmation
sixConfChannel chan *chainntnfs.TxConfirmation
@@ -199,6 +239,8 @@ type testNode struct {
mockChanEvent *mockChanEvent
testDir string
shutdownChannel chan struct{}
reportScidChan chan struct{}
localFeatures []lnwire.FeatureBit
remoteFeatures []lnwire.FeatureBit
remotePeer *testNode
@@ -234,7 +276,9 @@ func (n *testNode) QuitSignal() <-chan struct{} {
}
func (n *testNode) LocalFeatures() *lnwire.FeatureVector {
return lnwire.NewFeatureVector(nil, nil)
return lnwire.NewFeatureVector(
lnwire.NewRawFeatureVector(n.localFeatures...), nil,
)
}
func (n *testNode) RemoteFeatures() *lnwire.FeatureVector {
@@ -307,10 +351,13 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
epochChan: make(chan *chainntnfs.BlockEpoch, 2),
}
aliasMgr := &mockAliasMgr{}
sentMessages := make(chan lnwire.Message)
sentAnnouncements := make(chan lnwire.Message)
publTxChan := make(chan *wire.MsgTx, 1)
shutdownChan := make(chan struct{})
reportScidChan := make(chan struct{})
wc := &mock.WalletController{
RootKey: alicePrivKey,
@@ -382,14 +429,16 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
return lnwire.NodeAnnouncement{}, nil
},
TempChanIDSeed: chanIDSeed,
FindChannel: func(chanID lnwire.ChannelID) (
*channeldb.OpenChannel, error) {
dbChannels, err := cdb.FetchAllChannels()
FindChannel: func(node *btcec.PublicKey,
chanID lnwire.ChannelID) (*channeldb.OpenChannel,
error) {
nodeChans, err := cdb.FetchOpenChannels(node)
if err != nil {
return nil, err
}
for _, channel := range dbChannels {
for _, channel := range nodeChans {
if chanID.IsChanPoint(&channel.FundingOutpoint) {
return channel, nil
}
@@ -432,6 +481,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
return nil
},
ReportShortChanID: func(wire.OutPoint) error {
reportScidChan <- struct{}{}
return nil
},
PublishTransaction: func(txn *wire.MsgTx, _ string) error {
@@ -450,6 +500,12 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
OpenChannelPredicate: chainedAcceptor,
NotifyPendingOpenChannelEvent: evt.NotifyPendingOpenChannelEvent,
RegisteredChains: chainreg.NewChainRegistry(),
DeleteAliasEdge: func(scid lnwire.ShortChannelID) (
*channeldb.ChannelEdgePolicy, error) {
return nil, nil
},
AliasManager: aliasMgr,
}
for _, op := range options {
@@ -473,6 +529,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
mockChanEvent: evt,
testDir: tempTestDir,
shutdownChannel: shutdownChan,
reportScidChan: reportScidChan,
addr: addr,
}
@@ -542,6 +599,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
},
DefaultMinHtlcIn: 5,
RequiredRemoteMaxValue: oldCfg.RequiredRemoteMaxValue,
ReportShortChanID: oldCfg.ReportShortChanID,
PublishTransaction: func(txn *wire.MsgTx, _ string) error {
publishChan <- txn
return nil
@@ -552,6 +610,8 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
ZombieSweeperInterval: oldCfg.ZombieSweeperInterval,
ReservationTimeout: oldCfg.ReservationTimeout,
OpenChannelPredicate: chainedAcceptor,
DeleteAliasEdge: oldCfg.DeleteAliasEdge,
AliasManager: oldCfg.AliasManager,
})
require.NoError(t, err, "failed recreating aliceFundingManager")
@@ -639,7 +699,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
publ := fundChannel(
t, alice, bob, localFundingAmt, pushAmt, false, numConfs,
updateChan, announceChan,
updateChan, announceChan, nil,
)
fundingOutPoint := &wire.OutPoint{
Hash: publ.TxHash(),
@@ -652,7 +712,8 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
// transaction is confirmed on-chain. Returns the funding tx.
func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
pushAmt btcutil.Amount, subtractFees bool, numConfs uint32,
updateChan chan *lnrpc.OpenStatusUpdate, announceChan bool) *wire.MsgTx {
updateChan chan *lnrpc.OpenStatusUpdate, announceChan bool,
chanType *lnwire.ChannelType) *wire.MsgTx {
// Create a funding request and start the workflow.
errChan := make(chan error, 1)
@@ -665,6 +726,7 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
PushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
FundingFeePerKw: 1000,
Private: !announceChan,
ChannelType: chanType,
Updates: updateChan,
Err: errChan,
}
@@ -3231,7 +3293,7 @@ func TestFundingManagerFundAll(t *testing.T) {
pushAmt := btcutil.Amount(0)
fundingTx := fundChannel(
t, alice, bob, test.spendAmt, pushAmt, true, 1,
updateChan, true,
updateChan, true, nil,
)
// Check whether the expected change output is present.
@@ -3662,3 +3724,128 @@ func testUpfrontFailure(t *testing.T, pkscript []byte, expectErr bool) {
require.True(t, ok, "did not receive AcceptChannel")
}
}
// TestFundingManagerZeroConf tests that the fundingmanager properly handles
// the whole flow for zero-conf channels.
func TestFundingManagerZeroConf(t *testing.T) {
t.Parallel()
alice, bob := setupFundingManagers(t)
defer tearDownFundingManagers(t, alice, bob)
// Alice and Bob will have the same set of feature bits in our test.
featureBits := []lnwire.FeatureBit{
lnwire.ZeroConfOptional,
lnwire.ScidAliasOptional,
lnwire.ExplicitChannelTypeOptional,
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
}
alice.localFeatures = featureBits
alice.remoteFeatures = featureBits
bob.localFeatures = featureBits
bob.remoteFeatures = featureBits
fundingAmt := btcutil.Amount(500000)
pushAmt := btcutil.Amount(0)
updateChan := make(chan *lnrpc.OpenStatusUpdate)
// Construct the zero-conf ChannelType for use in open_channel.
channelTypeBits := []lnwire.FeatureBit{
lnwire.ZeroConfRequired,
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
}
channelType := lnwire.ChannelType(
*lnwire.NewRawFeatureVector(channelTypeBits...),
)
// Call fundChannel with the zero-conf ChannelType.
fundingTx := fundChannel(
t, alice, bob, fundingAmt, pushAmt, false, 1, updateChan, true,
&channelType,
)
fundingOp := &wire.OutPoint{
Hash: fundingTx.TxHash(),
Index: 0,
}
// Assert that Bob's funding_locked message has an AliasScid.
bobFundingLocked := assertFundingMsgSent(
t, bob.msgChan, "FundingLocked",
).(*lnwire.FundingLocked)
require.NotNil(t, bobFundingLocked.AliasScid)
require.Equal(t, *bobFundingLocked.AliasScid, alias)
// Do the same for Alice as well.
aliceFundingLocked := assertFundingMsgSent(
t, alice.msgChan, "FundingLocked",
).(*lnwire.FundingLocked)
require.NotNil(t, aliceFundingLocked.AliasScid)
require.Equal(t, *aliceFundingLocked.AliasScid, alias)
// Exchange the funding_locked messages.
alice.fundingMgr.ProcessFundingMsg(bobFundingLocked, bob)
bob.fundingMgr.ProcessFundingMsg(aliceFundingLocked, alice)
// We'll assert that they both create new links.
assertHandleFundingLocked(t, alice, bob)
// We'll now assert that both sides send ChannelAnnouncement and
// ChannelUpdate messages.
assertChannelAnnouncements(t, alice, bob, fundingAmt, nil, nil)
// We'll now wait for the OpenStatusUpdate_ChanOpen update.
waitForOpenUpdate(t, updateChan)
// Assert that both Alice & Bob are in the addedToRouterGraph state.
assertAddedToRouterGraph(t, alice, bob, fundingOp)
// We'll now restart Alice's funding manager and assert that the tx
// is rebroadcast.
recreateAliceFundingManager(t, alice)
select {
case <-alice.publTxChan:
case <-time.After(time.Second * 5):
t.Fatalf("timed out waiting for alice to rebroadcast tx")
}
// We'll now confirm the funding transaction.
alice.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{
Tx: fundingTx,
}
bob.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{
Tx: fundingTx,
}
assertChannelAnnouncements(t, alice, bob, fundingAmt, nil, nil)
// Both Alice and Bob should send on reportScidChan.
select {
case <-alice.reportScidChan:
case <-time.After(time.Second * 5):
t.Fatalf("did not call ReportShortChanID in time")
}
select {
case <-bob.reportScidChan:
case <-time.After(time.Second * 5):
t.Fatalf("did not call ReportShortChanID in time")
}
// Send along the 6-confirmation channel so that announcement sigs can
// be exchanged.
alice.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{
Tx: fundingTx,
}
bob.mockNotifier.sixConfChannel <- &chainntnfs.TxConfirmation{
Tx: fundingTx,
}
assertAnnouncementSignatures(t, alice, bob)
// Assert that the channel state is deleted from the fundingmanager's
// datastore.
assertNoChannelState(t, alice, bob, fundingOp)
}