Skip to content

Commit

Permalink
feat: btclightclient: Add BTCHeaderInserted event (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitsalis authored Jul 28, 2022
1 parent f3efa57 commit 8f94c83
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 23 deletions.
7 changes: 7 additions & 0 deletions proto/babylon/btclightclient/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ message EventBTCRollBack {
message EventBTCRollForward {
BTCHeaderInfo header = 1;
}

// EventBTCHeaderInserted is emitted on Msg/InsertHeader
// The header included in the event is the one that was added to the
// on chain BTC storage.
message EventBTCHeaderInserted {
BTCHeaderInfo header = 1;
}
2 changes: 2 additions & 0 deletions x/btccheckpoint/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func (h Hooks) AfterBTCRollForward(ctx sdk.Context, headerInfo *ltypes.BTCHeader
h.k.OnTipChange(ctx)
}

func (h Hooks) AfterBTCHeaderInserted(ctx sdk.Context, headerInfo *ltypes.BTCHeaderInfo) {}

func (h Hooks) AfterEpochBegins(ctx sdk.Context, epoch uint64) {}

func (h Hooks) AfterEpochEnds(ctx sdk.Context, epoch uint64) {}
Expand Down
7 changes: 7 additions & 0 deletions x/btclightclient/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import (
// Implements BTCLightClientHooks interface
var _ types.BTCLightClientHooks = Keeper{}

// AfterBTCHeaderInserted - call hook if registered
func (k Keeper) AfterBTCHeaderInserted(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
if k.hooks != nil {
k.hooks.AfterBTCHeaderInserted(ctx, headerInfo)
}
}

// AfterBTCRollBack - call hook if registered
func (k Keeper) AfterBTCRollBack(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
if k.hooks != nil {
Expand Down
1 change: 1 addition & 0 deletions x/btclightclient/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func (k Keeper) InsertHeader(ctx sdk.Context, header *bbl.BTCHeaderBytes) error
// Variable maintaining the headers that have been added to the main chain
var addedToMainChain []*types.BTCHeaderInfo

k.triggerHeaderInserted(ctx, headerInfo)
// The tip has changed, we need to send events
if !currentTip.Eq(previousTip) {
if !currentTip.Eq(headerInfo) {
Expand Down
38 changes: 29 additions & 9 deletions x/btclightclient/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,23 @@ func FuzzKeeperInsertHeader(f *testing.F) {
// Get event names. Those will be useful to test the types of the emitted events
rollForwardName := proto.MessageName(&types.EventBTCRollForward{})
rollBackName := proto.MessageName(&types.EventBTCRollBack{})
headerInsertedName := proto.MessageName(&types.EventBTCHeaderInserted{})

// The headerInserted hook call should contain the new header
if len(mockHooks.AfterBTCHeaderInsertedStore) != 1 {
t.Fatalf("Expected a single BTCHeaderInserted hook to be invoked. Got %d", len(mockHooks.AfterBTCHeaderInsertedStore))
}
if !mockHooks.AfterBTCHeaderInsertedStore[0].Eq(header) {
t.Errorf("The headerInfo inside the BTCHeaderInserted hook is not the new header")
}
// Check that an event has been triggered for the new header
if len(ctx.EventManager().Events()) == 0 {
t.Fatalf("No events were triggered")
}
// The header creation event should have been the one that was first generated
if ctx.EventManager().Events()[0].Type != headerInsertedName {
t.Errorf("The first event does not have the BTCHeaderInserted type")
}

// If the new header builds on top of the tip
if oldTip.Eq(parentHeader) {
Expand All @@ -391,11 +408,13 @@ func FuzzKeeperInsertHeader(f *testing.F) {
if len(mockHooks.AfterBTCRollBackStore) != 0 {
t.Fatalf("Expected the BTCRollBack hook to not be invoked")
}
if len(ctx.EventManager().Events()) != 1 {
t.Fatalf("Only one event should have been invoked")
// 2 events because the first one is for the header creation
if len(ctx.EventManager().Events()) != 2 {
t.Fatalf("We expected only two events. One for header creation and one for rolling forward.")
}
if ctx.EventManager().Events()[0].Type != rollForwardName {
t.Errorf("The single event expected does not have the roll forward type")
// The second event should be the roll forward one
if ctx.EventManager().Events()[1].Type != rollForwardName {
t.Errorf("The second event does not have the roll forward type")
}
} else if oldTip.Work.GT(*header.Work) {
// If the tip has a greater work than the newly inserted header
Expand All @@ -411,8 +430,9 @@ func FuzzKeeperInsertHeader(f *testing.F) {
if len(mockHooks.AfterBTCRollBackStore) != 0 {
t.Fatalf("Expected the BTCRollBack hook to not be invoked")
}
if len(ctx.EventManager().Events()) != 0 {
t.Errorf("Events have been invoked when the tip wasn't updated")
// No other events other than BTCHeaderInserted should be invoked
if len(ctx.EventManager().Events()) != 1 {
t.Errorf("Extra events have been invoked when the tip wasn't updated")
}
} else {
// The tip has been updated. It should be towards the new header
Expand Down Expand Up @@ -445,9 +465,9 @@ func FuzzKeeperInsertHeader(f *testing.F) {

// Test the invoked events
invokedEvents := ctx.EventManager().Events()
// There should be a total of len(ancestry) + 1 events
if len(invokedEvents) != len(ancestry)+1 {
t.Errorf("More events than expected were invoked %d %d", len(invokedEvents), len(ancestry)+1)
// There should be a total of len(ancestry) + 2 events
if len(invokedEvents) != len(ancestry)+2 {
t.Errorf("More events than expected were invoked %d %d", len(invokedEvents), len(ancestry)+2)
}
// Only test that there is a certain number of rollForward and rollBack events
// Testing the attributes is a much more complex approach
Expand Down
7 changes: 7 additions & 0 deletions x/btclightclient/keeper/triggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func (k Keeper) triggerHeaderInserted(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
// Trigger AfterBTCHeaderInserted hook
k.AfterBTCHeaderInserted(ctx, headerInfo)
// Emit HeaderInserted event
ctx.EventManager().EmitTypedEvent(&types.EventBTCHeaderInserted{Header: headerInfo})
}

func (k Keeper) triggerRollBack(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
// Trigger AfterBTCRollBack hook
k.AfterBTCRollBack(ctx, headerInfo)
Expand Down
20 changes: 15 additions & 5 deletions x/btclightclient/keeper/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,34 @@ import (
var _ types.BTCLightClientHooks = &MockHooks{}

type MockHooks struct {
AfterBTCRollForwardStore []*types.BTCHeaderInfo
AfterBTCRollBackStore []*types.BTCHeaderInfo
AfterBTCRollForwardStore []*types.BTCHeaderInfo
AfterBTCRollBackStore []*types.BTCHeaderInfo
AfterBTCHeaderInsertedStore []*types.BTCHeaderInfo
}

func NewMockHooks() *MockHooks {
rollForwardStore := make([]*types.BTCHeaderInfo, 0)
rollBackwardStore := make([]*types.BTCHeaderInfo, 0)
return &MockHooks{AfterBTCRollForwardStore: rollForwardStore, AfterBTCRollBackStore: rollBackwardStore}
headerInsertedStore := make([]*types.BTCHeaderInfo, 0)
return &MockHooks{
AfterBTCRollForwardStore: rollForwardStore,
AfterBTCRollBackStore: rollBackwardStore,
AfterBTCHeaderInsertedStore: headerInsertedStore,
}
}

func (m *MockHooks) AfterBTCRollForward(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
func (m *MockHooks) AfterBTCRollForward(_ sdk.Context, headerInfo *types.BTCHeaderInfo) {
m.AfterBTCRollForwardStore = append(m.AfterBTCRollForwardStore, headerInfo)
}

func (m *MockHooks) AfterBTCRollBack(ctx sdk.Context, headerInfo *types.BTCHeaderInfo) {
func (m *MockHooks) AfterBTCRollBack(_ sdk.Context, headerInfo *types.BTCHeaderInfo) {
m.AfterBTCRollBackStore = append(m.AfterBTCRollBackStore, headerInfo)
}

func (m *MockHooks) AfterBTCHeaderInserted(_ sdk.Context, headerInfo *types.BTCHeaderInfo) {
m.AfterBTCHeaderInsertedStore = append(m.AfterBTCHeaderInsertedStore, headerInfo)
}

// Methods for generating trees

// genRandomTree generates a tree of headers. It accomplishes this by generating a root
Expand Down
Loading

0 comments on commit 8f94c83

Please sign in to comment.