sweep: add new state TxFatal for erroneous sweepings

Also updated the loggings. This new state will be used in the following
commit.
This commit is contained in:
yyforyongyu authored and yyforyongyu committed 2024-12-20 17:53:58 +08:00
1 parent 1dfb5a0c20
commit 6c2e8b9a00
3 files changed
+67 -15

No files matched your search

+43 -14
View File
@@ -84,6 +84,11 @@ const (
// TxConfirmed is sent when the tx is confirmed.
TxConfirmed
// TxFatal is sent when the inputs in this tx cannot be retried. Txns
// will end up in this state if they have encountered a non-fee related
// error, which means they cannot be retried with increased budget.
TxFatal
// sentinalEvent is used to check if an event is unknown.
sentinalEvent
)
@@ -99,6 +104,8 @@ func (e BumpEvent) String() string {
return "Replaced"
case TxConfirmed:
return "Confirmed"
case TxFatal:
return "Fatal"
default:
return "Unknown"
}
@@ -246,10 +253,20 @@ type BumpResult struct {
requestID uint64
}
// String returns a human-readable string for the result.
func (b *BumpResult) String() string {
desc := fmt.Sprintf("Event=%v", b.Event)
if b.Tx != nil {
desc += fmt.Sprintf(", Tx=%v", b.Tx.TxHash())
}
return fmt.Sprintf("[%s]", desc)
}
// Validate validates the BumpResult so it's safe to use.
func (b *BumpResult) Validate() error {
// Every result must have a tx.
if b.Tx == nil {
// Every result must have a tx except the fatal or failed case.
if b.Tx == nil && b.Event != TxFatal {
return fmt.Errorf("%w: nil tx", ErrInvalidBumpResult)
}
@@ -263,10 +280,12 @@ func (b *BumpResult) Validate() error {
return fmt.Errorf("%w: nil replacing tx", ErrInvalidBumpResult)
}
// If it's a failed event, it must have an error.
if b.Event == TxFailed && b.Err == nil {
// If it's a failed or fatal event, it must have an error.
if b.Event == TxFatal || b.Event == TxFailed {
if b.Err == nil {
return fmt.Errorf("%w: nil error", ErrInvalidBumpResult)
}
}
// If it's a confirmed event, it must have a fee rate and fee.
if b.Event == TxConfirmed && (b.FeeRate == 0 || b.Fee == 0) {
@@ -659,8 +678,7 @@ func (t *TxPublisher) notifyResult(result *BumpResult) {
return
}
log.Debugf("Sending result for requestID=%v, tx=%v", id,
result.Tx.TxHash())
log.Debugf("Sending result %v for requestID=%v", result, id)
select {
// Send the result to the subscriber.
@@ -678,20 +696,31 @@ func (t *TxPublisher) notifyResult(result *BumpResult) {
func (t *TxPublisher) removeResult(result *BumpResult) {
id := result.requestID
// Remove the record from the maps if there's an error. This means this
// tx has failed its broadcast and cannot be retried. There are two
// cases,
// - when the budget cannot cover the fee.
// - when a non-RBF related error occurs.
var txid chainhash.Hash
if result.Tx != nil {
txid = result.Tx.TxHash()
}
// Remove the record from the maps if there's an error or the tx is
// confirmed. When there's an error, it means this tx has failed its
// broadcast and cannot be retried. There are two cases it may fail,
// - when the budget cannot cover the increased fee calculated by the
// fee function, hence the budget is used up.
// - when a non-fee related error returned from PublishTransaction.
switch result.Event {
case TxFailed:
log.Errorf("Removing monitor record=%v, tx=%v, due to err: %v",
id, result.Tx.TxHash(), result.Err)
id, txid, result.Err)
case TxConfirmed:
// Remove the record is the tx is confirmed.
// Remove the record if the tx is confirmed.
log.Debugf("Removing confirmed monitor record=%v, tx=%v", id,
result.Tx.TxHash())
txid)
case TxFatal:
// Remove the record if there's an error.
log.Debugf("Removing monitor record=%v due to fatal err: %v",
id, result.Err)
// Do nothing if it's neither failed or confirmed.
default:
+20
View File
@@ -91,6 +91,19 @@ func TestBumpResultValidate(t *testing.T) {
}
require.ErrorIs(t, b.Validate(), ErrInvalidBumpResult)
// A failed event without a tx will give an error.
b = BumpResult{
Event: TxFailed,
Err: errDummy,
}
require.ErrorIs(t, b.Validate(), ErrInvalidBumpResult)
// A fatal event without a failure reason will give an error.
b = BumpResult{
Event: TxFailed,
}
require.ErrorIs(t, b.Validate(), ErrInvalidBumpResult)
// A confirmed event without fee info will give an error.
b = BumpResult{
Tx: &wire.MsgTx{},
@@ -104,6 +117,13 @@ func TestBumpResultValidate(t *testing.T) {
Event: TxPublished,
}
require.NoError(t, b.Validate())
// Tx is allowed to be nil in a TxFatal event.
b = BumpResult{
Event: TxFatal,
Err: errDummy,
}
require.NoError(t, b.Validate())
}
// TestCalcSweepTxWeight checks that the weight of the sweep tx is calculated
+4 -1
View File
@@ -1729,7 +1729,7 @@ func (s *UtxoSweeper) handleBumpEventTxPublished(r *BumpResult) error {
// NOTE: TxConfirmed event is not handled, since we already subscribe to the
// input's spending event, we don't need to do anything here.
func (s *UtxoSweeper) handleBumpEvent(r *BumpResult) error {
log.Debugf("Received bump event [%v] for tx %v", r.Event, r.Tx.TxHash())
log.Debugf("Received bump result %v", r)
switch r.Event {
// The tx has been published, we update the inputs' state and create a
@@ -1745,6 +1745,9 @@ func (s *UtxoSweeper) handleBumpEvent(r *BumpResult) error {
// with the new one.
case TxReplaced:
return s.handleBumpEventTxReplaced(r)
case TxFatal:
// TODO(yy): create a method to remove this input.
}
return nil