Merge pull request #4344 from matheusdtech/lntest-improvs

lntest+itest improvements
This commit is contained in:
Olaoluwa Osuntokun 2020-07-15 18:01:33 -07:00 committed by GitHub
commit 26cff10c19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 119 additions and 73 deletions

@ -678,6 +678,8 @@ func (w *WalletKit) BumpFee(ctx context.Context,
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
// user is attempting to bump an unconfirmed transaction's fee rate by
// 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.
closeResp, err := closeRespStream.Recv()
if err != nil {
errChan <- err
errChan <- fmt.Errorf("unable to recv() from close "+
"stream: %v", err)
return
}
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)
if err != nil {
errChan <- err
errChan <- fmt.Errorf("unable to decode closeTxid: "+
"%v", err)
return
}
if err := n.WaitForTxBroadcast(ctx, *closeTxid); err != nil {
errChan <- err
errChan <- fmt.Errorf("error while waiting for "+
"broadcast tx: %v", err)
return
}
fin <- closeTxid
@ -1153,9 +1156,6 @@ func (n *NetworkHarness) CloseChannel(ctx context.Context,
// Wait until either the deadline for the context expires, an error
// occurs, or the channel close update is received.
select {
case <-ctx.Done():
return nil, nil, fmt.Errorf("timeout reached before channel close " +
"initiated")
case err := <-errChan:
return nil, nil, err
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")
}
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 {
txid, err := lnd.GetChanPointFundingTxid(chanPoint)
if err != nil {
@ -9055,6 +9088,29 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
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
// time. Once he's not watching, Carol will try to breach the channel.
restart, err := net.SuspendNode(dave)
@ -9083,9 +9139,6 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness,
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
// broadcasting his current channel state. This is actually the
// commitment transaction of a prior *revoked* state, so he'll soon
@ -13367,7 +13420,7 @@ func testChannelBackupUpdates(net *lntest.NetworkHarness, t *harnessTest) {
numChans := 2
chanAmt := btcutil.Amount(1000000)
for i := 0; i < numChans; i++ {
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
chanPoint := openChannelAndAssert(
ctxt, t, net, net.Alice, carol,
lntest.OpenChannelParams{
@ -13501,7 +13554,7 @@ func testExportChannelBackup(net *lntest.NetworkHarness, t *harnessTest) {
numChans := 2
chanAmt := btcutil.Amount(1000000)
for i := 0; i < numChans; i++ {
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
chanPoint := openChannelAndAssert(
ctxt, t, net, net.Alice, carol,
lntest.OpenChannelParams{

@ -86,12 +86,15 @@ func testCPFP(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("bob's output was not found within the transaction")
}
// We'll attempt to bump the fee of this transaction by performing a
// CPFP from Alice's point of view.
// Wait until bob has seen the tx and considers it as owned.
op := &lnrpc.OutPoint{
TxidBytes: txid[:],
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{
Outpoint: op,
SatPerByte: uint32(sweep.DefaultMaxFeeRate.FeePerKVByte() / 2000),

@ -625,9 +625,10 @@ func (hn *HarnessNode) initLightningClient(conn *grpc.ClientConn) error {
// Launch the watcher that will hook into graph related topology change
// from the PoV of this node.
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.
@ -688,28 +689,26 @@ func (hn *HarnessNode) writePidFile() error {
func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
*macaroon.Macaroon, error) {
// Wait until macaroon file is created before using it.
macTimeout := time.After(timeout)
for !fileExists(macPath) {
select {
case <-macTimeout:
return nil, fmt.Errorf("timeout waiting for macaroon "+
"file %s to be created after %d seconds",
macPath, timeout/time.Second)
case <-time.After(100 * time.Millisecond):
// Wait until macaroon file is created and has valid content before
// using it.
var mac *macaroon.Macaroon
err := wait.NoError(func() error {
macBytes, err := ioutil.ReadFile(macPath)
if err != nil {
return fmt.Errorf("error reading macaroon file: %v", err)
}
}
// Now that we know the file exists, read it and return the macaroon.
macBytes, err := ioutil.ReadFile(macPath)
if err != nil {
return nil, err
}
mac := &macaroon.Macaroon{}
if err = mac.UnmarshalBinary(macBytes); err != nil {
return nil, err
}
return mac, nil
newMac := &macaroon.Macaroon{}
if err = newMac.UnmarshalBinary(macBytes); err != nil {
return fmt.Errorf("error unmarshalling macaroon "+
"file: %v", err)
}
mac = newMac
return nil
}, timeout)
return mac, err
}
// 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) (
*grpc.ClientConn, error) {
// Wait until TLS certificate is created before using it, up to 30 sec.
tlsTimeout := time.After(DefaultTimeout)
for !fileExists(hn.Cfg.TLSCertPath) {
select {
case <-tlsTimeout:
return nil, fmt.Errorf("timeout waiting for TLS cert " +
"file to be created")
case <-time.After(100 * time.Millisecond):
}
// Wait until TLS certificate is created and has valid content before
// using it, up to 30 sec.
var tlsCreds credentials.TransportCredentials
err := wait.NoError(func() error {
var err error
tlsCreds, err = credentials.NewClientTLSFromFile(
hn.Cfg.TLSCertPath, "",
)
return err
}, DefaultTimeout)
if err != nil {
return nil, fmt.Errorf("error reading TLS cert: %v", err)
}
opts := []grpc.DialOption{grpc.WithBlock()}
tlsCreds, err := credentials.NewClientTLSFromFile(
hn.Cfg.TLSCertPath, "",
)
if err != nil {
return nil, err
opts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithTransportCredentials(tlsCreds),
}
opts = append(opts, grpc.WithTransportCredentials(tlsCreds))
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
if mac == nil {
return grpc.Dial(hn.Cfg.RPCAddr(), opts...)
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
}
macCred := macaroons.NewMacaroonCredential(mac)
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
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
// notifications, the GraphTopologySubscription client exposed as part of the
// gRPC interface is used.
func (hn *HarnessNode) lightningNetworkWatcher() {
func (hn *HarnessNode) lightningNetworkWatcher(subscribed chan error) {
defer hn.wg.Done()
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
@ -883,16 +882,16 @@ func (hn *HarnessNode) lightningNetworkWatcher() {
req := &lnrpc.GraphTopologySubscription{}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
topologyClient, err := hn.SubscribeChannelGraph(ctx, req)
if err != nil {
// We panic here in case of an error as failure to
// create the topology client will cause all subsequent
// tests to fail.
panic(fmt.Errorf("unable to create topology "+
"client: %v", err))
msg := fmt.Sprintf("%s(%d): unable to create topology "+
"client: %v (%s)", hn.Name(), hn.NodeID, err,
time.Now().String())
subscribed <- fmt.Errorf(msg)
return
}
defer cancelFunc()
close(subscribed)
for {
update, err := topologyClient.Recv()
@ -1157,14 +1156,3 @@ func (hn *HarnessNode) WaitForBalance(expectedBalance btcutil.Amount, confirmed
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
}