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:
1 parent
1dfb5a0c20
commit
6c2e8b9a00
3 files changed
+68
-16
No files matched your search
+44
-15
@@ -84,6 +84,11 @@ const (
|
|||||||
// TxConfirmed is sent when the tx is confirmed.
|
// TxConfirmed is sent when the tx is confirmed.
|
||||||
TxConfirmed
|
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 is used to check if an event is unknown.
|
||||||
sentinalEvent
|
sentinalEvent
|
||||||
)
|
)
|
||||||
@@ -99,6 +104,8 @@ func (e BumpEvent) String() string {
|
|||||||
return "Replaced"
|
return "Replaced"
|
||||||
case TxConfirmed:
|
case TxConfirmed:
|
||||||
return "Confirmed"
|
return "Confirmed"
|
||||||
|
case TxFatal:
|
||||||
|
return "Fatal"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
@@ -246,10 +253,20 @@ type BumpResult struct {
|
|||||||
requestID uint64
|
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.
|
// Validate validates the BumpResult so it's safe to use.
|
||||||
func (b *BumpResult) Validate() error {
|
func (b *BumpResult) Validate() error {
|
||||||
// Every result must have a tx.
|
// Every result must have a tx except the fatal or failed case.
|
||||||
if b.Tx == nil {
|
if b.Tx == nil && b.Event != TxFatal {
|
||||||
return fmt.Errorf("%w: nil tx", ErrInvalidBumpResult)
|
return fmt.Errorf("%w: nil tx", ErrInvalidBumpResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,9 +280,11 @@ func (b *BumpResult) Validate() error {
|
|||||||
return fmt.Errorf("%w: nil replacing tx", ErrInvalidBumpResult)
|
return fmt.Errorf("%w: nil replacing tx", ErrInvalidBumpResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a failed event, it must have an error.
|
// If it's a failed or fatal event, it must have an error.
|
||||||
if b.Event == TxFailed && b.Err == nil {
|
if b.Event == TxFatal || b.Event == TxFailed {
|
||||||
return fmt.Errorf("%w: nil error", ErrInvalidBumpResult)
|
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 it's a confirmed event, it must have a fee rate and fee.
|
||||||
@@ -659,8 +678,7 @@ func (t *TxPublisher) notifyResult(result *BumpResult) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Sending result for requestID=%v, tx=%v", id,
|
log.Debugf("Sending result %v for requestID=%v", result, id)
|
||||||
result.Tx.TxHash())
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
// Send the result to the subscriber.
|
// Send the result to the subscriber.
|
||||||
@@ -678,20 +696,31 @@ func (t *TxPublisher) notifyResult(result *BumpResult) {
|
|||||||
func (t *TxPublisher) removeResult(result *BumpResult) {
|
func (t *TxPublisher) removeResult(result *BumpResult) {
|
||||||
id := result.requestID
|
id := result.requestID
|
||||||
|
|
||||||
// Remove the record from the maps if there's an error. This means this
|
var txid chainhash.Hash
|
||||||
// tx has failed its broadcast and cannot be retried. There are two
|
if result.Tx != nil {
|
||||||
// cases,
|
txid = result.Tx.TxHash()
|
||||||
// - when the budget cannot cover the fee.
|
}
|
||||||
// - when a non-RBF related error occurs.
|
|
||||||
|
// 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 {
|
switch result.Event {
|
||||||
case TxFailed:
|
case TxFailed:
|
||||||
log.Errorf("Removing monitor record=%v, tx=%v, due to err: %v",
|
log.Errorf("Removing monitor record=%v, tx=%v, due to err: %v",
|
||||||
id, result.Tx.TxHash(), result.Err)
|
id, txid, result.Err)
|
||||||
|
|
||||||
case TxConfirmed:
|
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,
|
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.
|
// Do nothing if it's neither failed or confirmed.
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -91,6 +91,19 @@ func TestBumpResultValidate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.ErrorIs(t, b.Validate(), ErrInvalidBumpResult)
|
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.
|
// A confirmed event without fee info will give an error.
|
||||||
b = BumpResult{
|
b = BumpResult{
|
||||||
Tx: &wire.MsgTx{},
|
Tx: &wire.MsgTx{},
|
||||||
@@ -104,6 +117,13 @@ func TestBumpResultValidate(t *testing.T) {
|
|||||||
Event: TxPublished,
|
Event: TxPublished,
|
||||||
}
|
}
|
||||||
require.NoError(t, b.Validate())
|
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
|
// TestCalcSweepTxWeight checks that the weight of the sweep tx is calculated
|
||||||
|
|||||||
+4
-1
@@ -1729,7 +1729,7 @@ func (s *UtxoSweeper) handleBumpEventTxPublished(r *BumpResult) error {
|
|||||||
// NOTE: TxConfirmed event is not handled, since we already subscribe to the
|
// NOTE: TxConfirmed event is not handled, since we already subscribe to the
|
||||||
// input's spending event, we don't need to do anything here.
|
// input's spending event, we don't need to do anything here.
|
||||||
func (s *UtxoSweeper) handleBumpEvent(r *BumpResult) error {
|
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 {
|
switch r.Event {
|
||||||
// The tx has been published, we update the inputs' state and create a
|
// 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.
|
// with the new one.
|
||||||
case TxReplaced:
|
case TxReplaced:
|
||||||
return s.handleBumpEventTxReplaced(r)
|
return s.handleBumpEventTxReplaced(r)
|
||||||
|
|
||||||
|
case TxFatal:
|
||||||
|
// TODO(yy): create a method to remove this input.
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in new issue
Block a user