Skip to content

Commit

Permalink
fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianElvis committed Nov 14, 2024
1 parent d10dd40 commit 540d59f
Show file tree
Hide file tree
Showing 107 changed files with 31,177 additions and 0 deletions.
500 changes: 500 additions & 0 deletions proto/babylon/finality/zoneconcierge/README.md

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions proto/babylon/finality/zoneconcierge/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package zoneconcierge

import (
"context"
"time"

"github.com/babylonlabs-io/babylon/x/zoneconcierge/keeper"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/telemetry"
)

// BeginBlocker sends a pending packet for every channel upon each new block,
// so that the relayer is kept awake to relay headers
func BeginBlocker(ctx context.Context, k keeper.Keeper) error {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
return nil
}

func EndBlocker(ctx context.Context, k keeper.Keeper) ([]abci.ValidatorUpdate, error) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)

k.BroadcastBTCStakingConsumerEvents(ctx)
return []abci.ValidatorUpdate{}, nil
}
105 changes: 105 additions & 0 deletions proto/babylon/finality/zoneconcierge/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package cli

import (
"fmt"
"strconv"

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"

"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
)

// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(queryRoute string) *cobra.Command {
// Group zoneconcierge queries under a subcommand
cmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmd.AddCommand(CmdChainsInfo())
cmd.AddCommand(CmdFinalizedChainsInfo())
cmd.AddCommand(CmdEpochChainsInfoInfo())
return cmd
}

func CmdChainsInfo() *cobra.Command {
cmd := &cobra.Command{
Use: "chains-info <consumer-ids>",
Short: "retrieve the latest info for a given list of consumers",
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
queryClient := types.NewQueryClient(clientCtx)
req := types.QueryChainsInfoRequest{ConsumerIds: args}
resp, err := queryClient.ChainsInfo(cmd.Context(), &req)
if err != nil {
return err
}

return clientCtx.PrintProto(resp)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}

func CmdFinalizedChainsInfo() *cobra.Command {
cmd := &cobra.Command{
Use: "finalized-chains-info <consumer-ids>",
Short: "retrieve the finalized info for a given list of consumers",
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
prove, _ := cmd.Flags().GetBool("prove")

clientCtx := client.GetClientContextFromCmd(cmd)
queryClient := types.NewQueryClient(clientCtx)
req := types.QueryFinalizedChainsInfoRequest{ConsumerIds: args, Prove: prove}
resp, err := queryClient.FinalizedChainsInfo(cmd.Context(), &req)
if err != nil {
return err
}

return clientCtx.PrintProto(resp)
},
}

cmd.Flags().Bool("prove", false, "whether to retrieve proofs for each FinalizedChainInfo")
flags.AddQueryFlagsToCmd(cmd)

return cmd
}

func CmdEpochChainsInfoInfo() *cobra.Command {
cmd := &cobra.Command{
Use: "epoch-chains-info <epoch-num> <consumer-ids>",
Short: "retrieve the latest info for a list of consumers in a given epoch",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
queryClient := types.NewQueryClient(clientCtx)

epoch, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
req := types.QueryEpochChainsInfoRequest{EpochNum: epoch, ConsumerIds: args[1:]}
resp, err := queryClient.EpochChainsInfo(cmd.Context(), &req)
if err != nil {
return err
}

return clientCtx.PrintProto(resp)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
23 changes: 23 additions & 0 deletions proto/babylon/finality/zoneconcierge/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cli

import (
"fmt"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
// "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
)

// GetTxCmd returns the transaction commands for this module
func GetTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

return cmd
}
37 changes: 37 additions & 0 deletions proto/babylon/finality/zoneconcierge/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package zoneconcierge

import (
"context"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/keeper"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// InitGenesis initializes the module's state from a provided genesis state.
func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisState) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
// set params for this module
if err := k.SetParams(ctx, genState.Params); err != nil {
panic(err)
}

k.SetPort(ctx, genState.PortId)
// Only try to bind to port if it is not already bound, since we may already own
// port capability from capability InitGenesis
if !k.IsBound(sdkCtx, genState.PortId) {
// module binds to the port on InitChain
// and claims the returned capability
err := k.BindPort(sdkCtx, genState.PortId)
if err != nil {
panic("could not claim port capability: " + err.Error())
}
}
}

// ExportGenesis returns the module's exported genesis
func ExportGenesis(ctx context.Context, k keeper.Keeper) *types.GenesisState {
genesis := types.DefaultGenesis()
genesis.Params = k.GetParams(ctx)
genesis.PortId = k.GetPort(ctx)
return genesis
}
29 changes: 29 additions & 0 deletions proto/babylon/finality/zoneconcierge/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package zoneconcierge_test

import (
"testing"

keepertest "github.com/babylonlabs-io/babylon/testutil/keeper"
"github.com/babylonlabs-io/babylon/testutil/nullify"
"github.com/babylonlabs-io/babylon/x/zoneconcierge"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
"github.com/stretchr/testify/require"
)

func TestGenesis(t *testing.T) {
genesisState := types.GenesisState{
PortId: types.PortID,
Params: types.Params{IbcPacketTimeoutSeconds: 100},
}

k, ctx := keepertest.ZoneConciergeKeeper(t, nil, nil, nil, nil, nil, nil)
zoneconcierge.InitGenesis(ctx, *k, genesisState)
got := zoneconcierge.ExportGenesis(ctx, *k)
require.NotNil(t, got)

nullify.Fill(&genesisState)
nullify.Fill(got)

require.Equal(t, genesisState.PortId, got.PortId)
require.Equal(t, genesisState.Params, got.Params)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package keeper

import (
"context"
"fmt"

"github.com/cosmos/cosmos-sdk/runtime"

sdkerrors "cosmossdk.io/errors"
"cosmossdk.io/store/prefix"
"github.com/babylonlabs-io/babylon/x/zoneconcierge/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// FindClosestHeader finds the IndexedHeader that is closest to (but not after) the given height
func (k Keeper) FindClosestHeader(ctx context.Context, consumerID string, height uint64) (*types.IndexedHeader, error) {
chainInfo, err := k.GetChainInfo(ctx, consumerID)
if err != nil {
return nil, fmt.Errorf("failed to get chain info for chain with ID %s: %w", consumerID, err)
}

// if the given height is no lower than the latest header, return the latest header directly
if chainInfo.LatestHeader.Height <= height {
return chainInfo.LatestHeader, nil
}

// the requested height is lower than the latest header, trace back until finding a timestamped header
store := k.canonicalChainStore(ctx, consumerID)
heightBytes := sdk.Uint64ToBigEndian(height)
iter := store.ReverseIterator(nil, heightBytes)
defer iter.Close()
// if there is no key within range [0, height], return error
if !iter.Valid() {
return nil, fmt.Errorf("chain with ID %s does not have a timestamped header before height %d", consumerID, height)
}
// find the header in bytes, decode and return
headerBytes := iter.Value()
var header types.IndexedHeader
k.cdc.MustUnmarshal(headerBytes, &header)
return &header, nil
}

func (k Keeper) GetHeader(ctx context.Context, consumerID string, height uint64) (*types.IndexedHeader, error) {
store := k.canonicalChainStore(ctx, consumerID)
heightBytes := sdk.Uint64ToBigEndian(height)
if !store.Has(heightBytes) {
return nil, types.ErrHeaderNotFound
}
headerBytes := store.Get(heightBytes)
var header types.IndexedHeader
k.cdc.MustUnmarshal(headerBytes, &header)
return &header, nil
}

func (k Keeper) insertHeader(ctx context.Context, consumerID string, header *types.IndexedHeader) error {
if header == nil {
return sdkerrors.Wrapf(types.ErrInvalidHeader, "header is nil")
}
// NOTE: we can accept header without ancestor since IBC connection can be established at any height
store := k.canonicalChainStore(ctx, consumerID)
store.Set(sdk.Uint64ToBigEndian(header.Height), k.cdc.MustMarshal(header))
return nil
}

// canonicalChainStore stores the canonical chain of a CZ, formed as a list of IndexedHeader
// prefix: CanonicalChainKey || consumerID
// key: height
// value: IndexedHeader
func (k Keeper) canonicalChainStore(ctx context.Context, consumerID string) prefix.Store {
storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
canonicalChainStore := prefix.NewStore(storeAdapter, types.CanonicalChainKey)
consumerIDBytes := []byte(consumerID)
return prefix.NewStore(canonicalChainStore, consumerIDBytes)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package keeper_test

import (
"math/rand"
"testing"

"github.com/babylonlabs-io/babylon/app"
"github.com/babylonlabs-io/babylon/testutil/datagen"
"github.com/stretchr/testify/require"
)

func FuzzCanonicalChainIndexer(f *testing.F) {
datagen.AddRandomSeedsToFuzzer(f, 10)

f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(seed))

babylonApp := app.Setup(t, false)
zcKeeper := babylonApp.ZoneConciergeKeeper
ctx := babylonApp.NewContext(false)
czConsumerId := "test-consumerid"

// simulate a random number of blocks
numHeaders := datagen.RandomInt(r, 100) + 1
headers := SimulateNewHeaders(ctx, r, &zcKeeper, czConsumerId, 0, numHeaders)

// check if the canonical chain index is correct or not
for i := uint64(0); i < numHeaders; i++ {
header, err := zcKeeper.GetHeader(ctx, czConsumerId, i)
require.NoError(t, err)
require.NotNil(t, header)
require.Equal(t, czConsumerId, header.ConsumerId)
require.Equal(t, i, header.Height)
require.Equal(t, headers[i].Header.AppHash, header.Hash)
}

// check if the chain info is updated or not
chainInfo, err := zcKeeper.GetChainInfo(ctx, czConsumerId)
require.NoError(t, err)
require.NotNil(t, chainInfo.LatestHeader)
require.Equal(t, czConsumerId, chainInfo.LatestHeader.ConsumerId)
require.Equal(t, numHeaders-1, chainInfo.LatestHeader.Height)
require.Equal(t, headers[numHeaders-1].Header.AppHash, chainInfo.LatestHeader.Hash)
})
}

func FuzzFindClosestHeader(f *testing.F) {
datagen.AddRandomSeedsToFuzzer(f, 10)

f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(seed))

babylonApp := app.Setup(t, false)
zcKeeper := babylonApp.ZoneConciergeKeeper
ctx := babylonApp.NewContext(false)
czConsumerId := "test-consumerid"

// no header at the moment, FindClosestHeader invocation should give error
_, err := zcKeeper.FindClosestHeader(ctx, czConsumerId, 100)
require.Error(t, err)

// simulate a random number of blocks
numHeaders := datagen.RandomInt(r, 100) + 1
headers := SimulateNewHeaders(ctx, r, &zcKeeper, czConsumerId, 0, numHeaders)

header, err := zcKeeper.FindClosestHeader(ctx, czConsumerId, numHeaders)
require.NoError(t, err)
require.Equal(t, headers[len(headers)-1].Header.AppHash, header.Hash)

// skip a non-zero number of headers in between, in order to create a gap of non-timestamped headers
gap := datagen.RandomInt(r, 10) + 1

// simulate a random number of blocks
// where the new batch of headers has a gap with the previous batch
SimulateNewHeaders(ctx, r, &zcKeeper, czConsumerId, numHeaders+gap+1, numHeaders)

// get a random height that is in this gap
randomHeightInGap := datagen.RandomInt(r, int(gap+1)) + numHeaders
// find the closest header with the given randomHeightInGap
header, err = zcKeeper.FindClosestHeader(ctx, czConsumerId, randomHeightInGap)
require.NoError(t, err)
// the header should be the same as the last header in the last batch
require.Equal(t, headers[len(headers)-1].Header.AppHash, header.Hash)
})
}
Loading

0 comments on commit 540d59f

Please sign in to comment.