• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 16683051882

01 Aug 2025 07:03PM UTC coverage: 54.949% (-12.1%) from 67.047%
16683051882

Pull #9455

github

web-flow
Merge 3f1f50be8 into 37523b6cb
Pull Request #9455: discovery+lnwire: add support for DNS host name in NodeAnnouncement msg

144 of 226 new or added lines in 7 files covered. (63.72%)

23852 existing lines in 290 files now uncovered.

108751 of 197912 relevant lines covered (54.95%)

22080.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lnrpc/rpc_utils.go
1
package lnrpc
2

3
import (
4
        "encoding/hex"
5
        "errors"
6
        "fmt"
7
        "sort"
8

9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/lightningnetwork/lnd/lnwallet"
11
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
12
        "github.com/lightningnetwork/lnd/sweep"
13
        "google.golang.org/protobuf/encoding/protojson"
14
)
15

16
const (
17
        // RegisterRPCMiddlewareURI is the full RPC method URI for the
18
        // middleware registration call. This is declared here rather than where
19
        // it's mainly used to avoid circular package dependencies.
20
        RegisterRPCMiddlewareURI = "/lnrpc.Lightning/RegisterRPCMiddleware"
21
)
22

23
var (
24
        // ProtoJSONMarshalOpts is a struct that holds the default marshal
25
        // options for marshaling protobuf messages into JSON in a
26
        // human-readable way. This should only be used in the CLI and in
27
        // integration tests.
28
        ProtoJSONMarshalOpts = &protojson.MarshalOptions{
29
                EmitUnpopulated: true,
30
                UseProtoNames:   true,
31
                Indent:          "    ",
32
                UseHexForBytes:  true,
33
        }
34

35
        // ProtoJSONUnmarshalOpts is a struct that holds the default unmarshal
36
        // options for un-marshaling lncli JSON into protobuf messages. This
37
        // should only be used in the CLI and in integration tests.
38
        ProtoJSONUnmarshalOpts = &protojson.UnmarshalOptions{
39
                AllowPartial:   false,
40
                UseHexForBytes: true,
41
        }
42

43
        // RESTJsonMarshalOpts is a struct that holds the default marshal
44
        // options for marshaling protobuf messages into REST JSON in a
45
        // human-readable way. This should be used when interacting with the
46
        // REST proxy only.
47
        RESTJsonMarshalOpts = &protojson.MarshalOptions{
48
                EmitUnpopulated: true,
49
                UseProtoNames:   true,
50
        }
51

52
        // RESTJsonUnmarshalOpts is a struct that holds the default unmarshal
53
        // options for un-marshaling REST JSON into protobuf messages. This
54
        // should be used when interacting with the REST proxy only.
55
        RESTJsonUnmarshalOpts = &protojson.UnmarshalOptions{
56
                AllowPartial: false,
57
        }
58
)
59

60
// RPCTransaction returns a rpc transaction.
UNCOV
61
func RPCTransaction(tx *lnwallet.TransactionDetail) *Transaction {
×
UNCOV
62
        var destAddresses []string
×
UNCOV
63
        // Re-package destination output information.
×
UNCOV
64
        var outputDetails []*OutputDetail
×
UNCOV
65
        for _, o := range tx.OutputDetails {
×
UNCOV
66
                // Note: DestAddresses is deprecated but we keep
×
UNCOV
67
                // populating it with addresses for backwards
×
UNCOV
68
                // compatibility.
×
UNCOV
69
                for _, a := range o.Addresses {
×
UNCOV
70
                        destAddresses = append(destAddresses,
×
UNCOV
71
                                a.EncodeAddress())
×
UNCOV
72
                }
×
73

UNCOV
74
                var address string
×
UNCOV
75
                if len(o.Addresses) == 1 {
×
UNCOV
76
                        address = o.Addresses[0].EncodeAddress()
×
UNCOV
77
                }
×
78

UNCOV
79
                outputDetails = append(outputDetails, &OutputDetail{
×
UNCOV
80
                        OutputType:   MarshallOutputType(o.OutputType),
×
UNCOV
81
                        Address:      address,
×
UNCOV
82
                        PkScript:     hex.EncodeToString(o.PkScript),
×
UNCOV
83
                        OutputIndex:  int64(o.OutputIndex),
×
UNCOV
84
                        Amount:       int64(o.Value),
×
UNCOV
85
                        IsOurAddress: o.IsOurAddress,
×
UNCOV
86
                })
×
87
        }
88

UNCOV
89
        previousOutpoints := make([]*PreviousOutPoint, len(tx.PreviousOutpoints))
×
UNCOV
90
        for idx, previousOutPoint := range tx.PreviousOutpoints {
×
UNCOV
91
                previousOutpoints[idx] = &PreviousOutPoint{
×
UNCOV
92
                        Outpoint:    previousOutPoint.OutPoint,
×
UNCOV
93
                        IsOurOutput: previousOutPoint.IsOurOutput,
×
UNCOV
94
                }
×
UNCOV
95
        }
×
96

97
        // We also get unconfirmed transactions, so BlockHash can be nil.
UNCOV
98
        blockHash := ""
×
UNCOV
99
        if tx.BlockHash != nil {
×
UNCOV
100
                blockHash = tx.BlockHash.String()
×
UNCOV
101
        }
×
102

UNCOV
103
        return &Transaction{
×
UNCOV
104
                TxHash:            tx.Hash.String(),
×
UNCOV
105
                Amount:            int64(tx.Value),
×
UNCOV
106
                NumConfirmations:  tx.NumConfirmations,
×
UNCOV
107
                BlockHash:         blockHash,
×
UNCOV
108
                BlockHeight:       tx.BlockHeight,
×
UNCOV
109
                TimeStamp:         tx.Timestamp,
×
UNCOV
110
                TotalFees:         tx.TotalFees,
×
UNCOV
111
                DestAddresses:     destAddresses,
×
UNCOV
112
                OutputDetails:     outputDetails,
×
UNCOV
113
                RawTxHex:          hex.EncodeToString(tx.RawTx),
×
UNCOV
114
                Label:             tx.Label,
×
UNCOV
115
                PreviousOutpoints: previousOutpoints,
×
UNCOV
116
        }
×
117
}
118

119
// RPCTransactionDetails returns a set of rpc transaction details.
120
func RPCTransactionDetails(txns []*lnwallet.TransactionDetail, firstIdx,
UNCOV
121
        lastIdx uint64) *TransactionDetails {
×
UNCOV
122

×
UNCOV
123
        txDetails := &TransactionDetails{
×
UNCOV
124
                Transactions: make([]*Transaction, len(txns)),
×
UNCOV
125
                FirstIndex:   firstIdx,
×
UNCOV
126
                LastIndex:    lastIdx,
×
UNCOV
127
        }
×
UNCOV
128

×
UNCOV
129
        for i, tx := range txns {
×
UNCOV
130
                txDetails.Transactions[i] = RPCTransaction(tx)
×
UNCOV
131
        }
×
132

133
        // Sort transactions by number of confirmations rather than height so
134
        // that unconfirmed transactions (height =0; confirmations =-1) will
135
        // follow the most recently set of confirmed transactions. If we sort
136
        // by height, unconfirmed transactions will follow our oldest
137
        // transactions, because they have lower block heights.
UNCOV
138
        sort.Slice(txDetails.Transactions, func(i, j int) bool {
×
UNCOV
139
                return txDetails.Transactions[i].NumConfirmations <
×
UNCOV
140
                        txDetails.Transactions[j].NumConfirmations
×
UNCOV
141
        })
×
142

UNCOV
143
        return txDetails
×
144
}
145

146
// ExtractMinConfs extracts the minimum number of confirmations that each
147
// output used to fund a transaction should satisfy.
UNCOV
148
func ExtractMinConfs(minConfs int32, spendUnconfirmed bool) (int32, error) {
×
UNCOV
149
        switch {
×
150
        // Ensure that the MinConfs parameter is non-negative.
151
        case minConfs < 0:
×
152
                return 0, errors.New("minimum number of confirmations must " +
×
153
                        "be a non-negative number")
×
154

155
        // The transaction should not be funded with unconfirmed outputs
156
        // unless explicitly specified by SpendUnconfirmed. We do this to
157
        // provide sane defaults to the OpenChannel RPC, as otherwise, if the
158
        // MinConfs field isn't explicitly set by the caller, we'll use
159
        // unconfirmed outputs without the caller being aware.
UNCOV
160
        case minConfs == 0 && !spendUnconfirmed:
×
UNCOV
161
                return 1, nil
×
162

163
        // In the event that the caller set MinConfs > 0 and SpendUnconfirmed to
164
        // true, we'll return an error to indicate the conflict.
165
        case minConfs > 0 && spendUnconfirmed:
×
166
                return 0, errors.New("SpendUnconfirmed set to true with " +
×
167
                        "MinConfs > 0")
×
168

169
        // The funding transaction of the new channel to be created can be
170
        // funded with unconfirmed outputs.
UNCOV
171
        case spendUnconfirmed:
×
UNCOV
172
                return 0, nil
×
173

174
        // If none of the above cases matched, we'll return the value set
175
        // explicitly by the caller.
UNCOV
176
        default:
×
UNCOV
177
                return minConfs, nil
×
178
        }
179
}
180

181
// GetChanPointFundingTxid returns the given channel point's funding txid in
182
// raw bytes.
UNCOV
183
func GetChanPointFundingTxid(chanPoint *ChannelPoint) (*chainhash.Hash, error) {
×
UNCOV
184
        var txid []byte
×
UNCOV
185

×
UNCOV
186
        // A channel point's funding txid can be get/set as a byte slice or a
×
UNCOV
187
        // string. In the case it is a string, decode it.
×
UNCOV
188
        switch chanPoint.GetFundingTxid().(type) {
×
UNCOV
189
        case *ChannelPoint_FundingTxidBytes:
×
UNCOV
190
                txid = chanPoint.GetFundingTxidBytes()
×
UNCOV
191
        case *ChannelPoint_FundingTxidStr:
×
UNCOV
192
                s := chanPoint.GetFundingTxidStr()
×
UNCOV
193
                h, err := chainhash.NewHashFromStr(s)
×
UNCOV
194
                if err != nil {
×
195
                        return nil, err
×
196
                }
×
197

UNCOV
198
                txid = h[:]
×
199
        }
200

UNCOV
201
        return chainhash.NewHash(txid)
×
202
}
203

204
// GetChannelOutPoint returns the outpoint of the related channel point.
UNCOV
205
func GetChannelOutPoint(chanPoint *ChannelPoint) (*OutPoint, error) {
×
UNCOV
206
        var txid []byte
×
UNCOV
207

×
UNCOV
208
        // A channel point's funding txid can be get/set as a byte slice or a
×
UNCOV
209
        // string. In the case it is a string, decode it.
×
UNCOV
210
        switch chanPoint.GetFundingTxid().(type) {
×
UNCOV
211
        case *ChannelPoint_FundingTxidBytes:
×
UNCOV
212
                txid = chanPoint.GetFundingTxidBytes()
×
213

214
        case *ChannelPoint_FundingTxidStr:
×
215
                s := chanPoint.GetFundingTxidStr()
×
216
                h, err := chainhash.NewHashFromStr(s)
×
217
                if err != nil {
×
218
                        return nil, err
×
219
                }
×
220

221
                txid = h[:]
×
222
        }
223

UNCOV
224
        return &OutPoint{
×
UNCOV
225
                TxidBytes:   txid,
×
UNCOV
226
                OutputIndex: chanPoint.OutputIndex,
×
UNCOV
227
        }, nil
×
228
}
229

230
// CalculateFeeRate uses either satPerByte or satPerVByte, but not both, from a
231
// request to calculate the fee rate. It provides compatibility for the
232
// deprecated field, satPerByte. Once the field is safe to be removed, the
233
// check can then be deleted.
234
func CalculateFeeRate(satPerByte, satPerVByte uint64, targetConf uint32,
UNCOV
235
        estimator chainfee.Estimator) (chainfee.SatPerKWeight, error) {
×
UNCOV
236

×
UNCOV
237
        var feeRate chainfee.SatPerKWeight
×
UNCOV
238

×
UNCOV
239
        // We only allow using either the deprecated field or the new field.
×
UNCOV
240
        if satPerByte != 0 && satPerVByte != 0 {
×
241
                return feeRate, fmt.Errorf("either SatPerByte or " +
×
242
                        "SatPerVByte should be set, but not both")
×
243
        }
×
244

245
        // Default to satPerVByte, and overwrite it if satPerByte is set.
UNCOV
246
        satPerKw := chainfee.SatPerKVByte(satPerVByte * 1000).FeePerKWeight()
×
UNCOV
247
        if satPerByte != 0 {
×
UNCOV
248
                satPerKw = chainfee.SatPerKVByte(
×
UNCOV
249
                        satPerByte * 1000,
×
UNCOV
250
                ).FeePerKWeight()
×
UNCOV
251
        }
×
252

253
        // Based on the passed fee related parameters, we'll determine an
254
        // appropriate fee rate for this transaction.
UNCOV
255
        feePref := sweep.FeeEstimateInfo{
×
UNCOV
256
                ConfTarget: targetConf,
×
UNCOV
257
                FeeRate:    satPerKw,
×
UNCOV
258
        }
×
UNCOV
259
        // TODO(yy): need to pass the configured max fee here.
×
UNCOV
260
        feeRate, err := feePref.Estimate(estimator, 0)
×
UNCOV
261
        if err != nil {
×
262
                return feeRate, err
×
263
        }
×
264

UNCOV
265
        return feeRate, nil
×
266
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc