• 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

4.93
/lntest/unittest/backend.go
1
package unittest
2

3
import (
4
        "fmt"
5
        "os/exec"
6
        "path/filepath"
7
        "testing"
8
        "time"
9

10
        "github.com/btcsuite/btcd/chaincfg"
11
        "github.com/btcsuite/btcd/integration/rpctest"
12
        "github.com/btcsuite/btcwallet/chain"
13
        "github.com/btcsuite/btcwallet/walletdb"
14
        "github.com/lightninglabs/neutrino"
15
        "github.com/lightningnetwork/lnd/kvdb"
16
        "github.com/lightningnetwork/lnd/lntest/port"
17
        "github.com/lightningnetwork/lnd/lntest/wait"
18
        "github.com/stretchr/testify/require"
19
)
20

21
var (
22
        // TrickleInterval is the interval at which the miner should trickle
23
        // transactions to its peers. We'll set it small to ensure the miner
24
        // propagates transactions quickly in the tests.
25
        TrickleInterval = 10 * time.Millisecond
26
)
27

28
var (
29
        // NetParams are the default network parameters for the tests.
30
        NetParams = &chaincfg.RegressionNetParams
31
)
32

33
// NewMiner spawns testing harness backed by a btcd node that can serve as a
34
// miner.
35
func NewMiner(t *testing.T, netParams *chaincfg.Params, extraArgs []string,
UNCOV
36
        createChain bool, spendableOutputs uint32) *rpctest.Harness {
×
UNCOV
37

×
UNCOV
38
        t.Helper()
×
UNCOV
39

×
UNCOV
40
        // Add the trickle interval argument to the extra args.
×
UNCOV
41
        trickle := fmt.Sprintf("--trickleinterval=%v", TrickleInterval)
×
UNCOV
42
        extraArgs = append(extraArgs, trickle)
×
UNCOV
43

×
UNCOV
44
        node, err := rpctest.New(netParams, nil, extraArgs, "")
×
UNCOV
45
        require.NoError(t, err, "unable to create backend node")
×
UNCOV
46
        t.Cleanup(func() {
×
UNCOV
47
                require.NoError(t, node.TearDown())
×
UNCOV
48
        })
×
49

50
        // We want to overwrite some of the connection settings to make the
51
        // tests more robust. We might need to restart the backend while there
52
        // are already blocks present, which will take a bit longer than the
53
        // 1 second the default settings amount to. Doubling both values will
54
        // give us retries up to 4 seconds.
UNCOV
55
        node.MaxConnRetries = rpctest.DefaultMaxConnectionRetries * 2
×
UNCOV
56
        node.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
×
UNCOV
57

×
UNCOV
58
        if err := node.SetUp(createChain, spendableOutputs); err != nil {
×
59
                t.Fatalf("unable to set up backend node: %v", err)
×
60
        }
×
61

62
        // Next mine enough blocks in order for segwit and the CSV package
63
        // soft-fork to activate.
UNCOV
64
        numBlocks := netParams.MinerConfirmationWindow*2 + 17
×
UNCOV
65
        _, err = node.Client.Generate(numBlocks)
×
UNCOV
66
        require.NoError(t, err, "failed to generate blocks")
×
UNCOV
67

×
UNCOV
68
        return node
×
69
}
70

71
// NewBitcoindBackend spawns a new bitcoind node that connects to a miner at the
72
// specified address. The txindex boolean can be set to determine whether the
73
// backend node should maintain a transaction index. The rpcpolling boolean
74
// can be set to determine whether bitcoind's RPC polling interface should be
75
// used for block and tx notifications or if its ZMQ interface should be used.
76
// A connection to the newly spawned bitcoind node is returned.
77
func NewBitcoindBackend(t *testing.T, netParams *chaincfg.Params,
UNCOV
78
        minerAddr string, txindex, rpcpolling bool) *chain.BitcoindConn {
×
UNCOV
79

×
UNCOV
80
        t.Helper()
×
UNCOV
81

×
UNCOV
82
        tempBitcoindDir := t.TempDir()
×
UNCOV
83

×
UNCOV
84
        rpcPort := port.NextAvailablePort()
×
UNCOV
85
        torBindPort := port.NextAvailablePort()
×
UNCOV
86
        zmqBlockPort := port.NextAvailablePort()
×
UNCOV
87
        zmqTxPort := port.NextAvailablePort()
×
UNCOV
88
        zmqBlockHost := fmt.Sprintf("tcp://127.0.0.1:%d", zmqBlockPort)
×
UNCOV
89
        zmqTxHost := fmt.Sprintf("tcp://127.0.0.1:%d", zmqTxPort)
×
UNCOV
90

×
UNCOV
91
        args := []string{
×
UNCOV
92
                "-connect=" + minerAddr,
×
UNCOV
93
                "-datadir=" + tempBitcoindDir,
×
UNCOV
94
                "-regtest",
×
UNCOV
95
                "-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6fd$507c670e800a95" +
×
UNCOV
96
                        "284294edb5773b05544b220110063096c221be9933c82d38e1",
×
UNCOV
97
                fmt.Sprintf("-rpcport=%d", rpcPort),
×
UNCOV
98
                fmt.Sprintf("-bind=127.0.0.1:%d=onion", torBindPort),
×
UNCOV
99
                "-disablewallet",
×
UNCOV
100
                "-zmqpubrawblock=" + zmqBlockHost,
×
UNCOV
101
                "-zmqpubrawtx=" + zmqTxHost,
×
UNCOV
102
        }
×
UNCOV
103
        if txindex {
×
UNCOV
104
                args = append(args, "-txindex")
×
UNCOV
105
        }
×
106

UNCOV
107
        bitcoind := exec.Command("bitcoind", args...)
×
UNCOV
108
        if err := bitcoind.Start(); err != nil {
×
109
                t.Fatalf("unable to start bitcoind: %v", err)
×
110
        }
×
UNCOV
111
        t.Cleanup(func() {
×
UNCOV
112
                _ = bitcoind.Process.Kill()
×
UNCOV
113
                _ = bitcoind.Wait()
×
UNCOV
114
        })
×
115

116
        // Wait for the bitcoind instance to start up.
UNCOV
117
        time.Sleep(time.Second)
×
UNCOV
118

×
UNCOV
119
        host := fmt.Sprintf("127.0.0.1:%d", rpcPort)
×
UNCOV
120
        cfg := &chain.BitcoindConfig{
×
UNCOV
121
                ChainParams: netParams,
×
UNCOV
122
                Host:        host,
×
UNCOV
123
                User:        "weks",
×
UNCOV
124
                Pass:        "weks",
×
UNCOV
125
                // Fields only required for pruned nodes, not needed for these
×
UNCOV
126
                // tests.
×
UNCOV
127
                Dialer:             nil,
×
UNCOV
128
                PrunedModeMaxPeers: 0,
×
UNCOV
129
        }
×
UNCOV
130

×
UNCOV
131
        if rpcpolling {
×
UNCOV
132
                cfg.PollingConfig = &chain.PollingConfig{
×
UNCOV
133
                        BlockPollingInterval: time.Millisecond * 20,
×
UNCOV
134
                        TxPollingInterval:    time.Millisecond * 20,
×
UNCOV
135
                }
×
UNCOV
136
        } else {
×
UNCOV
137
                cfg.ZMQConfig = &chain.ZMQConfig{
×
UNCOV
138
                        ZMQBlockHost:    zmqBlockHost,
×
UNCOV
139
                        ZMQTxHost:       zmqTxHost,
×
UNCOV
140
                        ZMQReadDeadline: 5 * time.Second,
×
UNCOV
141
                }
×
UNCOV
142
        }
×
143

UNCOV
144
        var conn *chain.BitcoindConn
×
UNCOV
145
        err := wait.NoError(func() error {
×
UNCOV
146
                var err error
×
UNCOV
147
                conn, err = chain.NewBitcoindConn(cfg)
×
UNCOV
148
                if err != nil {
×
149
                        return err
×
150
                }
×
151

UNCOV
152
                return conn.Start()
×
153
        }, 10*time.Second)
UNCOV
154
        if err != nil {
×
155
                t.Fatalf("unable to establish connection to bitcoind at %v: "+
×
156
                        "%v", tempBitcoindDir, err)
×
157
        }
×
UNCOV
158
        t.Cleanup(conn.Stop)
×
UNCOV
159

×
UNCOV
160
        return conn
×
161
}
162

163
// NewNeutrinoBackend spawns a new neutrino node that connects to a miner at
164
// the specified address.
165
func NewNeutrinoBackend(t *testing.T, netParams *chaincfg.Params,
UNCOV
166
        minerAddr string) *neutrino.ChainService {
×
UNCOV
167

×
UNCOV
168
        t.Helper()
×
UNCOV
169

×
UNCOV
170
        spvDir := t.TempDir()
×
UNCOV
171

×
UNCOV
172
        dbName := filepath.Join(spvDir, "neutrino.db")
×
UNCOV
173
        spvDatabase, err := walletdb.Create(
×
UNCOV
174
                "bdb", dbName, true, kvdb.DefaultDBTimeout,
×
UNCOV
175
        )
×
UNCOV
176
        if err != nil {
×
177
                t.Fatalf("unable to create walletdb: %v", err)
×
178
        }
×
UNCOV
179
        t.Cleanup(func() {
×
UNCOV
180
                spvDatabase.Close()
×
UNCOV
181
        })
×
182

183
        // Create an instance of neutrino connected to the running btcd
184
        // instance.
UNCOV
185
        spvConfig := neutrino.Config{
×
UNCOV
186
                DataDir:      spvDir,
×
UNCOV
187
                Database:     spvDatabase,
×
UNCOV
188
                ChainParams:  *netParams,
×
UNCOV
189
                ConnectPeers: []string{minerAddr},
×
UNCOV
190
        }
×
UNCOV
191
        spvNode, err := neutrino.NewChainService(spvConfig)
×
UNCOV
192
        if err != nil {
×
193
                t.Fatalf("unable to create neutrino: %v", err)
×
194
        }
×
195

196
        // We'll also wait for the instance to sync up fully to the chain
197
        // generated by the btcd instance.
UNCOV
198
        _ = spvNode.Start()
×
UNCOV
199
        for !spvNode.IsCurrent() {
×
UNCOV
200
                time.Sleep(time.Millisecond * 100)
×
UNCOV
201
        }
×
UNCOV
202
        t.Cleanup(func() {
×
UNCOV
203
                _ = spvNode.Stop()
×
UNCOV
204
        })
×
205

UNCOV
206
        return spvNode
×
207
}
208

209
func init() {
3✔
210
        // Before we start any node, we need to make sure that any btcd or
3✔
211
        // bitcoind node that is started through the RPC harness uses a unique
3✔
212
        // port as well to avoid any port collisions.
3✔
213
        rpctest.ListenAddressGenerator =
3✔
214
                port.GenerateSystemUniqueListenerAddresses
3✔
215
}
3✔
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