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

lightningnetwork / lnd / 13974489001

20 Mar 2025 04:32PM UTC coverage: 56.292% (-2.9%) from 59.168%
13974489001

Pull #8754

github

web-flow
Merge aed149e6b into ea050d06f
Pull Request #8754: Add `Outbound` Remote Signer implementation

594 of 1713 new or added lines in 26 files covered. (34.68%)

23052 existing lines in 272 files now uncovered.

105921 of 188165 relevant lines covered (56.29%)

23796.34 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
        // ErrDependenciesFinalized is an error that is returned when the final
60
        // dependencies have already been injected into a sub-server.
61
        ErrDependenciesFinalized = errors.New("final dependencies have " +
62
                "already been injected")
63
)
64

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

UNCOV
79
                var address string
×
UNCOV
80
                if len(o.Addresses) == 1 {
×
UNCOV
81
                        address = o.Addresses[0].EncodeAddress()
×
UNCOV
82
                }
×
83

UNCOV
84
                outputDetails = append(outputDetails, &OutputDetail{
×
UNCOV
85
                        OutputType:   MarshallOutputType(o.OutputType),
×
UNCOV
86
                        Address:      address,
×
UNCOV
87
                        PkScript:     hex.EncodeToString(o.PkScript),
×
UNCOV
88
                        OutputIndex:  int64(o.OutputIndex),
×
UNCOV
89
                        Amount:       int64(o.Value),
×
UNCOV
90
                        IsOurAddress: o.IsOurAddress,
×
UNCOV
91
                })
×
92
        }
93

UNCOV
94
        previousOutpoints := make([]*PreviousOutPoint, len(tx.PreviousOutpoints))
×
UNCOV
95
        for idx, previousOutPoint := range tx.PreviousOutpoints {
×
UNCOV
96
                previousOutpoints[idx] = &PreviousOutPoint{
×
UNCOV
97
                        Outpoint:    previousOutPoint.OutPoint,
×
UNCOV
98
                        IsOurOutput: previousOutPoint.IsOurOutput,
×
UNCOV
99
                }
×
UNCOV
100
        }
×
101

102
        // We also get unconfirmed transactions, so BlockHash can be nil.
UNCOV
103
        blockHash := ""
×
UNCOV
104
        if tx.BlockHash != nil {
×
UNCOV
105
                blockHash = tx.BlockHash.String()
×
UNCOV
106
        }
×
107

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

124
// RPCTransactionDetails returns a set of rpc transaction details.
125
func RPCTransactionDetails(txns []*lnwallet.TransactionDetail, firstIdx,
UNCOV
126
        lastIdx uint64) *TransactionDetails {
×
UNCOV
127

×
UNCOV
128
        txDetails := &TransactionDetails{
×
UNCOV
129
                Transactions: make([]*Transaction, len(txns)),
×
UNCOV
130
                FirstIndex:   firstIdx,
×
UNCOV
131
                LastIndex:    lastIdx,
×
UNCOV
132
        }
×
UNCOV
133

×
UNCOV
134
        for i, tx := range txns {
×
UNCOV
135
                txDetails.Transactions[i] = RPCTransaction(tx)
×
UNCOV
136
        }
×
137

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

UNCOV
148
        return txDetails
×
149
}
150

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

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

168
        // In the event that the caller set MinConfs > 0 and SpendUnconfirmed to
169
        // true, we'll return an error to indicate the conflict.
170
        case minConfs > 0 && spendUnconfirmed:
×
171
                return 0, errors.New("SpendUnconfirmed set to true with " +
×
172
                        "MinConfs > 0")
×
173

174
        // The funding transaction of the new channel to be created can be
175
        // funded with unconfirmed outputs.
UNCOV
176
        case spendUnconfirmed:
×
UNCOV
177
                return 0, nil
×
178

179
        // If none of the above cases matched, we'll return the value set
180
        // explicitly by the caller.
UNCOV
181
        default:
×
UNCOV
182
                return minConfs, nil
×
183
        }
184
}
185

186
// GetChanPointFundingTxid returns the given channel point's funding txid in
187
// raw bytes.
UNCOV
188
func GetChanPointFundingTxid(chanPoint *ChannelPoint) (*chainhash.Hash, error) {
×
UNCOV
189
        var txid []byte
×
UNCOV
190

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

UNCOV
203
                txid = h[:]
×
204
        }
205

UNCOV
206
        return chainhash.NewHash(txid)
×
207
}
208

209
// GetChannelOutPoint returns the outpoint of the related channel point.
UNCOV
210
func GetChannelOutPoint(chanPoint *ChannelPoint) (*OutPoint, error) {
×
UNCOV
211
        var txid []byte
×
UNCOV
212

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

219
        case *ChannelPoint_FundingTxidStr:
×
220
                s := chanPoint.GetFundingTxidStr()
×
221
                h, err := chainhash.NewHashFromStr(s)
×
222
                if err != nil {
×
223
                        return nil, err
×
224
                }
×
225

226
                txid = h[:]
×
227
        }
228

UNCOV
229
        return &OutPoint{
×
UNCOV
230
                TxidBytes:   txid,
×
UNCOV
231
                OutputIndex: chanPoint.OutputIndex,
×
UNCOV
232
        }, nil
×
233
}
234

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

×
UNCOV
242
        var feeRate chainfee.SatPerKWeight
×
UNCOV
243

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

250
        // Default to satPerVByte, and overwrite it if satPerByte is set.
UNCOV
251
        satPerKw := chainfee.SatPerKVByte(satPerVByte * 1000).FeePerKWeight()
×
UNCOV
252
        if satPerByte != 0 {
×
UNCOV
253
                satPerKw = chainfee.SatPerKVByte(
×
UNCOV
254
                        satPerByte * 1000,
×
UNCOV
255
                ).FeePerKWeight()
×
UNCOV
256
        }
×
257

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

UNCOV
270
        return feeRate, nil
×
271
}
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