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

lightningnetwork / lnd / 16277065588

14 Jul 2025 08:24PM UTC coverage: 57.625% (-9.7%) from 67.339%
16277065588

Pull #9993

github

web-flow
Merge c91033ae4 into 5bb227774
Pull Request #9993: Validate UTF-8 description and empty route hints when parsing BOLT-11 invoices

2 of 7 new or added lines in 1 file covered. (28.57%)

28404 existing lines in 457 files now uncovered.

98663 of 171215 relevant lines covered (57.63%)

1.79 hits per line

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

74.68
/shachain/store.go
1
package shachain
2

3
import (
4
        "encoding/binary"
5
        "errors"
6
        "fmt"
7
        "io"
8

9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
)
11

12
// Store is an interface which serves as an abstraction over data structure
13
// responsible for efficiently storing and restoring of hash secrets by given
14
// indexes.
15
//
16
// Description: The Lightning Network wants a chain of (say 1 million)
17
// unguessable 256 bit values; we generate them and send them one at a time to
18
// a remote node.  We don't want the remote node to have to store all the
19
// values, so it's better if they can derive them once they see them.
20
type Store interface {
21
        // LookUp function is used to restore/lookup/fetch the previous secret
22
        // by its index.
23
        LookUp(uint64) (*chainhash.Hash, error)
24

25
        // AddNextEntry attempts to store the given hash within its internal
26
        // storage in an efficient manner.
27
        //
28
        // NOTE: The hashes derived from the shachain MUST be inserted in the
29
        // order they're produced by a shachain.Producer.
30
        AddNextEntry(*chainhash.Hash) error
31

32
        // Encode writes a binary serialization of the shachain elements
33
        // currently saved by implementation of shachain.Store to the passed
34
        // io.Writer.
35
        Encode(io.Writer) error
36
}
37

38
// RevocationStore is a concrete implementation of the Store interface. The
39
// revocation store is able to efficiently store N derived shachain elements in
40
// a space efficient manner with a space complexity of O(log N). The original
41
// description of the storage methodology can be found here:
42
// https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#efficient-per-commitment-secret-storage
43
type RevocationStore struct {
44
        // lenBuckets stores the number of currently active buckets.
45
        lenBuckets uint8
46

47
        // buckets is an array of elements from which we may derive all
48
        // previous elements, each bucket corresponds to the element with the
49
        // particular number of trailing zeros.
50
        buckets [maxHeight]element
51

52
        // index is an available index which will be assigned to the new
53
        // element.
54
        index index
55
}
56

57
// A compile time check to ensure RevocationStore implements the Store
58
// interface.
59
var _ Store = (*RevocationStore)(nil)
60

61
// NewRevocationStore creates the new shachain store.
62
func NewRevocationStore() *RevocationStore {
3✔
63
        return &RevocationStore{
3✔
64
                lenBuckets: 0,
3✔
65
                index:      startIndex,
3✔
66
        }
3✔
67
}
3✔
68

69
// NewRevocationStoreFromBytes recreates the initial store state from the given
70
// binary shachain store representation.
71
func NewRevocationStoreFromBytes(r io.Reader) (*RevocationStore, error) {
3✔
72
        store := &RevocationStore{}
3✔
73

3✔
74
        if err := binary.Read(r, binary.BigEndian, &store.lenBuckets); err != nil {
3✔
75
                return nil, err
×
76
        }
×
77

78
        for i := uint8(0); i < store.lenBuckets; i++ {
6✔
79
                var hashIndex index
3✔
80
                err := binary.Read(r, binary.BigEndian, &hashIndex)
3✔
81
                if err != nil {
3✔
82
                        return nil, err
×
83
                }
×
84

85
                var nextHash chainhash.Hash
3✔
86
                if _, err := io.ReadFull(r, nextHash[:]); err != nil {
3✔
87
                        return nil, err
×
88
                }
×
89

90
                store.buckets[i] = element{
3✔
91
                        index: hashIndex,
3✔
92
                        hash:  nextHash,
3✔
93
                }
3✔
94
        }
95

96
        if err := binary.Read(r, binary.BigEndian, &store.index); err != nil {
3✔
97
                return nil, err
×
98
        }
×
99

100
        return store, nil
3✔
101
}
102

103
// LookUp function is used to restore/lookup/fetch the previous secret by its
104
// index. If secret which corresponds to given index was not previously placed
105
// in store we will not able to derive it and function will fail.
106
//
107
// NOTE: This function is part of the Store interface.
108
func (store *RevocationStore) LookUp(v uint64) (*chainhash.Hash, error) {
3✔
109
        ind := newIndex(v)
3✔
110

3✔
111
        // Trying to derive the index from one of the existing buckets elements.
3✔
112
        for i := uint8(0); i < store.lenBuckets; i++ {
6✔
113
                element, err := store.buckets[i].derive(ind)
3✔
114
                if err != nil {
6✔
115
                        continue
3✔
116
                }
117

118
                return &element.hash, nil
3✔
119
        }
120

121
        return nil, fmt.Errorf("unable to derive hash #%v", ind)
×
122
}
123

124
// AddNextEntry attempts to store the given hash within its internal storage in
125
// an efficient manner.
126
//
127
// NOTE: The hashes derived from the shachain MUST be inserted in the order
128
// they're produced by a shachain.Producer.
129
//
130
// NOTE: This function is part of the Store interface.
131
func (store *RevocationStore) AddNextEntry(hash *chainhash.Hash) error {
3✔
132
        newElement := &element{
3✔
133
                index: store.index,
3✔
134
                hash:  *hash,
3✔
135
        }
3✔
136

3✔
137
        bucket := countTrailingZeros(newElement.index)
3✔
138

3✔
139
        for i := uint8(0); i < bucket; i++ {
6✔
140
                e, err := newElement.derive(store.buckets[i].index)
3✔
141
                if err != nil {
3✔
142
                        return err
×
143
                }
×
144

145
                if !e.isEqual(&store.buckets[i]) {
3✔
UNCOV
146
                        return errors.New("hash isn't derivable from " +
×
UNCOV
147
                                "previous ones")
×
UNCOV
148
                }
×
149
        }
150

151
        store.buckets[bucket] = *newElement
3✔
152
        if bucket+1 > store.lenBuckets {
6✔
153
                store.lenBuckets = bucket + 1
3✔
154
        }
3✔
155

156
        store.index--
3✔
157
        return nil
3✔
158
}
159

160
// Encode writes a binary serialization of the shachain elements currently
161
// saved by implementation of shachain.Store to the passed io.Writer.
162
//
163
// NOTE: This function is part of the Store interface.
164
func (store *RevocationStore) Encode(w io.Writer) error {
3✔
165
        err := binary.Write(w, binary.BigEndian, store.lenBuckets)
3✔
166
        if err != nil {
3✔
167
                return err
×
168
        }
×
169

170
        for i := uint8(0); i < store.lenBuckets; i++ {
6✔
171
                element := store.buckets[i]
3✔
172

3✔
173
                err := binary.Write(w, binary.BigEndian, element.index)
3✔
174
                if err != nil {
3✔
175
                        return err
×
176
                }
×
177

178
                if _, err = w.Write(element.hash[:]); err != nil {
3✔
179
                        return err
×
180
                }
×
181

182
        }
183

184
        return binary.Write(w, binary.BigEndian, store.index)
3✔
185
}
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