walletrpc: add new RemoveTransaction endpoint.

The RemoveTransaction endpoint removes the transaction with the
provided txid including all its descendants from the internal wallet.

We still keep watching for the address of the transation in case
the transcation is confirmed nonetheless. This command is particular
useful for neutrino backends because new bitcoind versions do not
reply with an invalid transaction error code when the tx published
fails to be included into the mempool (fullnodes do).
This commit is contained in:
ziggie committed 2023-12-12 14:18:16 +01:00
1 parent 2bc6b22a43
commit 227ac770af
8 files changed
+910 -561

No files matched your search

+62
View File
@@ -172,6 +172,10 @@ var (
Entity: "onchain",
Action: "write",
}},
"/walletrpc.WalletKit/RemoveTransaction": {{
Entity: "onchain",
Action: "write",
}},
}
// DefaultWalletKitMacFilename is the default name of the wallet kit
@@ -672,6 +676,64 @@ func (w *WalletKit) PublishTransaction(ctx context.Context,
return &PublishResponse{}, nil
}
// RemoveTransaction attempts to remove the transaction and all of its
// descendants resulting from further spends of the outputs of the provided
// transaction id.
// NOTE: We do not remove the transaction from the rebroadcaster which might
// run in the background rebroadcasting not yet confirmed transactions. We do
// not have access to the rebroadcaster here nor should we. This command is not
// a way to remove transactions from the network. It is a way to shortcircuit
// wallet utxo housekeeping while transactions are still unconfirmed and we know
// that a transaction will never confirm because a replacement already pays
// higher fees.
func (w *WalletKit) RemoveTransaction(_ context.Context,
req *GetTransactionRequest) (*RemoveTransactionResponse, error) {
// If the client doesn't specify a hash, then there's nothing to
// return.
if req.Txid == "" {
return nil, fmt.Errorf("must provide a transaction hash")
}
txHash, err := chainhash.NewHashFromStr(req.Txid)
if err != nil {
return nil, err
}
// Query the tx store of our internal wallet for the specified
// transaction.
res, err := w.cfg.Wallet.GetTransactionDetails(txHash)
if err != nil {
return nil, fmt.Errorf("transaction with txid=%v not found "+
"in the internal wallet store", txHash)
}
// Only allow unconfirmed transactions to be removed because as soon
// as a transaction is confirmed it will be evaluated by the wallet
// again and the wallet state would be updated in case the user had
// removed the transaction accidentally.
if res.NumConfirmations > 0 {
return nil, fmt.Errorf("transaction with txid=%v is already "+
"confirmed (numConfs=%d) cannot be removed", txHash,
res.NumConfirmations)
}
tx := &wire.MsgTx{}
txReader := bytes.NewReader(res.RawTx)
if err := tx.Deserialize(txReader); err != nil {
return nil, err
}
err = w.cfg.Wallet.RemoveDescendants(tx)
if err != nil {
return nil, err
}
return &RemoveTransactionResponse{
Status: "Successfully removed transaction",
}, nil
}
// SendOutputs is similar to the existing sendmany call in Bitcoind, and allows
// the caller to create a transaction that sends to several outputs at once.
// This is ideal when wanting to batch create a set of transactions.