Skip to content

Commit 1aa9626

Browse files
committed
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.
1 parent 13c15e8 commit 1aa9626

19 files changed

+3874
-2688
lines changed

chanacceptor/acceptor_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,15 @@ func TestMultipleAcceptClients(t *testing.T) {
184184
queries = map[*lnwire.OpenChannel]*ChannelAcceptResponse{
185185
chan1: NewChannelAcceptResponse(
186186
true, nil, testUpfront, 1, 2, 3, 4, 5, 6,
187+
false,
187188
),
188189
chan2: NewChannelAcceptResponse(
189190
false, errChannelRejected, nil, 0, 0, 0,
190-
0, 0, 0,
191+
0, 0, 0, false,
191192
),
192193
chan3: NewChannelAcceptResponse(
193194
false, customError, nil, 0, 0, 0, 0, 0, 0,
195+
false,
194196
),
195197
}
196198

@@ -245,7 +247,7 @@ func TestInvalidResponse(t *testing.T) {
245247
PendingChannelID: chan1,
246248
}: NewChannelAcceptResponse(
247249
false, errChannelRejected, nil, 0, 0,
248-
0, 0, 0, 0,
250+
0, 0, 0, 0, false,
249251
),
250252
}
251253

@@ -288,7 +290,7 @@ func TestInvalidReserve(t *testing.T) {
288290
DustLimit: dustLimit,
289291
}: NewChannelAcceptResponse(
290292
false, errChannelRejected, nil, 0, 0,
291-
0, reserve, 0, 0,
293+
0, reserve, 0, 0, false,
292294
),
293295
}
294296

chanacceptor/chainedacceptor.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (c *ChainedAcceptor) Accept(req *ChannelAcceptRequest) *ChannelAcceptRespon
8080

8181
return NewChannelAcceptResponse(
8282
false, errChannelRejected, nil, 0, 0,
83-
0, 0, 0, 0,
83+
0, 0, 0, 0, false,
8484
)
8585
}
8686
}

chanacceptor/interface.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ type ChannelAcceptResponse struct {
6262
// MinAcceptDepth is the minimum depth that the initiator of the
6363
// channel should wait before considering the channel open.
6464
MinAcceptDepth uint16
65+
66+
// ZeroConf indicates that the fundee wishes to send min_depth = 0 and
67+
// request a zero-conf channel with the counter-party.
68+
ZeroConf bool
6569
}
6670

6771
// NewChannelAcceptResponse is a constructor for a channel accept response,
@@ -72,7 +76,7 @@ type ChannelAcceptResponse struct {
7276
func NewChannelAcceptResponse(accept bool, acceptErr error,
7377
upfrontShutdown lnwire.DeliveryAddress, csvDelay, htlcLimit,
7478
minDepth uint16, reserve btcutil.Amount, inFlight,
75-
minHtlcIn lnwire.MilliSatoshi) *ChannelAcceptResponse {
79+
minHtlcIn lnwire.MilliSatoshi, zeroConf bool) *ChannelAcceptResponse {
7680

7781
resp := &ChannelAcceptResponse{
7882
UpfrontShutdown: upfrontShutdown,
@@ -82,6 +86,7 @@ func NewChannelAcceptResponse(accept bool, acceptErr error,
8286
HtlcLimit: htlcLimit,
8387
MinHtlcIn: minHtlcIn,
8488
MinAcceptDepth: minDepth,
89+
ZeroConf: zeroConf,
8590
}
8691

8792
// If we want to accept the channel, we return a response with a nil

chanacceptor/merge.go

+18
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,24 @@ const (
2020
fieldUpfrontShutdown = "upfront shutdown"
2121
)
2222

23+
var (
24+
errZeroConf = fmt.Errorf("zero-conf set with non-zero min-depth")
25+
)
26+
2327
// fieldMismatchError returns a merge error for a named field when we get two
2428
// channel acceptor responses which have different values set.
2529
func fieldMismatchError(name string, current, newValue interface{}) error {
2630
return fmt.Errorf("multiple values set for: %v, %v and %v",
2731
name, current, newValue)
2832
}
2933

34+
// mergeBool merges two boolean values.
35+
func mergeBool(current, newValue bool) bool {
36+
// If either is true, return true. It is not possible to have different
37+
// "non-zero" values like the other cases.
38+
return current || newValue
39+
}
40+
3041
// mergeInt64 merges two int64 values, failing if they have different non-zero
3142
// values.
3243
func mergeInt64(name string, current, newValue int64) (int64, error) {
@@ -117,6 +128,13 @@ func mergeResponse(current,
117128
}
118129
current.MinAcceptDepth = uint16(minDepth)
119130

131+
current.ZeroConf = mergeBool(current.ZeroConf, newValue.ZeroConf)
132+
133+
// Assert that if zero-conf is set, min-depth is zero.
134+
if current.ZeroConf && current.MinAcceptDepth != 0 {
135+
return current, errZeroConf
136+
}
137+
120138
reserve, err := mergeInt64(
121139
fieldReserve, int64(current.Reserve), int64(newValue.Reserve),
122140
)

chanacceptor/merge_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,18 @@ func TestMergeResponse(t *testing.T) {
167167
},
168168
err: nil,
169169
},
170+
{
171+
// Test the case where one response has ZeroConf set
172+
// and another has a non-zero min depth set.
173+
name: "zero conf conflict",
174+
current: ChannelAcceptResponse{
175+
ZeroConf: true,
176+
},
177+
new: ChannelAcceptResponse{
178+
MinAcceptDepth: 5,
179+
},
180+
err: errZeroConf,
181+
},
170182
}
171183

172184
for _, test := range tests {

chanacceptor/rpcacceptor.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func (r *RPCAcceptor) Accept(req *ChannelAcceptRequest) *ChannelAcceptResponse {
107107
// Create a rejection response which we can use for the cases where we
108108
// reject the channel.
109109
rejectChannel := NewChannelAcceptResponse(
110-
false, errChannelRejected, nil, 0, 0, 0, 0, 0, 0,
110+
false, errChannelRejected, nil, 0, 0, 0, 0, 0, 0, false,
111111
)
112112

113113
// Send the request to the newRequests channel.
@@ -216,6 +216,7 @@ func (r *RPCAcceptor) receiveResponses(errChan chan error,
216216
MaxHtlcCount: resp.MaxHtlcCount,
217217
MinHtlcIn: resp.MinHtlcIn,
218218
MinAcceptDepth: resp.MinAcceptDepth,
219+
ZeroConf: resp.ZeroConf,
219220
}
220221

221222
// We have received a decision for one of our channel
@@ -348,6 +349,7 @@ func (r *RPCAcceptor) sendAcceptRequests(errChan chan error,
348349
btcutil.Amount(resp.ReserveSat),
349350
lnwire.MilliSatoshi(resp.InFlightMaxMsat),
350351
lnwire.MilliSatoshi(resp.MinHtlcIn),
352+
resp.ZeroConf,
351353
)
352354

353355
// Delete the channel from the acceptRequests map.

channeldb/graph.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -1692,8 +1692,9 @@ func (c *ChannelGraph) PruneTip() (*chainhash.Hash, uint32, error) {
16921692
// database, then ErrEdgeNotFound will be returned. If strictZombiePruning is
16931693
// true, then when we mark these edges as zombies, we'll set up the keys such
16941694
// that we require the node that failed to send the fresh update to be the one
1695-
// that resurrects the channel from its zombie state.
1696-
func (c *ChannelGraph) DeleteChannelEdges(strictZombiePruning bool,
1695+
// that resurrects the channel from its zombie state. The markZombie bool
1696+
// denotes whether or not to mark the channel as a zombie.
1697+
func (c *ChannelGraph) DeleteChannelEdges(strictZombiePruning, markZombie bool,
16971698
chanIDs ...uint64) error {
16981699

16991700
// TODO(roasbeef): possibly delete from node bucket if node has no more
@@ -1730,7 +1731,7 @@ func (c *ChannelGraph) DeleteChannelEdges(strictZombiePruning bool,
17301731
byteOrder.PutUint64(rawChanID[:], chanID)
17311732
err := c.delChannelEdge(
17321733
edges, edgeIndex, chanIndex, zombieIndex, nodes,
1733-
rawChanID[:], true, strictZombiePruning,
1734+
rawChanID[:], markZombie, strictZombiePruning,
17341735
)
17351736
if err != nil {
17361737
return err

channeldb/graph_test.go

+14-8
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ func TestEdgeInsertionDeletion(t *testing.T) {
378378

379379
// Next, attempt to delete the edge from the database, again this
380380
// should proceed without any issues.
381-
if err := graph.DeleteChannelEdges(false, chanID); err != nil {
381+
if err := graph.DeleteChannelEdges(false, true, chanID); err != nil {
382382
t.Fatalf("unable to delete edge: %v", err)
383383
}
384384
assertNoEdge(t, graph, chanID)
@@ -398,7 +398,7 @@ func TestEdgeInsertionDeletion(t *testing.T) {
398398

399399
// Finally, attempt to delete a (now) non-existent edge within the
400400
// database, this should result in an error.
401-
err = graph.DeleteChannelEdges(false, chanID)
401+
err = graph.DeleteChannelEdges(false, true, chanID)
402402
if err != ErrEdgeNotFound {
403403
t.Fatalf("deleting a non-existent edge should fail!")
404404
}
@@ -1993,7 +1993,7 @@ func TestFilterKnownChanIDs(t *testing.T) {
19931993
if err := graph.AddChannelEdge(&channel); err != nil {
19941994
t.Fatalf("unable to create channel edge: %v", err)
19951995
}
1996-
err := graph.DeleteChannelEdges(false, channel.ChannelID)
1996+
err := graph.DeleteChannelEdges(false, true, channel.ChannelID)
19971997
if err != nil {
19981998
t.Fatalf("unable to mark edge zombie: %v", err)
19991999
}
@@ -2251,7 +2251,7 @@ func TestFetchChanInfos(t *testing.T) {
22512251
if err := graph.AddChannelEdge(&zombieChan); err != nil {
22522252
t.Fatalf("unable to create channel edge: %v", err)
22532253
}
2254-
err = graph.DeleteChannelEdges(false, zombieChan.ChannelID)
2254+
err = graph.DeleteChannelEdges(false, true, zombieChan.ChannelID)
22552255
require.NoError(t, err, "unable to delete and mark edge zombie")
22562256
edgeQuery = append(edgeQuery, zombieChanID.ToUint64())
22572257

@@ -2789,7 +2789,9 @@ func TestNodeIsPublic(t *testing.T) {
27892789
// graph. This will make Alice be seen as a private node as it no longer
27902790
// has any advertised edges.
27912791
for _, graph := range graphs {
2792-
err := graph.DeleteChannelEdges(false, aliceBobEdge.ChannelID)
2792+
err := graph.DeleteChannelEdges(
2793+
false, true, aliceBobEdge.ChannelID,
2794+
)
27932795
if err != nil {
27942796
t.Fatalf("unable to remove edge: %v", err)
27952797
}
@@ -2806,7 +2808,9 @@ func TestNodeIsPublic(t *testing.T) {
28062808
// completely remove the edge as it is not possible for her to know of
28072809
// it without it being advertised.
28082810
for i, graph := range graphs {
2809-
err := graph.DeleteChannelEdges(false, bobCarolEdge.ChannelID)
2811+
err := graph.DeleteChannelEdges(
2812+
false, true, bobCarolEdge.ChannelID,
2813+
)
28102814
if err != nil {
28112815
t.Fatalf("unable to remove edge: %v", err)
28122816
}
@@ -2900,7 +2904,9 @@ func TestDisabledChannelIDs(t *testing.T) {
29002904
}
29012905

29022906
// Delete the channel edge and ensure it is removed from the disabled list.
2903-
if err = graph.DeleteChannelEdges(false, edgeInfo.ChannelID); err != nil {
2907+
if err = graph.DeleteChannelEdges(
2908+
false, true, edgeInfo.ChannelID,
2909+
); err != nil {
29042910
t.Fatalf("unable to delete channel edge: %v", err)
29052911
}
29062912
disabledChanIds, err = graph.DisabledChannelIDs()
@@ -3111,7 +3117,7 @@ func TestGraphZombieIndex(t *testing.T) {
31113117

31123118
// If we delete the edge and mark it as a zombie, then we should expect
31133119
// to see it within the index.
3114-
err = graph.DeleteChannelEdges(false, edge.ChannelID)
3120+
err = graph.DeleteChannelEdges(false, true, edge.ChannelID)
31153121
require.NoError(t, err, "unable to mark edge as zombie")
31163122
isZombie, pubKey1, pubKey2 := graph.IsZombieEdge(edge.ChannelID)
31173123
if !isZombie {

0 commit comments

Comments
 (0)