Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
gusin13 committed Nov 20, 2024
1 parent bdf2cec commit e044772
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 28 deletions.
4 changes: 0 additions & 4 deletions internal/services/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,5 @@ func (s *Service) processSlashedFinalityProviderEvent(
)
}

// TODO: babylon needs to emit slashing tx
// so indexer can start watching for slashing spend
// to identify if staker has withdrawn after slashing

return nil
}
80 changes: 63 additions & 17 deletions internal/services/watch_btc_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,49 @@ func (s *Service) watchForSpendUnbondingTx(
case <-quitCtx.Done():
return
}
}

func (s *Service) watchForSpendSlashingChange(
spendEvent *notifier.SpendEvent,
delegation *model.BTCDelegationDetails,
) {
defer s.wg.Done()
quitCtx, cancel := s.quitContext()
defer cancel()

select {
case spendDetail := <-spendEvent.Spend:
log.Info().
Str("delegation", delegation.StakingTxHashHex).
Str("spending_tx", spendDetail.SpendingTx.TxHash().String()).
Msg("slashing change output has been spent")
delegationState, err := s.db.GetBTCDelegationState(quitCtx, delegation.StakingTxHashHex)
if err != nil {
log.Error().Err(err).Msg("failed to get delegation state")
return
}

qualifiedStates := types.QualifiedStatesForSlashedWithdrawn()
if qualifiedStates == nil || !utils.Contains(qualifiedStates, *delegationState) {
log.Error().Msgf("current state %s is not qualified for slashed withdrawn", *delegationState)
return
}

// Update to withdrawn state
if err := s.db.UpdateBTCDelegationState(
quitCtx,
delegation.StakingTxHashHex,
types.StateSlashedWithdrawn,
); err != nil {
log.Error().Err(err).Msg("failed to update delegation state")
return
}

case <-s.quit:
return
case <-quitCtx.Done():
return
}
}

func (s *Service) handleSpendingStakingTransaction(
Expand Down Expand Up @@ -119,8 +161,8 @@ func (s *Service) handleSpendingStakingTransaction(
return fmt.Errorf("failed to validate slashing tx: %w", err)
}

// It's a valid slashing tx, handle accordingly
return s.handleSlashing(ctx, delegation)
// It's a valid slashing tx, watch for the change output
return s.startWatchingSlashingChange(ctx, tx, delegation)
}

func (s *Service) handleSpendingUnbondingTransaction(
Expand Down Expand Up @@ -155,8 +197,8 @@ func (s *Service) handleSpendingUnbondingTransaction(
return fmt.Errorf("failed to validate slashing tx: %w", err)
}

// It's a valid slashing tx, handle accordingly
return s.handleSlashing(ctx, delegation)
// It's a valid slashing tx, watch for the change output
return s.startWatchingSlashingChange(ctx, tx, delegation)
}

func (s *Service) handleWithdrawal(ctx context.Context, delegation *model.BTCDelegationDetails) error {
Expand All @@ -178,23 +220,27 @@ func (s *Service) handleWithdrawal(ctx context.Context, delegation *model.BTCDel
)
}

func (s *Service) handleSlashing(ctx context.Context, delegation *model.BTCDelegationDetails) error {
delegationState, err := s.db.GetBTCDelegationState(ctx, delegation.StakingTxHashHex)
if err != nil {
return fmt.Errorf("failed to get delegation state: %w", err)
func (s *Service) startWatchingSlashingChange(ctx context.Context, slashingTx *wire.MsgTx, delegation *model.BTCDelegationDetails) error {
// Create outpoint for the change output (index 1)
changeOutpoint := wire.OutPoint{
Hash: slashingTx.TxHash(),
Index: 1, // Change output is always second
}

qualifiedStates := types.QualifiedStatesForSlashed()
if qualifiedStates == nil || !utils.Contains(qualifiedStates, *delegationState) {
return fmt.Errorf("current state %s is not qualified for slashing", *delegationState)
// Register spend notification for the change output
spendEv, err := s.btcNotifier.RegisterSpendNtfn(
&changeOutpoint,
slashingTx.TxOut[1].PkScript, // Script of change output
delegation.StartHeight,
)
if err != nil {
return fmt.Errorf("failed to register spend ntfn for slashing change output: %w", err)
}

// Update to slashed state
return s.db.UpdateBTCDelegationState(
ctx,
delegation.StakingTxHashHex,
types.StateSlashed,
)
s.wg.Add(1)
go s.watchForSpendSlashingChange(spendEv, delegation)

return nil
}

// IsValidUnbondingTx tries to identify a tx is a valid unbonding tx
Expand Down
20 changes: 13 additions & 7 deletions internal/types/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import bbntypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
type DelegationState string

const (
StatePending DelegationState = "PENDING"
StateVerified DelegationState = "VERIFIED"
StateActive DelegationState = "ACTIVE"
StateUnbonding DelegationState = "UNBONDING"
StateWithdrawable DelegationState = "WITHDRAWABLE"
StateWithdrawn DelegationState = "WITHDRAWN"
StateSlashed DelegationState = "SLASHED"
StatePending DelegationState = "PENDING"
StateVerified DelegationState = "VERIFIED"
StateActive DelegationState = "ACTIVE"
StateUnbonding DelegationState = "UNBONDING"
StateWithdrawable DelegationState = "WITHDRAWABLE"
StateWithdrawn DelegationState = "WITHDRAWN"
StateSlashed DelegationState = "SLASHED"
StateSlashedWithdrawn DelegationState = "SLASHED_WITHDRAWN"
)

func (s DelegationState) String() string {
Expand Down Expand Up @@ -65,3 +66,8 @@ func QualifiedStatesForWithdrawable() []DelegationState {
func QualifiedStatesForSlashed() []DelegationState {
return []DelegationState{StateActive, StateUnbonding}
}

// QualifiedStatesForSlashedWithdrawn returns the qualified current states for SlashedWithdrawn event
func QualifiedStatesForSlashedWithdrawn() []DelegationState {
return []DelegationState{StateSlashed}
}

0 comments on commit e044772

Please sign in to comment.