• 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

0.0
/watchtower/wtdb/migration6/client_db.go
1
package migration6
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "errors"
7

8
        "github.com/lightningnetwork/lnd/kvdb"
9
        "github.com/lightningnetwork/lnd/tlv"
10
)
11

12
var (
13
        // cSessionBkt is a top-level bucket storing:
14
        //   session-id => cSessionBody -> encoded ClientSessionBody
15
        //                 => cSessionDBID -> db-assigned-id
16
        //              => cSessionCommits => seqnum -> encoded CommittedUpdate
17
        //              => cSessionAcks => seqnum -> encoded BackupID
18
        cSessionBkt = []byte("client-session-bucket")
19

20
        // cSessionDBID is a key used in the cSessionBkt to store the
21
        // db-assigned-id of a session.
22
        cSessionDBID = []byte("client-session-db-id")
23

24
        // cSessionIDIndexBkt is a top-level bucket storing:
25
        //    db-assigned-id -> session-id
26
        cSessionIDIndexBkt = []byte("client-session-id-index")
27

28
        // cSessionBody is a sub-bucket of cSessionBkt storing only the body of
29
        // the ClientSession.
30
        cSessionBody = []byte("client-session-body")
31

32
        // ErrUninitializedDB signals that top-level buckets for the database
33
        // have not been initialized.
34
        ErrUninitializedDB = errors.New("db not initialized")
35

36
        // ErrCorruptClientSession signals that the client session's on-disk
37
        // structure deviates from what is expected.
38
        ErrCorruptClientSession = errors.New("client session corrupted")
39

40
        byteOrder = binary.BigEndian
41
)
42

43
// MigrateSessionIDIndex adds a new session ID index to the tower client db.
44
// This index is a mapping from db-assigned ID (a uint64 encoded using BigSize)
45
// to real session ID (33 bytes). This mapping will allow us to persist session
46
// pointers with fewer bytes in the future.
UNCOV
47
func MigrateSessionIDIndex(tx kvdb.RwTx) error {
×
UNCOV
48
        log.Infof("Migrating the tower client db to add a new session ID " +
×
UNCOV
49
                "index which stores a mapping from db-assigned ID to real " +
×
UNCOV
50
                "session ID")
×
UNCOV
51

×
UNCOV
52
        // Create a new top-level bucket for the index.
×
UNCOV
53
        indexBkt, err := tx.CreateTopLevelBucket(cSessionIDIndexBkt)
×
UNCOV
54
        if err != nil {
×
55
                return err
×
56
        }
×
57

58
        // Get the existing top-level sessions bucket.
UNCOV
59
        sessionsBkt := tx.ReadWriteBucket(cSessionBkt)
×
UNCOV
60
        if sessionsBkt == nil {
×
61
                return ErrUninitializedDB
×
62
        }
×
63

64
        // Iterate over the sessions bucket where each key is a session-ID.
UNCOV
65
        return sessionsBkt.ForEach(func(sessionID, _ []byte) error {
×
UNCOV
66
                // Ask the DB for a new, unique, id for the index bucket.
×
UNCOV
67
                nextSeq, err := indexBkt.NextSequence()
×
UNCOV
68
                if err != nil {
×
69
                        return err
×
70
                }
×
71

UNCOV
72
                newIndex, err := writeBigSize(nextSeq)
×
UNCOV
73
                if err != nil {
×
74
                        return err
×
75
                }
×
76

77
                // Add the new db-assigned-ID to real-session-ID pair to the
78
                // new index bucket.
UNCOV
79
                err = indexBkt.Put(newIndex, sessionID)
×
UNCOV
80
                if err != nil {
×
81
                        return err
×
82
                }
×
83

84
                // Get the sub-bucket for this specific session ID.
UNCOV
85
                sessionBkt := sessionsBkt.NestedReadWriteBucket(sessionID)
×
UNCOV
86
                if sessionBkt == nil {
×
UNCOV
87
                        return ErrCorruptClientSession
×
UNCOV
88
                }
×
89

90
                // Here we ensure that the session bucket includes a session
91
                // body. The only reason we do this is so that we can simulate
92
                // a migration fail in a test to ensure that a migration fail
93
                // results in an untouched db.
UNCOV
94
                sessionBodyBytes := sessionBkt.Get(cSessionBody)
×
UNCOV
95
                if sessionBodyBytes == nil {
×
96
                        return ErrCorruptClientSession
×
97
                }
×
98

99
                // Add the db-assigned ID of the session to the session under
100
                // the cSessionDBID key.
UNCOV
101
                return sessionBkt.Put(cSessionDBID, newIndex)
×
102
        })
103
}
104

105
// writeBigSize will encode the given uint64 as a BigSize byte slice.
UNCOV
106
func writeBigSize(i uint64) ([]byte, error) {
×
UNCOV
107
        var b bytes.Buffer
×
UNCOV
108
        err := tlv.WriteVarInt(&b, i, &[8]byte{})
×
UNCOV
109
        if err != nil {
×
110
                return nil, err
×
111
        }
×
112

UNCOV
113
        return b.Bytes(), nil
×
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