Merge pull request #4762 from carlaKC/4748-sweeps

multi: update listsweeps to allow sweeps that are not in ListTransactions
This commit is contained in:
Olaoluwa Osuntokun 2020-11-16 17:55:41 -08:00 committed by GitHub
commit e63f41c936
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 57 deletions

@ -1117,7 +1117,8 @@ var xxx_messageInfo_BumpFeeResponse proto.InternalMessageInfo
type ListSweepsRequest struct { type ListSweepsRequest struct {
// //
//Retrieve the full sweep transaction details. If false, only the sweep txids //Retrieve the full sweep transaction details. If false, only the sweep txids
//will be returned. //will be returned. Note that some sweeps that LND publishes will have been
//replaced-by-fee, so will not be included in this output.
Verbose bool `protobuf:"varint,1,opt,name=verbose,proto3" json:"verbose,omitempty"` Verbose bool `protobuf:"varint,1,opt,name=verbose,proto3" json:"verbose,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`

@ -464,7 +464,8 @@ message BumpFeeResponse {
message ListSweepsRequest { message ListSweepsRequest {
/* /*
Retrieve the full sweep transaction details. If false, only the sweep txids Retrieve the full sweep transaction details. If false, only the sweep txids
will be returned. will be returned. Note that some sweeps that LND publishes will have been
replaced-by-fee, so will not be included in this output.
*/ */
bool verbose = 1; bool verbose = 1;
} }

@ -299,7 +299,7 @@
"parameters": [ "parameters": [
{ {
"name": "verbose", "name": "verbose",
"description": "Retrieve the full sweep transaction details. If false, only the sweep txids\nwill be returned.", "description": "Retrieve the full sweep transaction details. If false, only the sweep txids\nwill be returned. Note that some sweeps that LND publishes will have been\nreplaced-by-fee, so will not be included in this output.",
"in": "query", "in": "query",
"required": false, "required": false,
"type": "boolean", "type": "boolean",

@ -782,29 +782,14 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
} }
sweepTxns := make(map[string]bool) sweepTxns := make(map[string]bool)
for _, sweep := range sweeps {
txids := make([]string, len(sweeps))
for i, sweep := range sweeps {
sweepTxns[sweep.String()] = true sweepTxns[sweep.String()] = true
txids[i] = sweep.String()
} }
// If the caller does not want verbose output, just return the set of // Some of our sweeps could have been replaced by fee, or dropped out
// sweep txids. // of the mempool. Here, we lookup our wallet transactions so that we
if !in.Verbose { // can match our list of sweeps against the list of transactions that
txidResp := &ListSweepsResponse_TransactionIDs{ // the wallet is still tracking.
TransactionIds: txids,
}
return &ListSweepsResponse{
Sweeps: &ListSweepsResponse_TransactionIds{
TransactionIds: txidResp,
},
}, nil
}
// If the caller does want full transaction lookups, query our wallet
// for all transactions, including unconfirmed transactions.
transactions, err := w.cfg.Wallet.ListTransactionDetails( transactions, err := w.cfg.Wallet.ListTransactionDetails(
0, btcwallet.UnconfirmedHeight, 0, btcwallet.UnconfirmedHeight,
) )
@ -812,26 +797,41 @@ func (w *WalletKit) ListSweeps(ctx context.Context,
return nil, err return nil, err
} }
var sweepTxDetails []*lnwallet.TransactionDetail var (
txids []string
txDetails []*lnwallet.TransactionDetail
)
for _, tx := range transactions { for _, tx := range transactions {
_, ok := sweepTxns[tx.Hash.String()] _, ok := sweepTxns[tx.Hash.String()]
if !ok { if !ok {
continue continue
} }
sweepTxDetails = append(sweepTxDetails, tx) // Add the txid or full tx details depending on whether we want
// verbose output or not.
if in.Verbose {
txDetails = append(txDetails, tx)
} else {
txids = append(txids, tx.Hash.String())
}
} }
// Fail if we have not retrieved all of our sweep transactions from the if in.Verbose {
// wallet. return &ListSweepsResponse{
if len(sweepTxDetails) != len(txids) { Sweeps: &ListSweepsResponse_TransactionDetails{
return nil, fmt.Errorf("not all sweeps found by list "+ TransactionDetails: lnrpc.RPCTransactionDetails(
"transactions: %v, %v", len(sweepTxDetails), len(txids)) txDetails,
),
},
}, nil
} }
return &ListSweepsResponse{ return &ListSweepsResponse{
Sweeps: &ListSweepsResponse_TransactionDetails{ Sweeps: &ListSweepsResponse_TransactionIds{
TransactionDetails: lnrpc.RPCTransactionDetails(transactions), TransactionIds: &ListSweepsResponse_TransactionIDs{
TransactionIds: txids,
},
}, },
}, nil }, nil
} }

@ -3975,11 +3975,8 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
} }
// Check that we can find the commitment sweep in our set of known // Check that we can find the commitment sweep in our set of known
// sweeps. // sweeps, using the simple transaction id ListSweeps output.
err = findSweep(ctxb, alice, sweepingTXID) assertSweepFound(ctxb, t.t, alice, sweepingTXID.String(), false)
if err != nil {
t.Fatalf("csv sweep not found: %v", err)
}
// Restart Alice to ensure that she resumes watching the finalized // Restart Alice to ensure that she resumes watching the finalized
// commitment sweep txid. // commitment sweep txid.
@ -4368,11 +4365,9 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
} }
} }
// Check that we can find the htlc sweep in our set of sweeps. // Check that we can find the htlc sweep in our set of sweeps using
err = findSweep(ctxb, alice, htlcSweepTx.Hash()) // the verbose output of the listsweeps output.
if err != nil { assertSweepFound(ctxb, t.t, alice, htlcSweepTx.Hash().String(), true)
t.Fatalf("htlc sweep not found: %v", err)
}
// The following restart checks to ensure that the nursery store is // The following restart checks to ensure that the nursery store is
// storing the txid of the previously broadcast htlc sweep txn, and that // storing the txid of the previously broadcast htlc sweep txn, and that
@ -4571,33 +4566,60 @@ func assertReports(ctxb context.Context, t *harnessTest,
} }
} }
// findSweep looks up a sweep in a nodes list of broadcast sweeps. // assertSweepFound looks up a sweep in a nodes list of broadcast sweeps.
func findSweep(ctx context.Context, node *lntest.HarnessNode, func assertSweepFound(ctx context.Context, t *testing.T, node *lntest.HarnessNode,
sweep *chainhash.Hash) error { sweep string, verbose bool) {
// List all sweeps that alice's node had broadcast. // List all sweeps that alice's node had broadcast.
ctx, _ = context.WithTimeout(ctx, defaultTimeout) ctx, _ = context.WithTimeout(ctx, defaultTimeout)
sweepResp, err := node.WalletKitClient.ListSweeps( sweepResp, err := node.WalletKitClient.ListSweeps(
ctx, &walletrpc.ListSweepsRequest{ ctx, &walletrpc.ListSweepsRequest{
Verbose: false, Verbose: verbose,
}) },
if err != nil { )
return fmt.Errorf("list sweeps error: %v", err) require.NoError(t, err)
var found bool
if verbose {
found = findSweepInDetails(t, sweep, sweepResp)
} else {
found = findSweepInTxids(t, sweep, sweepResp)
} }
sweepTxIDs, ok := sweepResp.Sweeps.(*walletrpc.ListSweepsResponse_TransactionIds) require.True(t, found, "sweep: %v not found", sweep)
if !ok {
return errors.New("expected sweep txids in response")
} }
func findSweepInTxids(t *testing.T, sweepTxid string,
sweepResp *walletrpc.ListSweepsResponse) bool {
sweepTxIDs := sweepResp.GetTransactionIds()
require.NotNil(t, sweepTxIDs, "expected transaction ids")
require.Nil(t, sweepResp.GetTransactionDetails())
// Check that the sweep tx we have just produced is present. // Check that the sweep tx we have just produced is present.
for _, tx := range sweepTxIDs.TransactionIds.TransactionIds { for _, tx := range sweepTxIDs.TransactionIds {
if tx == sweep.String() { if tx == sweepTxid {
return nil return true
} }
} }
return fmt.Errorf("sweep: %v not found", sweep.String()) return false
}
func findSweepInDetails(t *testing.T, sweepTxid string,
sweepResp *walletrpc.ListSweepsResponse) bool {
sweepDetails := sweepResp.GetTransactionDetails()
require.NotNil(t, sweepDetails, "expected transaction details")
require.Nil(t, sweepResp.GetTransactionIds())
for _, tx := range sweepDetails.Transactions {
if tx.TxHash == sweepTxid {
return true
}
}
return false
} }
// assertAmountSent generates a closure which queries listchannels for sndr and // assertAmountSent generates a closure which queries listchannels for sndr and