From e1aa8d8348018acbf0c03befb3a669368cd19ae2 Mon Sep 17 00:00:00 2001 From: Gurjot Date: Thu, 12 Sep 2024 13:03:13 -0400 Subject: [PATCH] notify consumers about slashed fp --- x/btcstaking/keeper/btc_delegators.go | 27 ++++++++++++++++ x/btcstaking/keeper/finality_providers.go | 32 +++++++++++++++++++ .../types/btc_staking_consumer_events.go | 12 +++++++ x/finality/keeper/msg_server.go | 5 +++ x/finality/types/expected_keepers.go | 1 + x/finality/types/mocked_keepers.go | 14 ++++++++ .../ibc_packet_btc_staking_consumer_event.go | 6 ++++ 7 files changed, 97 insertions(+) diff --git a/x/btcstaking/keeper/btc_delegators.go b/x/btcstaking/keeper/btc_delegators.go index 550a899fa..7030069d0 100644 --- a/x/btcstaking/keeper/btc_delegators.go +++ b/x/btcstaking/keeper/btc_delegators.go @@ -60,6 +60,33 @@ func (k Keeper) getBTCDelegatorDelegations(ctx context.Context, fpBTCPK *bbn.BIP return &types.BTCDelegatorDelegations{Dels: btcDels} } +func (k Keeper) getFPBTCDelegations(ctx context.Context, fpBTCPK *bbn.BIP340PubKey) ([]*types.BTCDelegation, error) { + store := k.btcDelegatorFpStore(ctx, fpBTCPK) + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + btcDels := make([]*types.BTCDelegation, 0) + for ; iterator.Valid(); iterator.Next() { + var btcDelIndex types.BTCDelegatorDelegationIndex + if err := btcDelIndex.Unmarshal(iterator.Value()); err != nil { + return nil, err + } + + for _, stakingTxHashBytes := range btcDelIndex.StakingTxHashList { + stakingTxHash, err := chainhash.NewHash(stakingTxHashBytes) + if err != nil { + return nil, err + } + btcDel := k.getBTCDelegation(ctx, *stakingTxHash) + if btcDel != nil { + btcDels = append(btcDels, btcDel) + } + } + } + + return btcDels, nil +} + // btcDelegatorFpStore returns the KVStore of the BTC delegators // prefix: BTCDelegatorKey || finality provider's Bitcoin secp256k1 PK // key: delegator's Bitcoin secp256k1 PK diff --git a/x/btcstaking/keeper/finality_providers.go b/x/btcstaking/keeper/finality_providers.go index f590ffc94..f6757e936 100644 --- a/x/btcstaking/keeper/finality_providers.go +++ b/x/btcstaking/keeper/finality_providers.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" + bbn "github.com/babylonlabs-io/babylon/types" "github.com/babylonlabs-io/babylon/x/btcstaking/types" ) @@ -67,6 +68,37 @@ func (k Keeper) SlashFinalityProvider(ctx context.Context, fpBTCPK []byte) error return nil } +func (k Keeper) NotifyConsumersOfSlashedFinalityProvider(ctx context.Context, fpBTCPK *bbn.BIP340PubKey) error { + // Get all delegations for this finality provider + delegations, err := k.getFPBTCDelegations(ctx, fpBTCPK) + if err != nil { + return err + } + + for _, delegation := range delegations { + // Create SlashedBTCDelegation event + consumerEvent, err := types.CreateSlashedBTCDelegationEvent(delegation) + if err != nil { + return err + } + + // Get consumer IDs of non-Babylon finality providers + restakedFPConsumerIDs, err := k.restakedFPConsumerIDs(ctx, delegation.FpBtcPkList) + if err != nil { + return err + } + + // Send event to each involved consumer chain + for _, consumerID := range restakedFPConsumerIDs { + if err := k.AddBTCStakingConsumerEvent(ctx, consumerID, consumerEvent); err != nil { + return err + } + } + } + + return nil +} + // RevertSluggishFinalityProvider sets the Sluggish flag of the given finality provider // to false func (k Keeper) RevertSluggishFinalityProvider(ctx context.Context, fpBTCPK []byte) error { diff --git a/x/btcstaking/types/btc_staking_consumer_events.go b/x/btcstaking/types/btc_staking_consumer_events.go index 05565f082..89e6922a8 100644 --- a/x/btcstaking/types/btc_staking_consumer_events.go +++ b/x/btcstaking/types/btc_staking_consumer_events.go @@ -99,3 +99,15 @@ func CreateUnbondedBTCDelegationEvent(unbondedDel *BTCDelegation) (*BTCStakingCo return event, nil } + +func CreateSlashedBTCDelegationEvent(slashedDel *BTCDelegation) (*BTCStakingConsumerEvent, error) { + event := &BTCStakingConsumerEvent{ + Event: &BTCStakingConsumerEvent_SlashedDel{ + SlashedDel: &SlashedBTCDelegation{ + StakingTxHash: slashedDel.MustGetStakingTxHash().String(), + }, + }, + } + + return event, nil +} diff --git a/x/finality/keeper/msg_server.go b/x/finality/keeper/msg_server.go index 2cb795f22..140e5feb8 100644 --- a/x/finality/keeper/msg_server.go +++ b/x/finality/keeper/msg_server.go @@ -246,6 +246,11 @@ func (k Keeper) slashFinalityProvider(ctx context.Context, fpBtcPk *bbn.BIP340Pu panic(fmt.Errorf("failed to slash finality provider: %v", err)) } + // Notify consumer chains about the slashed finality provider + if err := k.BTCStakingKeeper.NotifyConsumersOfSlashedFinalityProvider(ctx, fpBtcPk); err != nil { + panic(fmt.Errorf("failed to notify consumers of slashed finality provider: %w", err)) + } + // emit slashing event eventSlashing := types.NewEventSlashedFinalityProvider(evidence) if err := sdk.UnwrapSDKContext(ctx).EventManager().EmitTypedEvent(eventSlashing); err != nil { diff --git a/x/finality/types/expected_keepers.go b/x/finality/types/expected_keepers.go index f4d6e58d9..8d10ca881 100644 --- a/x/finality/types/expected_keepers.go +++ b/x/finality/types/expected_keepers.go @@ -12,6 +12,7 @@ type BTCStakingKeeper interface { GetFinalityProvider(ctx context.Context, fpBTCPK []byte) (*bstypes.FinalityProvider, error) HasFinalityProvider(ctx context.Context, fpBTCPK []byte) bool SlashFinalityProvider(ctx context.Context, fpBTCPK []byte) error + NotifyConsumersOfSlashedFinalityProvider(ctx context.Context, fpBTCPK *bbn.BIP340PubKey) error GetVotingPower(ctx context.Context, fpBTCPK []byte, height uint64) uint64 GetVotingPowerTable(ctx context.Context, height uint64) map[string]uint64 GetBTCStakingActivatedHeight(ctx context.Context) (uint64, error) diff --git a/x/finality/types/mocked_keepers.go b/x/finality/types/mocked_keepers.go index c546a68da..098c39451 100644 --- a/x/finality/types/mocked_keepers.go +++ b/x/finality/types/mocked_keepers.go @@ -151,6 +151,20 @@ func (mr *MockBTCStakingKeeperMockRecorder) HasFinalityProvider(ctx, fpBTCPK int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasFinalityProvider", reflect.TypeOf((*MockBTCStakingKeeper)(nil).HasFinalityProvider), ctx, fpBTCPK) } +// NotifyConsumersOfSlashedFinalityProvider mocks base method. +func (m *MockBTCStakingKeeper) NotifyConsumersOfSlashedFinalityProvider(ctx context.Context, fpBTCPK *types.BIP340PubKey) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NotifyConsumersOfSlashedFinalityProvider", ctx, fpBTCPK) + ret0, _ := ret[0].(error) + return ret0 +} + +// NotifyConsumersOfSlashedFinalityProvider indicates an expected call of NotifyConsumersOfSlashedFinalityProvider. +func (mr *MockBTCStakingKeeperMockRecorder) NotifyConsumersOfSlashedFinalityProvider(ctx, fpBTCPK interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotifyConsumersOfSlashedFinalityProvider", reflect.TypeOf((*MockBTCStakingKeeper)(nil).NotifyConsumersOfSlashedFinalityProvider), ctx, fpBTCPK) +} + // RemoveVotingPowerDistCache mocks base method. func (m *MockBTCStakingKeeper) RemoveVotingPowerDistCache(ctx context.Context, height uint64) { m.ctrl.T.Helper() diff --git a/x/zoneconcierge/keeper/ibc_packet_btc_staking_consumer_event.go b/x/zoneconcierge/keeper/ibc_packet_btc_staking_consumer_event.go index a822e701a..da72b2ddb 100644 --- a/x/zoneconcierge/keeper/ibc_packet_btc_staking_consumer_event.go +++ b/x/zoneconcierge/keeper/ibc_packet_btc_staking_consumer_event.go @@ -31,6 +31,12 @@ func (k Keeper) BroadcastBTCStakingConsumerEvents( continue } + // Log the IBC packet + k.Logger(sdkCtx).Info("BroadcastBTCStakingConsumerEvents: Preparing ZoneConcierge packet", + "consumerID", consumerID, + "packetType", "BtcStaking", + "packetContent", fmt.Sprintf("%+v", ibcPacket)) + // Prepare the packet for ZoneConcierge. zcPacket := &types.ZoneconciergePacketData{ Packet: &types.ZoneconciergePacketData_BtcStaking{