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

lightningnetwork / lnd / 12392191719

18 Dec 2024 11:38AM UTC coverage: 58.677%. First build
12392191719

Pull #9260

github

yyforyongyu
itest: fix flake in `testCoopCloseWithExternalDeliveryImpl`

The response from `ClosedChannels` may not be up-to-date, so we wrap it
inside a wait closure.
Pull Request #9260: Beat itest [3/3]: fix all itest flakes

1 of 117 new or added lines in 6 files covered. (0.85%)

135149 of 230328 relevant lines covered (58.68%)

19156.08 hits per line

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

0.0
/lntest/harness_node_manager.go
1
package lntest
2

3
import (
4
        "context"
5
        "fmt"
6
        "sync"
7
        "sync/atomic"
8
        "testing"
9

10
        "github.com/lightningnetwork/lnd/lnrpc"
11
        "github.com/lightningnetwork/lnd/lntest/miner"
12
        "github.com/lightningnetwork/lnd/lntest/node"
13
        "github.com/lightningnetwork/lnd/lntest/wait"
14
)
15

16
// nodeManager is responsible for handling the start and stop of a given node.
17
// It also keeps track of the running nodes.
18
type nodeManager struct {
19
        sync.Mutex
20

21
        // chainBackend houses the information necessary to use a node as LND
22
        // chain backend, such as rpc configuration, P2P information etc.
23
        chainBackend node.BackendConfig
24

25
        // currentTestCase holds the name for the currently run test case.
26
        currentTestCase string
27

28
        // lndBinary is the full path to the lnd binary that was specifically
29
        // compiled with all required itest flags.
30
        lndBinary string
31

32
        // dbBackend sets the database backend to use.
33
        dbBackend node.DatabaseBackend
34

35
        // nativeSQL sets the database backend to use native SQL when
36
        // applicable.
37
        nativeSQL bool
38

39
        // activeNodes is a map of all running nodes, format:
40
        // {pubkey: *HarnessNode}.
41
        activeNodes map[uint32]*node.HarnessNode
42

43
        // nodeCounter is a monotonically increasing counter that's used as the
44
        // node's unique ID.
45
        nodeCounter atomic.Uint32
46

47
        // feeServiceURL is the url of the fee service.
48
        feeServiceURL string
49
}
50

51
// newNodeManager creates a new node manager instance.
52
func newNodeManager(lndBinary string, dbBackend node.DatabaseBackend,
53
        nativeSQL bool) *nodeManager {
×
54

×
55
        return &nodeManager{
×
56
                lndBinary:   lndBinary,
×
57
                dbBackend:   dbBackend,
×
58
                nativeSQL:   nativeSQL,
×
59
                activeNodes: make(map[uint32]*node.HarnessNode),
×
60
        }
×
61
}
×
62

63
// nextNodeID generates a unique sequence to be used as the node's ID.
64
func (nm *nodeManager) nextNodeID() uint32 {
×
65
        nodeID := nm.nodeCounter.Add(1)
×
66
        return nodeID
×
67
}
×
68

69
// newNode initializes a new HarnessNode, supporting the ability to initialize
70
// a wallet with or without a seed. If useSeed is false, the returned harness
71
// node can be used immediately. Otherwise, the node will require an additional
72
// initialization phase where the wallet is either created or restored.
73
func (nm *nodeManager) newNode(t *testing.T, name string, extraArgs []string,
74
        password []byte, noAuth bool) (*node.HarnessNode, error) {
×
75

×
76
        cfg := &node.BaseNodeConfig{
×
77
                Name:              name,
×
78
                LogFilenamePrefix: nm.currentTestCase,
×
79
                Password:          password,
×
80
                BackendCfg:        nm.chainBackend,
×
81
                ExtraArgs:         extraArgs,
×
82
                FeeURL:            nm.feeServiceURL,
×
83
                DBBackend:         nm.dbBackend,
×
84
                NativeSQL:         nm.nativeSQL,
×
85
                NodeID:            nm.nextNodeID(),
×
86
                LndBinary:         nm.lndBinary,
×
87
                NetParams:         miner.HarnessNetParams,
×
88
                SkipUnlock:        noAuth,
×
89
        }
×
90

×
91
        node, err := node.NewHarnessNode(t, cfg)
×
92
        if err != nil {
×
93
                return nil, err
×
94
        }
×
95

96
        // Put node in activeNodes to ensure Shutdown is called even if start
97
        // returns an error.
98
        nm.registerNode(node)
×
99

×
100
        return node, nil
×
101
}
102

103
// RegisterNode records a new HarnessNode in the NetworkHarnesses map of known
104
// nodes. This method should only be called with nodes that have successfully
105
// retrieved their public keys via FetchNodeInfo.
106
func (nm *nodeManager) registerNode(node *node.HarnessNode) {
×
107
        nm.Lock()
×
108
        nm.activeNodes[node.Cfg.NodeID] = node
×
109
        nm.Unlock()
×
110
}
×
111

112
// ShutdownNode stops an active lnd process and returns when the process has
113
// exited and any temporary directories have been cleaned up.
114
func (nm *nodeManager) shutdownNode(node *node.HarnessNode) error {
×
NEW
115
        // Remove the node from the active nodes map even if the shutdown
×
NEW
116
        // fails as the shutdown cannot be retried in that case.
×
NEW
117
        delete(nm.activeNodes, node.Cfg.NodeID)
×
NEW
118

×
119
        if err := node.Shutdown(); err != nil {
×
120
                return err
×
121
        }
×
122

123
        return nil
×
124
}
125

126
// restartNode attempts to restart a lightning node by shutting it down
127
// cleanly, then restarting the process. This function is fully blocking. Upon
128
// restart, the RPC connection to the node will be re-attempted, continuing iff
129
// the connection attempt is successful. If the callback parameter is non-nil,
130
// then the function will be executed after the node shuts down, but *before*
131
// the process has been started up again.
132
func (nm *nodeManager) restartNode(ctxt context.Context,
133
        hn *node.HarnessNode, callback func() error) error {
×
134

×
135
        // Stop the node.
×
136
        if err := hn.Stop(); err != nil {
×
137
                return fmt.Errorf("restart node got error: %w", err)
×
138
        }
×
139

140
        if callback != nil {
×
141
                if err := callback(); err != nil {
×
142
                        return err
×
143
                }
×
144
        }
145

146
        // Start the node without unlocking the wallet.
147
        if hn.Cfg.SkipUnlock {
×
148
                return hn.StartWithNoAuth(ctxt)
×
149
        }
×
150

151
        return hn.Start(ctxt)
×
152
}
153

154
// unlockNode unlocks the node's wallet if the password is configured.
155
// Additionally, each time the node is unlocked, the caller can pass a set of
156
// SCBs to pass in via the Unlock method allowing them to restore channels
157
// during restart.
158
func (nm *nodeManager) unlockNode(hn *node.HarnessNode,
159
        chanBackups ...*lnrpc.ChanBackupSnapshot) error {
×
160

×
161
        // If the node doesn't have a password set, then we can exit here as we
×
162
        // don't need to unlock it.
×
163
        if len(hn.Cfg.Password) == 0 {
×
164
                return nil
×
165
        }
×
166

167
        // Otherwise, we'll unlock the wallet, then complete the final steps
168
        // for the node initialization process.
169
        unlockReq := &lnrpc.UnlockWalletRequest{
×
170
                WalletPassword: hn.Cfg.Password,
×
171
        }
×
172
        if len(chanBackups) != 0 {
×
173
                unlockReq.ChannelBackups = chanBackups[0]
×
174
                unlockReq.RecoveryWindow = 100
×
175
        }
×
176

177
        err := wait.NoError(func() error {
×
178
                return hn.Unlock(unlockReq)
×
179
        }, DefaultTimeout)
×
180
        if err != nil {
×
181
                return fmt.Errorf("%s: failed to unlock: %w", hn.Name(), err)
×
182
        }
×
183

184
        return nil
×
185
}
186

187
// initWalletAndNode will unlock the node's wallet and finish setting up the
188
// node so it's ready to take RPC requests.
189
func (nm *nodeManager) initWalletAndNode(hn *node.HarnessNode,
190
        req *lnrpc.InitWalletRequest) ([]byte, error) {
×
191

×
192
        // Pass the init request via rpc to finish unlocking the node.
×
193
        resp := hn.RPC.InitWallet(req)
×
194

×
195
        // Now that the wallet is unlocked, before creating an authed
×
196
        // connection we will close the old unauthed connection.
×
197
        if err := hn.CloseConn(); err != nil {
×
198
                return nil, fmt.Errorf("close unauthed conn failed")
×
199
        }
×
200

201
        // Init the node, which will create the authed grpc conn and all its
202
        // rpc clients.
203
        err := hn.InitNode(resp.AdminMacaroon)
×
204

×
205
        // In stateless initialization mode we get a macaroon back that we have
×
206
        // to return to the test, otherwise gRPC calls won't be possible since
×
207
        // there are no macaroon files created in that mode.
×
208
        // In stateful init the admin macaroon will just be nil.
×
209
        return resp.AdminMacaroon, err
×
210
}
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