Merge pull request #8887 from yyforyongyu/fix-err-match

multi: fix `lnwallet.ErrDoubleSpend`
This commit is contained in:
Yong 2024-07-08 14:09:07 +08:00 committed by GitHub
commit 3526f82b5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 165 additions and 99 deletions

View File

@ -220,4 +220,8 @@ func (n *NoChainSource) TestMempoolAccept([]*wire.MsgTx,
return nil, nil
}
func (n *NoChainSource) MapRPCErr(err error) error {
return err
}
var _ chain.Interface = (*NoChainSource)(nil)

View File

@ -17,9 +17,9 @@ import (
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btclog"
"github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet"
"github.com/btcsuite/btcwallet/walletdb"
@ -708,9 +708,9 @@ func (d *DefaultWalletImpl) BuildChainControl(
// The broadcast is already always active for neutrino nodes, so we
// don't want to create a rebroadcast loop.
if partialChainControl.Cfg.NeutrinoCS == nil {
cs := partialChainControl.ChainSource
broadcastCfg := pushtx.Config{
Broadcast: func(tx *wire.MsgTx) error {
cs := partialChainControl.ChainSource
_, err := cs.SendRawTransaction(
tx, true,
)
@ -724,7 +724,10 @@ func (d *DefaultWalletImpl) BuildChainControl(
// In case the backend is different from neutrino we
// make sure that broadcast backend errors are mapped
// to the neutrino broadcastErr.
MapCustomBroadcastError: broadcastErrorMapper,
MapCustomBroadcastError: func(err error) error {
rpcErr := cs.MapRPCErr(err)
return broadcastErrorMapper(rpcErr)
},
}
lnWalletConfig.Rebroadcaster = newWalletReBroadcaster(
@ -1475,27 +1478,27 @@ func parseHeaderStateAssertion(state string) (*headerfs.FilterHeader, error) {
// the neutrino BroadcastError which allows the Rebroadcaster which currently
// resides in the neutrino package to use all of its functionalities.
func broadcastErrorMapper(err error) error {
returnErr := rpcclient.MapRPCErr(err)
var returnErr error
// We only filter for specific backend errors which are relevant for the
// Rebroadcaster.
switch {
// This makes sure the tx is removed from the rebroadcaster once it is
// confirmed.
case errors.Is(returnErr, rpcclient.ErrTxAlreadyKnown),
errors.Is(err, rpcclient.ErrTxAlreadyConfirmed):
case errors.Is(err, chain.ErrTxAlreadyKnown),
errors.Is(err, chain.ErrTxAlreadyConfirmed):
returnErr = &pushtx.BroadcastError{
Code: pushtx.Confirmed,
Reason: returnErr.Error(),
Reason: err.Error(),
}
// Transactions which are still in mempool but might fall out because
// of low fees are rebroadcasted despite of their backend error.
case errors.Is(returnErr, rpcclient.ErrTxAlreadyInMempool):
case errors.Is(err, chain.ErrTxAlreadyInMempool):
returnErr = &pushtx.BroadcastError{
Code: pushtx.Mempool,
Reason: returnErr.Error(),
Reason: err.Error(),
}
// Transactions which are not accepted into mempool because of low fees
@ -1503,13 +1506,12 @@ func broadcastErrorMapper(err error) error {
// Mempool conditions change over time so it makes sense to retry
// publishing the transaction. Moreover we log the detailed error so the
// user can intervene and increase the size of his mempool.
case errors.Is(err, rpcclient.ErrMempoolMinFeeNotMet):
ltndLog.Warnf("Error while broadcasting transaction: %v",
returnErr)
case errors.Is(err, chain.ErrMempoolMinFeeNotMet):
ltndLog.Warnf("Error while broadcasting transaction: %v", err)
returnErr = &pushtx.BroadcastError{
Code: pushtx.Mempool,
Reason: returnErr.Error(),
Reason: err.Error(),
}
}

View File

@ -19,76 +19,25 @@
# Bug Fixes
* `closedchannels` now [successfully reports](https://github.com/lightningnetwork/lnd/pull/8800)
settled balances even if the delivery address is set to an address that
LND does not control.
* [SendPaymentV2](https://github.com/lightningnetwork/lnd/pull/8734) now cancels
the background payment loop if the user cancels the stream context.
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/8822) that caused
LND to read the config only partially and continued with the startup.
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/8887) in error
matching from publishing already confirmed transactions that can cause lnd
fail to startup if `btcd` with an older version (pre-`v0.24.2`) is used.
# New Features
## Functional Enhancements
## RPC Additions
* The [SendPaymentRequest](https://github.com/lightningnetwork/lnd/pull/8734)
message receives a new flag `cancelable` which indicates if the payment loop
is cancelable. The cancellation can either occur manually by cancelling the
send payment stream context, or automatically at the end of the timeout period
if the user provided `timeout_seconds`.
## lncli Additions
* [Added](https://github.com/lightningnetwork/lnd/pull/8491) the `cltv_expiry`
argument to `addinvoice` and `addholdinvoice`, allowing users to set the
`min_final_cltv_expiry_delta`.
* The [`lncli wallet estimatefeerate`](https://github.com/lightningnetwork/lnd/pull/8730)
command returns the fee rate estimate for on-chain transactions in sat/kw and
sat/vb to achieve a given confirmation target.
# Improvements
## Functional Updates
## RPC Updates
* [`xImportMissionControl`](https://github.com/lightningnetwork/lnd/pull/8779)
now accepts `0` failure amounts.
* [`ChanInfoRequest`](https://github.com/lightningnetwork/lnd/pull/8813)
adds support for channel points.
## lncli Updates
* [`importmc`](https://github.com/lightningnetwork/lnd/pull/8779) now accepts
`0` failure amounts.
* [`getchaninfo`](https://github.com/lightningnetwork/lnd/pull/8813) now accepts
a channel outpoint besides a channel id.
* [Fixed](https://github.com/lightningnetwork/lnd/pull/8823) how we parse the
`--amp` flag when sending a payment specifying the payment request.
## Code Health
## Breaking Changes
## Performance Improvements
* Mission Control Store [improved performance during DB
flushing](https://github.com/lightningnetwork/lnd/pull/8549) stage.
# Technical and Architectural Updates
## BOLT Spec Updates
* Start assuming that all hops used during path-finding and route construction
[support the TLV onion
format](https://github.com/lightningnetwork/lnd/pull/8791).
* Allow channel fundee to send a [minimum confirmation depth of
0](https://github.com/lightningnetwork/lnd/pull/8796) for a non-zero-conf
channel. We will still wait for the channel to have at least one confirmation
and so the main change here is that we don't error out for such a case.
## Testing
## Database
@ -100,9 +49,4 @@
# Contributors (Alphabetical Order)
* Andras Banki-Horvath
* Bufo
* Elle Mouton
* Matheus Degiovani
* Oliver Gugger
* Slyghtning
* Yong Yu

View File

@ -0,0 +1,105 @@
# Release Notes
- [Bug Fixes](#bug-fixes)
- [New Features](#new-features)
- [Functional Enhancements](#functional-enhancements)
- [RPC Additions](#rpc-additions)
- [lncli Additions](#lncli-additions)
- [Improvements](#improvements)
- [Functional Updates](#functional-updates)
- [RPC Updates](#rpc-updates)
- [lncli Updates](#lncli-updates)
- [Breaking Changes](#breaking-changes)
- [Performance Improvements](#performance-improvements)
- [Technical and Architectural Updates](#technical-and-architectural-updates)
- [BOLT Spec Updates](#bolt-spec-updates)
- [Testing](#testing)
- [Database](#database)
- [Code Health](#code-health)
- [Tooling and Documentation](#tooling-and-documentation)
# Bug Fixes
* `closedchannels` now [successfully reports](https://github.com/lightningnetwork/lnd/pull/8800)
settled balances even if the delivery address is set to an address that
LND does not control.
* [SendPaymentV2](https://github.com/lightningnetwork/lnd/pull/8734) now cancels
the background payment loop if the user cancels the stream context.
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/8822) that caused
LND to read the config only partially and continued with the startup.
# New Features
## Functional Enhancements
## RPC Additions
* The [SendPaymentRequest](https://github.com/lightningnetwork/lnd/pull/8734)
message receives a new flag `cancelable` which indicates if the payment loop
is cancelable. The cancellation can either occur manually by cancelling the
send payment stream context, or automatically at the end of the timeout period
if the user provided `timeout_seconds`.
## lncli Additions
* [Added](https://github.com/lightningnetwork/lnd/pull/8491) the `cltv_expiry`
argument to `addinvoice` and `addholdinvoice`, allowing users to set the
`min_final_cltv_expiry_delta`.
* The [`lncli wallet estimatefeerate`](https://github.com/lightningnetwork/lnd/pull/8730)
command returns the fee rate estimate for on-chain transactions in sat/kw and
sat/vb to achieve a given confirmation target.
# Improvements
## Functional Updates
## RPC Updates
* [`xImportMissionControl`](https://github.com/lightningnetwork/lnd/pull/8779)
now accepts `0` failure amounts.
* [`ChanInfoRequest`](https://github.com/lightningnetwork/lnd/pull/8813)
adds support for channel points.
## lncli Updates
* [`importmc`](https://github.com/lightningnetwork/lnd/pull/8779) now accepts
`0` failure amounts.
* [`getchaninfo`](https://github.com/lightningnetwork/lnd/pull/8813) now accepts
a channel outpoint besides a channel id.
* [Fixed](https://github.com/lightningnetwork/lnd/pull/8823) how we parse the
`--amp` flag when sending a payment specifying the payment request.
## Code Health
## Breaking Changes
## Performance Improvements
* Mission Control Store [improved performance during DB
flushing](https://github.com/lightningnetwork/lnd/pull/8549) stage.
# Technical and Architectural Updates
## BOLT Spec Updates
* Start assuming that all hops used during path-finding and route construction
[support the TLV onion
format](https://github.com/lightningnetwork/lnd/pull/8791).
* Allow channel fundee to send a [minimum confirmation depth of
0](https://github.com/lightningnetwork/lnd/pull/8796) for a non-zero-conf
channel. We will still wait for the channel to have at least one confirmation
and so the main change here is that we don't error out for such a case.
## Testing
## Database
## Code Health
## Tooling and Documentation
# Contributors (Alphabetical Order)
* Andras Banki-Horvath
* Bufo
* Elle Mouton
* Matheus Degiovani
* Oliver Gugger
* Slyghtning
* Yong Yu

4
go.mod
View File

@ -10,7 +10,7 @@ require (
github.com/btcsuite/btcd/btcutil/psbt v1.1.8
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcwallet v0.16.10-0.20240625163855-b42ed59f0528
github.com/btcsuite/btcwallet v0.16.10-0.20240706055350-e391a1c31df2
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1
github.com/btcsuite/btcwallet/walletdb v1.4.2
@ -54,7 +54,7 @@ require (
golang.org/x/crypto v0.22.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028
golang.org/x/net v0.22.0
golang.org/x/net v0.24.0
golang.org/x/sync v0.6.0
golang.org/x/term v0.19.0
golang.org/x/time v0.3.0

8
go.sum
View File

@ -92,8 +92,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcwallet v0.16.10-0.20240625163855-b42ed59f0528 h1:DZRmr47CdPnNglwEVACPnJnGrfb/GBGyoGs5oqvLFg4=
github.com/btcsuite/btcwallet v0.16.10-0.20240625163855-b42ed59f0528/go.mod h1:SLFUSQbP8ON/wxholYMfVLvGPJyk7boczOW/ob+nww4=
github.com/btcsuite/btcwallet v0.16.10-0.20240706055350-e391a1c31df2 h1:mJquwdcEA4hZip4XKbRPAM9rOrus6wlNEcWzMz5CHsI=
github.com/btcsuite/btcwallet v0.16.10-0.20240706055350-e391a1c31df2/go.mod h1:SLFUSQbP8ON/wxholYMfVLvGPJyk7boczOW/ob+nww4=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 h1:poyHFf7+5+RdxNp5r2T6IBRD7RyraUsYARYbp/7t4D8=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4/go.mod h1:GETGDQuyq+VFfH1S/+/7slLM/9aNa4l7P4ejX6dJfb0=
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 h1:UZo7YRzdHbwhK7Rhv3PO9bXgTxiOH45edK5qdsdiatk=
@ -759,8 +759,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

View File

@ -157,3 +157,9 @@ func (m *MockChain) TestMempoolAccept(txns []*wire.MsgTx, maxFeeRate float64) (
return args.Get(0).([]*btcjson.TestMempoolAcceptResult), args.Error(1)
}
func (m *MockChain) MapRPCErr(err error) error {
args := m.Called(err)
return args.Error(0)
}

View File

@ -1191,8 +1191,8 @@ func (b *BtcWallet) ListUnspentWitness(minConfs, maxConfs int32,
return witnessOutputs, nil
}
// mapRpcclientError maps an error from the rpcclient package to defined error
// in this package.
// mapRpcclientError maps an error from the `btcwallet/chain` package to
// defined error in this package.
//
// NOTE: we are mapping the errors returned from `sendrawtransaction` RPC or
// the reject reason from `testmempoolaccept` RPC.
@ -1202,15 +1202,17 @@ func mapRpcclientError(err error) error {
switch {
// If the wallet reports a double spend, convert it to our internal
// ErrDoubleSpend and return.
case errors.Is(err, rpcclient.ErrMempoolConflict),
errors.Is(err, rpcclient.ErrMissingInputs):
case errors.Is(err, chain.ErrMempoolConflict),
errors.Is(err, chain.ErrMissingInputs),
errors.Is(err, chain.ErrTxAlreadyKnown),
errors.Is(err, chain.ErrTxAlreadyConfirmed):
return lnwallet.ErrDoubleSpend
// If the wallet reports that fee requirements for accepting the tx
// into mempool are not met, convert it to our internal ErrMempoolFee
// and return.
case errors.Is(err, rpcclient.ErrMempoolMinFeeNotMet):
case errors.Is(err, chain.ErrMempoolMinFeeNotMet):
return fmt.Errorf("%w: %v", lnwallet.ErrMempoolFee, err.Error())
}
@ -1277,7 +1279,7 @@ func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
// We need to use the string to create an error type and map it to a
// btcwallet error.
err = rpcclient.MapRPCErr(errors.New(result.RejectReason))
err = b.chain.MapRPCErr(errors.New(result.RejectReason))
//nolint:lll
// These two errors are ignored inside `PublishTransaction`:
@ -1295,9 +1297,9 @@ func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
// `PublishTransaction` again because we need to mark the label in the
// wallet. We can remove this exception once we have the above TODO
// fixed.
case errors.Is(err, rpcclient.ErrTxAlreadyInMempool),
errors.Is(err, rpcclient.ErrTxAlreadyKnown),
errors.Is(err, rpcclient.ErrTxAlreadyConfirmed):
case errors.Is(err, chain.ErrTxAlreadyInMempool),
errors.Is(err, chain.ErrTxAlreadyKnown),
errors.Is(err, chain.ErrTxAlreadyConfirmed):
err := b.wallet.PublishTransaction(tx, label)
return mapRpcclientError(err)
@ -1922,7 +1924,7 @@ func (b *BtcWallet) CheckMempoolAcceptance(tx *wire.MsgTx) error {
// Mempool check failed, we now map the reject reason to a proper RPC
// error and return it.
if !result.Allowed {
err := rpcclient.MapRPCErr(errors.New(result.RejectReason))
err := b.chain.MapRPCErr(errors.New(result.RejectReason))
return fmt.Errorf("mempool rejection: %w", err)
}

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcwallet/wallet"
"github.com/lightningnetwork/lnd/lnmock"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
@ -204,10 +205,12 @@ func TestCheckMempoolAcceptance(t *testing.T) {
}}
mockChain.On("TestMempoolAccept", []*wire.MsgTx{tx}, maxFeeRate).Return(
results, nil).Once()
mockChain.On("MapRPCErr", mock.Anything).Return(
chain.ErrInsufficientFee).Once()
// Now call the method under test.
err = wallet.CheckMempoolAcceptance(tx)
rt.ErrorIs(err, rpcclient.ErrInsufficientFee)
rt.ErrorIs(err, chain.ErrInsufficientFee)
// Assert that when the tx is accepted, no error is returned.
//

View File

@ -1808,7 +1808,7 @@ func testPublishTransaction(r *rpctest.Harness,
// If RBF is enabled, we expect it to be rejected
// because it doesn't pay enough fees.
if rbf {
expectedErr = rpcclient.ErrInsufficientFee
expectedErr = chain.ErrInsufficientFee
}
// Assert the expected error.
@ -1891,7 +1891,7 @@ func testPublishTransaction(r *rpctest.Harness,
// Now broadcast the transaction, we should get an error that
// the weight is too large.
err := alice.PublishTransaction(testTx, labels.External)
require.ErrorIs(t, err, rpcclient.ErrOversizeTx)
require.ErrorIs(t, err, chain.ErrOversizeTx)
})
}

View File

@ -427,7 +427,7 @@ func (t *TxPublisher) createRBFCompliantTx(req *BumpRequest,
fallthrough
// We are not paying enough fees so we increase it.
case errors.Is(err, rpcclient.ErrInsufficientFee):
case errors.Is(err, chain.ErrInsufficientFee):
increased := false
// Keep calling the fee function until the fee rate is
@ -934,7 +934,7 @@ func (t *TxPublisher) createAndPublishTx(requestID uint64,
// - if the deadline is close, we expect the fee function to give us a
// higher fee rate. If the fee rate cannot satisfy the RBF rules, it
// means the budget is not enough.
if errors.Is(err, rpcclient.ErrInsufficientFee) ||
if errors.Is(err, chain.ErrInsufficientFee) ||
errors.Is(err, lnwallet.ErrMempoolFee) {
log.Debugf("Failed to bump tx %v: %v", oldTx.TxHash(), err)
@ -989,7 +989,7 @@ func (t *TxPublisher) createAndPublishTx(requestID uint64,
//
// NOTE: we may get this error if we've bypassed the mempool check,
// which means we are suing neutrino backend.
if errors.Is(result.Err, rpcclient.ErrInsufficientFee) ||
if errors.Is(result.Err, chain.ErrInsufficientFee) ||
errors.Is(result.Err, lnwallet.ErrMempoolFee) {
log.Debugf("Failed to bump tx %v: %v", oldTx.TxHash(), err)

View File

@ -8,8 +8,8 @@ import (
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/chain"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
@ -569,7 +569,7 @@ func TestCreateRBFCompliantTx(t *testing.T) {
// for the first call.
m.wallet.On("CheckMempoolAcceptance",
mock.Anything).Return(
rpcclient.ErrInsufficientFee).Once()
chain.ErrInsufficientFee).Once()
// Mock the fee function to increase feerate.
m.feeFunc.On("Increment").Return(
@ -591,7 +591,7 @@ func TestCreateRBFCompliantTx(t *testing.T) {
// for the first call.
m.wallet.On("CheckMempoolAcceptance",
mock.Anything).Return(
rpcclient.ErrInsufficientFee).Once()
chain.ErrInsufficientFee).Once()
// Mock the fee function to NOT increase
// feerate on the first round.
@ -1087,7 +1087,7 @@ func TestCreateAnPublishFail(t *testing.T) {
// Mock the testmempoolaccept to return a fee related error that should
// be ignored.
m.wallet.On("CheckMempoolAcceptance",
mock.Anything).Return(rpcclient.ErrInsufficientFee).Once()
mock.Anything).Return(chain.ErrInsufficientFee).Once()
// Call the createAndPublish method and expect a none option.
resultOpt = tp.createAndPublishTx(requestID, record)