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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

57.5
/lnwallet/commit_sort.go
1
package lnwallet
2

3
import (
4
        "bytes"
5
        "sort"
6

7
        "github.com/btcsuite/btcd/chaincfg/chainhash"
8
        "github.com/btcsuite/btcd/wire"
9
)
10

11
// InPlaceCommitSort performs an in-place sort of a commitment transaction,
12
// given an unsorted transaction and a list of CLTV values for the HTLCs.
13
//
14
// The sort applied is a modified BIP69 sort, that uses the CLTV values of HTLCs
15
// as a tie breaker in case two HTLC outputs have an identical amount and
16
// pkscript. The pkscripts can be the same if they share the same payment hash,
17
// but since the CLTV is enforced via the nLockTime of the second-layer
18
// transactions, the script does not directly commit to them. Instead, the CLTVs
19
// must be supplied separately to act as a tie-breaker, otherwise we may produce
20
// invalid HTLC signatures if the receiver produces an alternative ordering
21
// during verification.
22
//
23
// NOTE: Commitment outputs should have a 0 CLTV corresponding to their index on
24
// the unsorted commitment transaction.
25
func InPlaceCommitSort(tx *wire.MsgTx, cltvs []uint32) {
3✔
26
        if len(tx.TxOut) != len(cltvs) {
3✔
27
                panic("output and cltv list size mismatch")
×
28
        }
29

30
        sort.Sort(sortableInputSlice(tx.TxIn))
3✔
31
        sort.Sort(sortableCommitOutputSlice{tx.TxOut, cltvs})
3✔
32
}
33

34
// sortableInputSlice is a slice of transaction inputs that supports sorting via
35
// BIP69.
36
type sortableInputSlice []*wire.TxIn
37

38
// Len returns the length of the sortableInputSlice.
39
//
40
// NOTE: Part of the sort.Interface interface.
41
func (s sortableInputSlice) Len() int { return len(s) }
3✔
42

43
// Swap exchanges the position of inputs i and j.
44
//
45
// NOTE: Part of the sort.Interface interface.
UNCOV
46
func (s sortableInputSlice) Swap(i, j int) {
×
UNCOV
47
        s[i], s[j] = s[j], s[i]
×
UNCOV
48
}
×
49

50
// Less is the BIP69 input comparison function. The sort is first applied on
51
// input hash (reversed / rpc-style), then index. This logic is copied from
52
// btcutil/txsort.
53
//
54
// NOTE: Part of the sort.Interface interface.
UNCOV
55
func (s sortableInputSlice) Less(i, j int) bool {
×
UNCOV
56
        // Input hashes are the same, so compare the index.
×
UNCOV
57
        ihash := s[i].PreviousOutPoint.Hash
×
UNCOV
58
        jhash := s[j].PreviousOutPoint.Hash
×
UNCOV
59
        if ihash == jhash {
×
UNCOV
60
                return s[i].PreviousOutPoint.Index < s[j].PreviousOutPoint.Index
×
UNCOV
61
        }
×
62

63
        // At this point, the hashes are not equal, so reverse them to
64
        // big-endian and return the result of the comparison.
UNCOV
65
        const hashSize = chainhash.HashSize
×
UNCOV
66
        for b := 0; b < hashSize/2; b++ {
×
UNCOV
67
                ihash[b], ihash[hashSize-1-b] = ihash[hashSize-1-b], ihash[b]
×
UNCOV
68
                jhash[b], jhash[hashSize-1-b] = jhash[hashSize-1-b], jhash[b]
×
UNCOV
69
        }
×
UNCOV
70
        return bytes.Compare(ihash[:], jhash[:]) == -1
×
71
}
72

73
// sortableCommitOutputSlice is a slice of transaction outputs on a commitment
74
// transaction and the corresponding CLTV values of any HTLCs. Commitment
75
// outputs should have a CLTV of 0 and the same index in cltvs.
76
type sortableCommitOutputSlice struct {
77
        txouts []*wire.TxOut
78
        cltvs  []uint32
79
}
80

81
// Len returns the length of the sortableCommitOutputSlice.
82
//
83
// NOTE: Part of the sort.Interface interface.
84
func (s sortableCommitOutputSlice) Len() int {
3✔
85
        return len(s.txouts)
3✔
86
}
3✔
87

88
// Swap exchanges the position of outputs i and j, as well as their
89
// corresponding CLTV values.
90
//
91
// NOTE: Part of the sort.Interface interface.
92
func (s sortableCommitOutputSlice) Swap(i, j int) {
3✔
93
        s.txouts[i], s.txouts[j] = s.txouts[j], s.txouts[i]
3✔
94
        s.cltvs[i], s.cltvs[j] = s.cltvs[j], s.cltvs[i]
3✔
95
}
3✔
96

97
// Less is a modified BIP69 output comparison, that sorts based on value, then
98
// pkscript, then CLTV value.
99
//
100
// NOTE: Part of the sort.Interface interface.
101
func (s sortableCommitOutputSlice) Less(i, j int) bool {
3✔
102
        outi, outj := s.txouts[i], s.txouts[j]
3✔
103

3✔
104
        if outi.Value != outj.Value {
6✔
105
                return outi.Value < outj.Value
3✔
106
        }
3✔
107

108
        pkScriptCmp := bytes.Compare(outi.PkScript, outj.PkScript)
3✔
109
        if pkScriptCmp != 0 {
6✔
110
                return pkScriptCmp < 0
3✔
111
        }
3✔
112

113
        return s.cltvs[i] < s.cltvs[j]
3✔
114
}
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