Merge pull request #8554 from yyforyongyu/use-new-errors

lnwallet: use new errors returned from `rpcclient`
This commit is contained in:
Oliver Gugger authored and GitHub committed 2024-03-21 01:42:57 -06:00
commit 15c7686830
7 files changed
+77 -79

No files matched your search

+38 -41
View File
@@ -29,7 +29,6 @@ import (
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnutils"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
@@ -1191,6 +1190,32 @@ func (b *BtcWallet) ListUnspentWitness(minConfs, maxConfs int32,
return witnessOutputs, nil
}
// mapRpcclientError maps an error from the rpcclient package to defined error
// in this package.
//
// NOTE: we are mapping the errors returned from `sendrawtransaction` RPC or
// the reject reason from `testmempoolaccept` RPC.
func mapRpcclientError(err error) error {
// If we failed to publish the transaction, check whether we got an
// error of known type.
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):
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):
return fmt.Errorf("%w: %v", lnwallet.ErrMempoolFee, err.Error())
}
return err
}
// PublishTransaction performs cursory validation (dust checks, etc), then
// finally broadcasts the passed transaction to the Bitcoin network. If
// publishing the transaction fails, an error describing the reason is returned
@@ -1198,40 +1223,12 @@ func (b *BtcWallet) ListUnspentWitness(minConfs, maxConfs int32,
// already published to the network (either in the mempool or chain) no error
// will be returned.
func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
// handleErr is a helper closure that handles the error from
// PublishTransaction and TestMempoolAccept.
handleErr := func(err error) error {
// If we failed to publish the transaction, check whether we
// got an error of known type.
switch {
// If the wallet reports a double spend, convert it to our
// internal ErrDoubleSpend and return.
case lnutils.ErrorAs[*base.ErrDoubleSpend](err):
return lnwallet.ErrDoubleSpend
// If the wallet reports a replacement error, return
// ErrDoubleSpend, as we currently are never attempting to
// replace transactions.
case lnutils.ErrorAs[*base.ErrReplacement](err):
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 lnutils.ErrorAs[*base.ErrMempoolFee](err):
return fmt.Errorf("%w: %v", lnwallet.ErrMempoolFee,
err.Error())
}
return err
}
// For neutrino backend there's no mempool, so we return early by
// publishing the transaction.
if b.chain.BackEnd() == "neutrino" {
err := b.wallet.PublishTransaction(tx, label)
return handleErr(err)
return mapRpcclientError(err)
}
// For non-neutrino nodes, we will first check whether the transaction
@@ -1250,7 +1247,7 @@ func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
err := b.wallet.PublishTransaction(tx, label)
return handleErr(err)
return mapRpcclientError(err)
}
return err
@@ -1269,7 +1266,7 @@ func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
if result.Allowed {
err = b.wallet.PublishTransaction(tx, label)
return handleErr(err)
return mapRpcclientError(err)
}
// If the check failed, there's no need to publish it. We'll handle the
@@ -1279,7 +1276,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 = base.MapBroadcastBackendError(errors.New(result.RejectReason))
err = rpcclient.MapRPCErr(errors.New(result.RejectReason))
//nolint:lll
// These two errors are ignored inside `PublishTransaction`:
@@ -1288,24 +1285,24 @@ func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx, label string) error {
// returned from TestMempoolAccept.
//
// TODO(yy): since `LightningWallet.PublishTransaction` always publish
// the same tx twice, we'd always get ErrInMempool. We should instead
// create a new rebroadcaster that monitors the mempool, and only
// rebroadcast when the tx is evicted. This way we don't need to
// the same tx twice, we'd always get ErrTxAlreadyInMempool. We should
// instead create a new rebroadcaster that monitors the mempool, and
// only rebroadcast when the tx is evicted. This way we don't need to
// broadcast twice, and can instead return these errors here.
switch {
// NOTE: In addition to ignoring these errors, we need to call
// `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 lnutils.ErrorAs[*base.ErrInMempool](err),
lnutils.ErrorAs[*base.ErrAlreadyConfirmed](err):
case errors.Is(err, rpcclient.ErrTxAlreadyInMempool),
errors.Is(err, rpcclient.ErrTxAlreadyKnown),
errors.Is(err, rpcclient.ErrTxAlreadyConfirmed):
err := b.wallet.PublishTransaction(tx, label)
return handleErr(err)
return mapRpcclientError(err)
}
return handleErr(err)
return mapRpcclientError(err)
}
// LabelTransaction adds a label to a transaction. If the tx already
+15 -17
View File
@@ -1788,8 +1788,7 @@ func testPublishTransaction(r *rpctest.Harness,
require.NoError(t, err, "unable to obtain public key")
// Create a new transaction that spends the output from
// tx3, and that pays to a different address. We expect
// this to be rejected because it is a double spend.
// tx3, and that pays to a different address.
tx5, err := txFromOutput(
tx3, alice.Cfg.Signer, keyDesc.PubKey,
keyDesc2.PubKey, txFee, rbf,
@@ -1797,7 +1796,19 @@ func testPublishTransaction(r *rpctest.Harness,
require.NoError(t, err)
err = alice.PublishTransaction(tx5, labels.External)
require.ErrorIs(t, err, lnwallet.ErrDoubleSpend)
// If RBF is not enabled, we expect this to be rejected
// because it is a double spend.
expectedErr := lnwallet.ErrDoubleSpend
// If RBF is enabled, we expect it to be rejected
// because it doesn't pay enough fees.
if rbf {
expectedErr = rpcclient.ErrInsufficientFee
}
// Assert the expected error.
require.ErrorIsf(t, err, expectedErr, "has rbf=%v", rbf)
// Create another transaction that spends the same
// output, but has a higher fee. We expect also this tx
@@ -1875,21 +1886,8 @@ func testPublishTransaction(r *rpctest.Harness,
// Now broadcast the transaction, we should get an error that
// the weight is too large.
//
// TODO(roasbeef): we can't use Unwrap() here as TxRuleError
// doesn't define it
err := alice.PublishTransaction(testTx, labels.External)
errStr := "bad-txns-oversize"
// For neutrino backend, the error string in not mapped.
//
// TODO(yy): unify error matching in neutrino too.
if alice.BackEnd() == "neutrino" {
errStr = "serialized transaction is too big"
}
require.Contains(t, err.Error(), errStr)
require.ErrorIs(t, err, rpcclient.ErrOversizeTx)
})
}