itest+lntest: migrate lntemp to lntest
This commit performs the takeover that `lntemp` is now promoted to be `lntest`, and the scaffolding is now removed as all the refactoring is finished!
This commit is contained in:
76 files changed
+590
-584
No files matched your search
@@ -0,0 +1,205 @@
|
||||
package lntest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest/node"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
)
|
||||
|
||||
// nodeManager is responsible for hanlding the start and stop of a given node.
|
||||
// It also keeps track of the running nodes.
|
||||
type nodeManager struct {
|
||||
sync.Mutex
|
||||
|
||||
// chainBackend houses the information necessary to use a node as LND
|
||||
// chain backend, such as rpc configuration, P2P information etc.
|
||||
chainBackend node.BackendConfig
|
||||
|
||||
// currentTestCase holds the name for the currently run test case.
|
||||
currentTestCase string
|
||||
|
||||
// lndBinary is the full path to the lnd binary that was specifically
|
||||
// compiled with all required itest flags.
|
||||
lndBinary string
|
||||
|
||||
// dbBackend sets the database backend to use.
|
||||
dbBackend node.DatabaseBackend
|
||||
|
||||
// activeNodes is a map of all running nodes, format:
|
||||
// {pubkey: *HarnessNode}.
|
||||
activeNodes map[uint32]*node.HarnessNode
|
||||
|
||||
// standbyNodes is a map of all the standby nodes, format:
|
||||
// {pubkey: *HarnessNode}.
|
||||
standbyNodes map[uint32]*node.HarnessNode
|
||||
|
||||
// nodeCounter is a monotonically increasing counter that's used as the
|
||||
// node's unique ID.
|
||||
nodeCounter uint32
|
||||
|
||||
// feeServiceURL is the url of the fee service.
|
||||
feeServiceURL string
|
||||
}
|
||||
|
||||
// newNodeManager creates a new node manager instance.
|
||||
func newNodeManager(lndBinary string,
|
||||
dbBackend node.DatabaseBackend) *nodeManager {
|
||||
|
||||
return &nodeManager{
|
||||
lndBinary: lndBinary,
|
||||
dbBackend: dbBackend,
|
||||
activeNodes: make(map[uint32]*node.HarnessNode),
|
||||
standbyNodes: make(map[uint32]*node.HarnessNode),
|
||||
}
|
||||
}
|
||||
|
||||
// nextNodeID generates a unique sequence to be used as the node's ID.
|
||||
func (nm *nodeManager) nextNodeID() uint32 {
|
||||
nodeID := atomic.AddUint32(&nm.nodeCounter, 1)
|
||||
return nodeID - 1
|
||||
}
|
||||
|
||||
// newNode initializes a new HarnessNode, supporting the ability to initialize
|
||||
// a wallet with or without a seed. If useSeed is false, the returned harness
|
||||
// node can be used immediately. Otherwise, the node will require an additional
|
||||
// initialization phase where the wallet is either created or restored.
|
||||
func (nm *nodeManager) newNode(t *testing.T, name string, extraArgs []string,
|
||||
password []byte, noAuth bool) (*node.HarnessNode, error) {
|
||||
|
||||
cfg := &node.BaseNodeConfig{
|
||||
Name: name,
|
||||
LogFilenamePrefix: nm.currentTestCase,
|
||||
Password: password,
|
||||
BackendCfg: nm.chainBackend,
|
||||
ExtraArgs: extraArgs,
|
||||
FeeURL: nm.feeServiceURL,
|
||||
DbBackend: nm.dbBackend,
|
||||
NodeID: nm.nextNodeID(),
|
||||
LndBinary: nm.lndBinary,
|
||||
NetParams: harnessNetParams,
|
||||
SkipUnlock: noAuth,
|
||||
}
|
||||
|
||||
node, err := node.NewHarnessNode(t, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Put node in activeNodes to ensure Shutdown is called even if start
|
||||
// returns an error.
|
||||
nm.registerNode(node)
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// RegisterNode records a new HarnessNode in the NetworkHarnesses map of known
|
||||
// nodes. This method should only be called with nodes that have successfully
|
||||
// retrieved their public keys via FetchNodeInfo.
|
||||
func (nm *nodeManager) registerNode(node *node.HarnessNode) {
|
||||
nm.Lock()
|
||||
nm.activeNodes[node.Cfg.NodeID] = node
|
||||
nm.Unlock()
|
||||
}
|
||||
|
||||
// ShutdownNode stops an active lnd process and returns when the process has
|
||||
// exited and any temporary directories have been cleaned up.
|
||||
func (nm *nodeManager) shutdownNode(node *node.HarnessNode) error {
|
||||
if err := node.Shutdown(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(nm.activeNodes, node.Cfg.NodeID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// restartNode attempts to restart a lightning node by shutting it down
|
||||
// cleanly, then restarting the process. This function is fully blocking. Upon
|
||||
// restart, the RPC connection to the node will be re-attempted, continuing iff
|
||||
// the connection attempt is successful. If the callback parameter is non-nil,
|
||||
// then the function will be executed after the node shuts down, but *before*
|
||||
// the process has been started up again.
|
||||
func (nm *nodeManager) restartNode(ctxt context.Context,
|
||||
hn *node.HarnessNode, callback func() error) error {
|
||||
|
||||
// Stop the node.
|
||||
if err := hn.Stop(); err != nil {
|
||||
return fmt.Errorf("restart node got error: %w", err)
|
||||
}
|
||||
|
||||
if callback != nil {
|
||||
if err := callback(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start the node without unlocking the wallet.
|
||||
if hn.Cfg.SkipUnlock {
|
||||
return hn.StartWithNoAuth(ctxt)
|
||||
}
|
||||
|
||||
return hn.Start(ctxt)
|
||||
}
|
||||
|
||||
// unlockNode unlocks the node's wallet if the password is configured.
|
||||
// Additionally, each time the node is unlocked, the caller can pass a set of
|
||||
// SCBs to pass in via the Unlock method allowing them to restore channels
|
||||
// during restart.
|
||||
func (nm *nodeManager) unlockNode(hn *node.HarnessNode,
|
||||
chanBackups ...*lnrpc.ChanBackupSnapshot) error {
|
||||
|
||||
// If the node doesn't have a password set, then we can exit here as we
|
||||
// don't need to unlock it.
|
||||
if len(hn.Cfg.Password) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise, we'll unlock the wallet, then complete the final steps
|
||||
// for the node initialization process.
|
||||
unlockReq := &lnrpc.UnlockWalletRequest{
|
||||
WalletPassword: hn.Cfg.Password,
|
||||
}
|
||||
if len(chanBackups) != 0 {
|
||||
unlockReq.ChannelBackups = chanBackups[0]
|
||||
unlockReq.RecoveryWindow = 100
|
||||
}
|
||||
|
||||
err := wait.NoError(func() error {
|
||||
return hn.Unlock(unlockReq)
|
||||
}, DefaultTimeout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: failed to unlock: %w", hn.Name(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initWalletAndNode will unlock the node's wallet and finish setting up the
|
||||
// node so it's ready to take RPC requests.
|
||||
func (nm *nodeManager) initWalletAndNode(hn *node.HarnessNode,
|
||||
req *lnrpc.InitWalletRequest) ([]byte, error) {
|
||||
|
||||
// Pass the init request via rpc to finish unlocking the node.
|
||||
resp := hn.RPC.InitWallet(req)
|
||||
|
||||
// Now that the wallet is unlocked, before creating an authed
|
||||
// connection we will close the old unauthed connection.
|
||||
if err := hn.CloseConn(); err != nil {
|
||||
return nil, fmt.Errorf("close unauthed conn failed")
|
||||
}
|
||||
|
||||
// Init the node, which will create the authed grpc conn and all its
|
||||
// rpc clients.
|
||||
err := hn.InitNode(resp.AdminMacaroon)
|
||||
|
||||
// In stateless initialization mode we get a macaroon back that we have
|
||||
// to return to the test, otherwise gRPC calls won't be possible since
|
||||
// there are no macaroon files created in that mode.
|
||||
// In stateful init the admin macaroon will just be nil.
|
||||
return resp.AdminMacaroon, err
|
||||
}
|
||||
Reference in new issue
Block a user