mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-23 14:40:30 +01:00
Merge pull request #4344 from matheusdtech/lntest-improvs
lntest+itest improvements
This commit is contained in:
commit
26cff10c19
5 changed files with 119 additions and 73 deletions
|
@ -678,6 +678,8 @@ func (w *WalletKit) BumpFee(ctx context.Context,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("Attempting to CPFP outpoint %s", op)
|
||||||
|
|
||||||
// Since we're unable to perform a bump through RBF, we'll assume the
|
// Since we're unable to perform a bump through RBF, we'll assume the
|
||||||
// user is attempting to bump an unconfirmed transaction's fee rate by
|
// user is attempting to bump an unconfirmed transaction's fee rate by
|
||||||
// sweeping an output within it under control of the wallet with a
|
// sweeping an output within it under control of the wallet with a
|
||||||
|
|
|
@ -1128,7 +1128,8 @@ func (n *NetworkHarness) CloseChannel(ctx context.Context,
|
||||||
// within the network.
|
// within the network.
|
||||||
closeResp, err := closeRespStream.Recv()
|
closeResp, err := closeRespStream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- fmt.Errorf("unable to recv() from close "+
|
||||||
|
"stream: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pendingClose, ok := closeResp.Update.(*lnrpc.CloseStatusUpdate_ClosePending)
|
pendingClose, ok := closeResp.Update.(*lnrpc.CloseStatusUpdate_ClosePending)
|
||||||
|
@ -1140,11 +1141,13 @@ func (n *NetworkHarness) CloseChannel(ctx context.Context,
|
||||||
|
|
||||||
closeTxid, err := chainhash.NewHash(pendingClose.ClosePending.Txid)
|
closeTxid, err := chainhash.NewHash(pendingClose.ClosePending.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- fmt.Errorf("unable to decode closeTxid: "+
|
||||||
|
"%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := n.WaitForTxBroadcast(ctx, *closeTxid); err != nil {
|
if err := n.WaitForTxBroadcast(ctx, *closeTxid); err != nil {
|
||||||
errChan <- err
|
errChan <- fmt.Errorf("error while waiting for "+
|
||||||
|
"broadcast tx: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fin <- closeTxid
|
fin <- closeTxid
|
||||||
|
@ -1153,9 +1156,6 @@ func (n *NetworkHarness) CloseChannel(ctx context.Context,
|
||||||
// Wait until either the deadline for the context expires, an error
|
// Wait until either the deadline for the context expires, an error
|
||||||
// occurs, or the channel close update is received.
|
// occurs, or the channel close update is received.
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, nil, fmt.Errorf("timeout reached before channel close " +
|
|
||||||
"initiated")
|
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
case closeTxid := <-fin:
|
case closeTxid := <-fin:
|
||||||
|
|
|
@ -155,6 +155,39 @@ func assertTxInBlock(t *harnessTest, block *wire.MsgBlock, txid *chainhash.Hash)
|
||||||
t.Fatalf("tx was not included in block")
|
t.Fatalf("tx was not included in block")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertWalletUnspent(t *harnessTest, node *lntest.HarnessNode, out *lnrpc.OutPoint) {
|
||||||
|
t.t.Helper()
|
||||||
|
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
ctxt, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
unspent, err := node.ListUnspent(ctxt, &lnrpc.ListUnspentRequest{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = errors.New("tx with wanted txhash never found")
|
||||||
|
for _, utxo := range unspent.Utxos {
|
||||||
|
if !bytes.Equal(utxo.Outpoint.TxidBytes, out.TxidBytes) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = errors.New("wanted output is not a wallet utxo")
|
||||||
|
if utxo.Outpoint.OutputIndex != out.OutputIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}, defaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("outpoint %s not unspent by %s's wallet: %v", out,
|
||||||
|
node.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func rpcPointToWirePoint(t *harnessTest, chanPoint *lnrpc.ChannelPoint) wire.OutPoint {
|
func rpcPointToWirePoint(t *harnessTest, chanPoint *lnrpc.ChannelPoint) wire.OutPoint {
|
||||||
txid, err := lnd.GetChanPointFundingTxid(chanPoint)
|
txid, err := lnd.GetChanPointFundingTxid(chanPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9055,6 +9088,29 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
|
||||||
|
|
||||||
davePreSweepBalance := daveBalResp.ConfirmedBalance
|
davePreSweepBalance := daveBalResp.ConfirmedBalance
|
||||||
|
|
||||||
|
// Wait until the backup has been accepted by the watchtower before
|
||||||
|
// shutting down Dave.
|
||||||
|
err = wait.NoError(func() error {
|
||||||
|
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
bkpStats, err := dave.WatchtowerClient.Stats(ctxt, &wtclientrpc.StatsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
if bkpStats == nil {
|
||||||
|
return errors.New("no active backup sessions")
|
||||||
|
}
|
||||||
|
if bkpStats.NumBackups == 0 {
|
||||||
|
return errors.New("no backups accepted")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, defaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to verify backup task completed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Shutdown Dave to simulate going offline for an extended period of
|
// Shutdown Dave to simulate going offline for an extended period of
|
||||||
// time. Once he's not watching, Carol will try to breach the channel.
|
// time. Once he's not watching, Carol will try to breach the channel.
|
||||||
restart, err := net.SuspendNode(dave)
|
restart, err := net.SuspendNode(dave)
|
||||||
|
@ -9083,9 +9139,6 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
|
||||||
t.Fatalf("db copy failed: %v", carolChan.NumUpdates)
|
t.Fatalf("db copy failed: %v", carolChan.NumUpdates)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(conner): add hook for backup completion
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
|
|
||||||
// Now force Carol to execute a *force* channel closure by unilaterally
|
// Now force Carol to execute a *force* channel closure by unilaterally
|
||||||
// broadcasting his current channel state. This is actually the
|
// broadcasting his current channel state. This is actually the
|
||||||
// commitment transaction of a prior *revoked* state, so he'll soon
|
// commitment transaction of a prior *revoked* state, so he'll soon
|
||||||
|
@ -13367,7 +13420,7 @@ func testChannelBackupUpdates(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
numChans := 2
|
numChans := 2
|
||||||
chanAmt := btcutil.Amount(1000000)
|
chanAmt := btcutil.Amount(1000000)
|
||||||
for i := 0; i < numChans; i++ {
|
for i := 0; i < numChans; i++ {
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
|
||||||
chanPoint := openChannelAndAssert(
|
chanPoint := openChannelAndAssert(
|
||||||
ctxt, t, net, net.Alice, carol,
|
ctxt, t, net, net.Alice, carol,
|
||||||
lntest.OpenChannelParams{
|
lntest.OpenChannelParams{
|
||||||
|
@ -13501,7 +13554,7 @@ func testExportChannelBackup(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
numChans := 2
|
numChans := 2
|
||||||
chanAmt := btcutil.Amount(1000000)
|
chanAmt := btcutil.Amount(1000000)
|
||||||
for i := 0; i < numChans; i++ {
|
for i := 0; i < numChans; i++ {
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
|
||||||
chanPoint := openChannelAndAssert(
|
chanPoint := openChannelAndAssert(
|
||||||
ctxt, t, net, net.Alice, carol,
|
ctxt, t, net, net.Alice, carol,
|
||||||
lntest.OpenChannelParams{
|
lntest.OpenChannelParams{
|
||||||
|
|
|
@ -86,12 +86,15 @@ func testCPFP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
t.Fatalf("bob's output was not found within the transaction")
|
t.Fatalf("bob's output was not found within the transaction")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll attempt to bump the fee of this transaction by performing a
|
// Wait until bob has seen the tx and considers it as owned.
|
||||||
// CPFP from Alice's point of view.
|
|
||||||
op := &lnrpc.OutPoint{
|
op := &lnrpc.OutPoint{
|
||||||
TxidBytes: txid[:],
|
TxidBytes: txid[:],
|
||||||
OutputIndex: uint32(bobOutputIdx),
|
OutputIndex: uint32(bobOutputIdx),
|
||||||
}
|
}
|
||||||
|
assertWalletUnspent(t, net.Bob, op)
|
||||||
|
|
||||||
|
// We'll attempt to bump the fee of this transaction by performing a
|
||||||
|
// CPFP from Alice's point of view.
|
||||||
bumpFeeReq := &walletrpc.BumpFeeRequest{
|
bumpFeeReq := &walletrpc.BumpFeeRequest{
|
||||||
Outpoint: op,
|
Outpoint: op,
|
||||||
SatPerByte: uint32(sweep.DefaultMaxFeeRate.FeePerKVByte() / 2000),
|
SatPerByte: uint32(sweep.DefaultMaxFeeRate.FeePerKVByte() / 2000),
|
||||||
|
|
108
lntest/node.go
108
lntest/node.go
|
@ -625,9 +625,10 @@ func (hn *HarnessNode) initLightningClient(conn *grpc.ClientConn) error {
|
||||||
// Launch the watcher that will hook into graph related topology change
|
// Launch the watcher that will hook into graph related topology change
|
||||||
// from the PoV of this node.
|
// from the PoV of this node.
|
||||||
hn.wg.Add(1)
|
hn.wg.Add(1)
|
||||||
go hn.lightningNetworkWatcher()
|
subscribed := make(chan error)
|
||||||
|
go hn.lightningNetworkWatcher(subscribed)
|
||||||
|
|
||||||
return nil
|
return <-subscribed
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchNodeInfo queries an unlocked node to retrieve its public key.
|
// FetchNodeInfo queries an unlocked node to retrieve its public key.
|
||||||
|
@ -688,28 +689,26 @@ func (hn *HarnessNode) writePidFile() error {
|
||||||
func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
|
func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
|
||||||
*macaroon.Macaroon, error) {
|
*macaroon.Macaroon, error) {
|
||||||
|
|
||||||
// Wait until macaroon file is created before using it.
|
// Wait until macaroon file is created and has valid content before
|
||||||
macTimeout := time.After(timeout)
|
// using it.
|
||||||
for !fileExists(macPath) {
|
var mac *macaroon.Macaroon
|
||||||
select {
|
err := wait.NoError(func() error {
|
||||||
case <-macTimeout:
|
macBytes, err := ioutil.ReadFile(macPath)
|
||||||
return nil, fmt.Errorf("timeout waiting for macaroon "+
|
if err != nil {
|
||||||
"file %s to be created after %d seconds",
|
return fmt.Errorf("error reading macaroon file: %v", err)
|
||||||
macPath, timeout/time.Second)
|
|
||||||
case <-time.After(100 * time.Millisecond):
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we know the file exists, read it and return the macaroon.
|
newMac := &macaroon.Macaroon{}
|
||||||
macBytes, err := ioutil.ReadFile(macPath)
|
if err = newMac.UnmarshalBinary(macBytes); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("error unmarshalling macaroon "+
|
||||||
return nil, err
|
"file: %v", err)
|
||||||
}
|
}
|
||||||
mac := &macaroon.Macaroon{}
|
mac = newMac
|
||||||
if err = mac.UnmarshalBinary(macBytes); err != nil {
|
|
||||||
return nil, err
|
return nil
|
||||||
}
|
}, timeout)
|
||||||
return mac, nil
|
|
||||||
|
return mac, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectRPCWithMacaroon uses the TLS certificate and given macaroon to
|
// ConnectRPCWithMacaroon uses the TLS certificate and given macaroon to
|
||||||
|
@ -717,34 +716,34 @@ func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
|
||||||
func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
|
func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
|
||||||
*grpc.ClientConn, error) {
|
*grpc.ClientConn, error) {
|
||||||
|
|
||||||
// Wait until TLS certificate is created before using it, up to 30 sec.
|
// Wait until TLS certificate is created and has valid content before
|
||||||
tlsTimeout := time.After(DefaultTimeout)
|
// using it, up to 30 sec.
|
||||||
for !fileExists(hn.Cfg.TLSCertPath) {
|
var tlsCreds credentials.TransportCredentials
|
||||||
select {
|
err := wait.NoError(func() error {
|
||||||
case <-tlsTimeout:
|
var err error
|
||||||
return nil, fmt.Errorf("timeout waiting for TLS cert " +
|
tlsCreds, err = credentials.NewClientTLSFromFile(
|
||||||
"file to be created")
|
hn.Cfg.TLSCertPath, "",
|
||||||
case <-time.After(100 * time.Millisecond):
|
)
|
||||||
}
|
return err
|
||||||
|
}, DefaultTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading TLS cert: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := []grpc.DialOption{grpc.WithBlock()}
|
opts := []grpc.DialOption{
|
||||||
tlsCreds, err := credentials.NewClientTLSFromFile(
|
grpc.WithBlock(),
|
||||||
hn.Cfg.TLSCertPath, "",
|
grpc.WithTransportCredentials(tlsCreds),
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
opts = append(opts, grpc.WithTransportCredentials(tlsCreds))
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if mac == nil {
|
if mac == nil {
|
||||||
return grpc.Dial(hn.Cfg.RPCAddr(), opts...)
|
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
|
||||||
}
|
}
|
||||||
macCred := macaroons.NewMacaroonCredential(mac)
|
macCred := macaroons.NewMacaroonCredential(mac)
|
||||||
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
|
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
|
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,7 +872,7 @@ func getChanPointFundingTxid(chanPoint *lnrpc.ChannelPoint) ([]byte, error) {
|
||||||
// closed or opened within the network. In order to dispatch these
|
// closed or opened within the network. In order to dispatch these
|
||||||
// notifications, the GraphTopologySubscription client exposed as part of the
|
// notifications, the GraphTopologySubscription client exposed as part of the
|
||||||
// gRPC interface is used.
|
// gRPC interface is used.
|
||||||
func (hn *HarnessNode) lightningNetworkWatcher() {
|
func (hn *HarnessNode) lightningNetworkWatcher(subscribed chan error) {
|
||||||
defer hn.wg.Done()
|
defer hn.wg.Done()
|
||||||
|
|
||||||
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
|
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
|
||||||
|
@ -883,16 +882,16 @@ func (hn *HarnessNode) lightningNetworkWatcher() {
|
||||||
|
|
||||||
req := &lnrpc.GraphTopologySubscription{}
|
req := &lnrpc.GraphTopologySubscription{}
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
defer cancelFunc()
|
||||||
topologyClient, err := hn.SubscribeChannelGraph(ctx, req)
|
topologyClient, err := hn.SubscribeChannelGraph(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We panic here in case of an error as failure to
|
msg := fmt.Sprintf("%s(%d): unable to create topology "+
|
||||||
// create the topology client will cause all subsequent
|
"client: %v (%s)", hn.Name(), hn.NodeID, err,
|
||||||
// tests to fail.
|
time.Now().String())
|
||||||
panic(fmt.Errorf("unable to create topology "+
|
subscribed <- fmt.Errorf(msg)
|
||||||
"client: %v", err))
|
return
|
||||||
}
|
}
|
||||||
|
close(subscribed)
|
||||||
defer cancelFunc()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
update, err := topologyClient.Recv()
|
update, err := topologyClient.Recv()
|
||||||
|
@ -1157,14 +1156,3 @@ func (hn *HarnessNode) WaitForBalance(expectedBalance btcutil.Amount, confirmed
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileExists reports whether the named file or directory exists.
|
|
||||||
// This function is taken from https://github.com/btcsuite/btcd
|
|
||||||
func fileExists(name string) bool {
|
|
||||||
if _, err := os.Stat(name); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue