Skip to content

Commit 2a614cc

Browse files
committed
multi: add labels to lnd native transactions
Follow up labelling of external transactions with labels for the transaction types we create within lnd. Since these labels will live a life of string matching, a version number and rigid format is added so that string matching is less painful. We start out with channel ID, where available, and a transaction "type". External labels, added in a previous PR, are not updated to this new versioned label because they are not lnd-initiated transactions. Label matching can check this case, then check for a version number.
1 parent a39c91f commit 2a614cc

13 files changed

+225
-20
lines changed

breacharbiter.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/lightningnetwork/lnd/channeldb/kvdb"
2121
"github.com/lightningnetwork/lnd/htlcswitch"
2222
"github.com/lightningnetwork/lnd/input"
23+
"github.com/lightningnetwork/lnd/labels"
2324
"github.com/lightningnetwork/lnd/lnwallet"
2425
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
2526
)
@@ -566,7 +567,8 @@ justiceTxBroadcast:
566567

567568
// We'll now attempt to broadcast the transaction which finalized the
568569
// channel's retribution against the cheating counter party.
569-
err = b.cfg.PublishTransaction(finalTx, "")
570+
label := labels.MakeLabel(labels.LabelTypeJusticeTransaction, nil)
571+
err = b.cfg.PublishTransaction(finalTx, label)
570572
if err != nil {
571573
brarLog.Errorf("Unable to broadcast justice tx: %v", err)
572574

contractcourt/chain_arbitrator.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/lightningnetwork/lnd/channeldb/kvdb"
1616
"github.com/lightningnetwork/lnd/clock"
1717
"github.com/lightningnetwork/lnd/input"
18+
"github.com/lightningnetwork/lnd/labels"
1819
"github.com/lightningnetwork/lnd/lnwallet"
1920
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
2021
"github.com/lightningnetwork/lnd/lnwire"
@@ -715,7 +716,10 @@ func (c *ChainArbitrator) rebroadcast(channel *channeldb.OpenChannel,
715716
log.Infof("Re-publishing %s close tx(%v) for channel %v",
716717
kind, closeTx.TxHash(), chanPoint)
717718

718-
err = c.cfg.PublishTx(closeTx, "")
719+
label := labels.MakeLabel(
720+
labels.LabelTypeChannelClose, &channel.ShortChannelID,
721+
)
722+
err = c.cfg.PublishTx(closeTx, label)
719723
if err != nil && err != lnwallet.ErrDoubleSpend {
720724
log.Warnf("Unable to broadcast %s close tx(%v): %v",
721725
kind, closeTx.TxHash(), err)

contractcourt/channel_arbitrator.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/lightningnetwork/lnd/channeldb"
1717
"github.com/lightningnetwork/lnd/channeldb/kvdb"
1818
"github.com/lightningnetwork/lnd/input"
19+
"github.com/lightningnetwork/lnd/labels"
1920
"github.com/lightningnetwork/lnd/lntypes"
2021
"github.com/lightningnetwork/lnd/lnwallet"
2122
"github.com/lightningnetwork/lnd/lnwire"
@@ -874,7 +875,11 @@ func (c *ChannelArbitrator) stateStep(
874875

875876
// At this point, we'll now broadcast the commitment
876877
// transaction itself.
877-
if err := c.cfg.PublishTx(closeTx, ""); err != nil {
878+
label := labels.MakeLabel(
879+
labels.LabelTypeChannelClose, &c.cfg.ShortChanID,
880+
)
881+
882+
if err := c.cfg.PublishTx(closeTx, label); err != nil {
878883
log.Errorf("ChannelArbitrator(%v): unable to broadcast "+
879884
"close tx: %v", c.cfg.ChanPoint, err)
880885
if err != lnwallet.ErrDoubleSpend {

contractcourt/htlc_success_resolver.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/davecgh/go-spew/spew"
1111
"github.com/lightningnetwork/lnd/channeldb"
1212
"github.com/lightningnetwork/lnd/input"
13+
"github.com/lightningnetwork/lnd/labels"
1314
"github.com/lightningnetwork/lnd/lnwallet"
1415
"github.com/lightningnetwork/lnd/sweep"
1516
)
@@ -157,7 +158,10 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
157158
// Regardless of whether an existing transaction was found or newly
158159
// constructed, we'll broadcast the sweep transaction to the
159160
// network.
160-
err := h.PublishTx(h.sweepTx, "")
161+
label := labels.MakeLabel(
162+
labels.LabelTypeChannelClose, &h.ShortChanID,
163+
)
164+
err := h.PublishTx(h.sweepTx, label)
161165
if err != nil {
162166
log.Infof("%T(%x): unable to publish tx: %v",
163167
h, h.htlc.RHash[:], err)
@@ -206,7 +210,10 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
206210
// the claiming process.
207211
//
208212
// TODO(roasbeef): after changing sighashes send to tx bundler
209-
err := h.PublishTx(h.htlcResolution.SignedSuccessTx, "")
213+
label := labels.MakeLabel(
214+
labels.LabelTypeChannelClose, &h.ShortChanID,
215+
)
216+
err := h.PublishTx(h.htlcResolution.SignedSuccessTx, label)
210217
if err != nil {
211218
return nil, err
212219
}

fundingmanager.go

+39-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/lightningnetwork/lnd/htlcswitch"
2323
"github.com/lightningnetwork/lnd/input"
2424
"github.com/lightningnetwork/lnd/keychain"
25+
"github.com/lightningnetwork/lnd/labels"
2526
"github.com/lightningnetwork/lnd/lnpeer"
2627
"github.com/lightningnetwork/lnd/lnrpc"
2728
"github.com/lightningnetwork/lnd/lnwallet"
@@ -243,6 +244,10 @@ type fundingConfig struct {
243244
// transaction to the network.
244245
PublishTransaction func(*wire.MsgTx, string) error
245246

247+
// UpdateLabel updates the label that a transaction has in our wallet,
248+
// overwriting any existing labels.
249+
UpdateLabel func(chainhash.Hash, string) error
250+
246251
// FeeEstimator calculates appropriate fee rates based on historical
247252
// transaction information.
248253
FeeEstimator chainfee.Estimator
@@ -576,8 +581,15 @@ func (f *fundingManager) start() error {
576581
channel.FundingOutpoint,
577582
fundingTxBuf.Bytes())
578583

584+
// Set a nil short channel ID at this stage
585+
// because we do not know it until our funding
586+
// tx confirms.
587+
label := labels.MakeLabel(
588+
labels.LabelTypeChannelOpen, nil,
589+
)
590+
579591
err = f.cfg.PublishTransaction(
580-
channel.FundingTxn, "",
592+
channel.FundingTxn, label,
581593
)
582594
if err != nil {
583595
fndgLog.Errorf("Unable to rebroadcast "+
@@ -2032,7 +2044,13 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) {
20322044
fndgLog.Infof("Broadcasting funding tx for ChannelPoint(%v): %x",
20332045
completeChan.FundingOutpoint, fundingTxBuf.Bytes())
20342046

2035-
err = f.cfg.PublishTransaction(fundingTx, "")
2047+
// Set a nil short channel ID at this stage because we do not
2048+
// know it until our funding tx confirms.
2049+
label := labels.MakeLabel(
2050+
labels.LabelTypeChannelOpen, nil,
2051+
)
2052+
2053+
err = f.cfg.PublishTransaction(fundingTx, label)
20362054
if err != nil {
20372055
fndgLog.Errorf("Unable to broadcast funding tx %x for "+
20382056
"ChannelPoint(%v): %v", fundingTxBuf.Bytes(),
@@ -2372,6 +2390,25 @@ func (f *fundingManager) handleFundingConfirmation(
23722390
fndgLog.Errorf("unable to report short chan id: %v", err)
23732391
}
23742392

2393+
// If we opened the channel, and lnd's wallet published our funding tx
2394+
// (which is not the case for some channels) then we update our
2395+
// transaction label with our short channel ID, which is known now that
2396+
// our funding transaction has confirmed. We do not label transactions
2397+
// we did not publish, because our wallet has no knowledge of them.
2398+
if completeChan.IsInitiator && completeChan.ChanType.HasFundingTx() {
2399+
shortChanID := completeChan.ShortChanID()
2400+
label := labels.MakeLabel(
2401+
labels.LabelTypeChannelOpen, &shortChanID,
2402+
)
2403+
2404+
err = f.cfg.UpdateLabel(
2405+
completeChan.FundingOutpoint.Hash, label,
2406+
)
2407+
if err != nil {
2408+
fndgLog.Errorf("unable to update label: %v", err)
2409+
}
2410+
}
2411+
23752412
// Close the discoverySignal channel, indicating to a separate
23762413
// goroutine that the channel now is marked as open in the database
23772414
// and that it is acceptable to process funding locked messages

fundingmanager_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,9 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
421421
publTxChan <- txn
422422
return nil
423423
},
424+
UpdateLabel: func(chainhash.Hash, string) error {
425+
return nil
426+
},
424427
ZombieSweeperInterval: 1 * time.Hour,
425428
ReservationTimeout: 1 * time.Nanosecond,
426429
MaxPendingChannels: lncfg.DefaultMaxPendingChannels,
@@ -524,6 +527,9 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
524527
publishChan <- txn
525528
return nil
526529
},
530+
UpdateLabel: func(chainhash.Hash, string) error {
531+
return nil
532+
},
527533
ZombieSweeperInterval: oldCfg.ZombieSweeperInterval,
528534
ReservationTimeout: oldCfg.ReservationTimeout,
529535
OpenChannelPredicate: chainedAcceptor,

labels/labels.go

+59
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
// Package labels contains labels used to label transactions broadcast by lnd.
22
// These labels are used across packages, so they are declared in a separate
33
// package to avoid dependency issues.
4+
//
5+
// Labels for transactions broadcast by lnd have two set fields followed by an
6+
// optional set labelled data values, all separated by colons.
7+
// - Label version: an integer that indicates the version lnd used
8+
// - Label type: the type of transaction we are labelling
9+
// - {field name}-{value}: a named field followed by its value, these items are
10+
// optional, and there may be more than field present.
11+
//
12+
// For version 0 we have the following optional data fields defined:
13+
// - shortchanid: the short channel ID that a transaction is associated with,
14+
// with its value set to the uint64 short channel id.
415
package labels
516

617
import (
718
"fmt"
819

920
"github.com/btcsuite/btcwallet/wtxmgr"
21+
"github.com/lightningnetwork/lnd/lnwire"
1022
)
1123

1224
// External labels a transaction as user initiated via the api. This
@@ -31,3 +43,50 @@ func ValidateAPI(label string) (string, error) {
3143

3244
return label, nil
3345
}
46+
47+
// LabelVersion versions our labels so they can be easily update to contain
48+
// new data while still easily string matched.
49+
type LabelVersion uint8
50+
51+
// LabelVersionZero is the label version for labels that contain label type and
52+
// channel ID (where available).
53+
const LabelVersionZero LabelVersion = iota
54+
55+
// LabelType indicates the type of label we are creating. It is a string rather
56+
// than an int for easy string matching and human-readability.
57+
type LabelType string
58+
59+
const (
60+
// LabelTypeChannelOpen is used to label channel opens.
61+
LabelTypeChannelOpen LabelType = "openchannel"
62+
63+
// LabelTypeChannelClose is used to label channel closes.
64+
LabelTypeChannelClose LabelType = "closechannel"
65+
66+
// LabelTypeJusticeTransaction is used to label justice transactions.
67+
LabelTypeJusticeTransaction LabelType = "justicetx"
68+
69+
// LabelTypeSweepTransaction is used to label sweeps.
70+
LabelTypeSweepTransaction LabelType = "sweep"
71+
)
72+
73+
// LabelField is used to tag a value within a label.
74+
type LabelField string
75+
76+
const (
77+
// ShortChanID is used to tag short channel id values in our labels.
78+
ShortChanID LabelField = "shortchanid"
79+
)
80+
81+
// MakeLabel creates a label with the provided type and short channel id. If
82+
// our short channel ID is not known, we simply return version:label_type. If
83+
// we do have a short channel ID set, the label will also contain its value:
84+
// shortchanid-{int64 chan ID}.
85+
func MakeLabel(labelType LabelType, channelID *lnwire.ShortChannelID) string {
86+
if channelID == nil {
87+
return fmt.Sprintf("%v:%v", LabelVersionZero, labelType)
88+
}
89+
90+
return fmt.Sprintf("%v:%v:%v-%v", LabelVersionZero, labelType,
91+
ShortChanID, channelID.ToUint64())
92+
}

lntest/harness.go

+19-6
Original file line numberDiff line numberDiff line change
@@ -1204,9 +1204,14 @@ func (n *NetworkHarness) WaitForChannelClose(ctx context.Context,
12041204
}
12051205

12061206
// AssertChannelExists asserts that an active channel identified by the
1207-
// specified channel point exists from the point-of-view of the node.
1207+
// specified channel point exists from the point-of-view of the node. It takes
1208+
// an optional set of check functions which can be used to make further
1209+
// assertions using channel's values. These functions are responsible for
1210+
// failing the test themselves if they do not pass.
1211+
// nolint: interfacer
12081212
func (n *NetworkHarness) AssertChannelExists(ctx context.Context,
1209-
node *HarnessNode, chanPoint *wire.OutPoint) error {
1213+
node *HarnessNode, chanPoint *wire.OutPoint,
1214+
checks ...func(*lnrpc.Channel)) error {
12101215

12111216
req := &lnrpc.ListChannelsRequest{}
12121217

@@ -1218,12 +1223,20 @@ func (n *NetworkHarness) AssertChannelExists(ctx context.Context,
12181223

12191224
for _, channel := range resp.Channels {
12201225
if channel.ChannelPoint == chanPoint.String() {
1221-
if channel.Active {
1222-
return nil
1226+
// First check whether our channel is active,
1227+
// failing early if it is not.
1228+
if !channel.Active {
1229+
return fmt.Errorf("channel %s inactive",
1230+
chanPoint)
12231231
}
12241232

1225-
return fmt.Errorf("channel %s inactive",
1226-
chanPoint)
1233+
// Apply any additional checks that we would
1234+
// like to verify.
1235+
for _, check := range checks {
1236+
check(channel)
1237+
}
1238+
1239+
return nil
12271240
}
12281241
}
12291242

0 commit comments

Comments
 (0)