Cosmos SDK Interview Questions - Medium

Medium-level Cosmos SDK interview questions covering advanced module development, SDK internals, and Ignite customization.

Q1: How do you implement custom state transitions and state machines in a module?

Answer:

State Machine Pattern:

 1package keeper
 2
 3import (
 4    sdk "github.com/cosmos/cosmos-sdk/types"
 5)
 6
 7// OrderState represents order state
 8type OrderState uint8
 9
10const (
11    OrderStatePending OrderState = iota
12    OrderStateConfirmed
13    OrderStateShipped
14    OrderStateDelivered
15    OrderStateCancelled
16)
17
18// Order represents an order
19type Order struct {
20    Id      uint64
21    State   OrderState
22    Buyer   sdk.AccAddress
23    Seller  sdk.AccAddress
24    Amount  sdk.Coins
25}
26
27// StateMachine manages order state transitions
28type StateMachine struct {
29    keeper Keeper
30}
31
32// Transition validates and executes state transition
33func (sm StateMachine) Transition(ctx sdk.Context, orderId uint64, newState OrderState) error {
34    order, found := sm.keeper.GetOrder(ctx, orderId)
35    if !found {
36        return sdkerrors.Wrap(types.ErrOrderNotFound, fmt.Sprintf("order %d not found", orderId))
37    }
38    
39    // Validate transition
40    if !sm.isValidTransition(order.State, newState) {
41        return sdkerrors.Wrap(
42            types.ErrInvalidStateTransition,
43            fmt.Sprintf("cannot transition from %d to %d", order.State, newState),
44        )
45    }
46    
47    // Execute transition
48    order.State = newState
49    sm.keeper.SetOrder(ctx, order)
50    
51    // Emit event
52    ctx.EventManager().EmitEvent(
53        sdk.NewEvent(
54            types.EventTypeOrderStateChanged,
55            sdk.NewAttribute(types.AttributeKeyOrderId, fmt.Sprintf("%d", orderId)),
56            sdk.NewAttribute(types.AttributeKeyOldState, fmt.Sprintf("%d", order.State)),
57            sdk.NewAttribute(types.AttributeKeyNewState, fmt.Sprintf("%d", newState)),
58        ),
59    )
60    
61    return nil
62}
63
64// isValidTransition checks if transition is allowed
65func (sm StateMachine) isValidTransition(current, next OrderState) bool {
66    transitions := map[OrderState][]OrderState{
67        OrderStatePending:   {OrderStateConfirmed, OrderStateCancelled},
68        OrderStateConfirmed: {OrderStateShipped, OrderStateCancelled},
69        OrderStateShipped:     {OrderStateDelivered},
70        OrderStateDelivered:  {},
71        OrderStateCancelled: {},
72    }
73    
74    allowed, exists := transitions[current]
75    if !exists {
76        return false
77    }
78    
79    for _, state := range allowed {
80        if state == next {
81            return true
82        }
83    }
84    
85    return false
86}

Usage:

1// In handler
2func (k Keeper) ConfirmOrder(ctx sdk.Context, orderId uint64) error {
3    sm := StateMachine{keeper: k}
4    return sm.Transition(ctx, orderId, OrderStateConfirmed)
5}

Q2: How do you implement custom authentication and authorization in Cosmos SDK?

Answer:

Custom AnteHandler:

 1package ante
 2
 3import (
 4    sdk "github.com/cosmos/cosmos-sdk/types"
 5    sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
 6    "github.com/cosmos/cosmos-sdk/x/auth/ante"
 7)
 8
 9// CustomAnteHandler implements custom authentication
10type CustomAnteHandler struct {
11    accountKeeper ante.AccountKeeper
12    signer        SignerVerifier
13}
14
15// NewAnteHandler creates a new ante handler
16func NewAnteHandler(
17    ak ante.AccountKeeper,
18    signer SignerVerifier,
19) sdk.AnteHandler {
20    return sdk.ChainAnteDecorators(
21        ante.NewSetUpContextDecorator(),
22        ante.NewRejectExtensionOptionsDecorator(),
23        ante.NewMempoolFeeDecorator(),
24        ante.NewValidateBasicDecorator(),
25        ante.NewTxTimeoutHeightDecorator(),
26        ante.NewValidateSigCountDecorator(ak),
27        ante.NewDeductFeeDecorator(ak),
28        NewCustomAuthDecorator(ak, signer),
29        ante.NewSetPubKeyDecorator(ak),
30        ante.NewValidateSigDecorator(ak),
31        ante.NewIncrementSequenceDecorator(ak),
32    )
33}
34
35// CustomAuthDecorator performs custom authentication
36type CustomAuthDecorator struct {
37    accountKeeper ante.AccountKeeper
38    signer         SignerVerifier
39}
40
41func NewCustomAuthDecorator(ak ante.AccountKeeper, signer SignerVerifier) CustomAuthDecorator {
42    return CustomAuthDecorator{
43        accountKeeper: ak,
44        signer:        signer,
45    }
46}
47
48// AnteHandle performs authentication
49func (cad CustomAuthDecorator) AnteHandle(
50    ctx sdk.Context,
51    tx sdk.Tx,
52    simulate bool,
53    next sdk.AnteHandler,
54) (sdk.Context, error) {
55    sigTx, ok := tx.(authsigning.SigVerifiableTx)
56    if !ok {
57        return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
58    }
59    
60    // Get signers
61    signers := sigTx.GetSigners()
62    
63    // Verify each signer
64    for _, signer := range signers {
65        // Check if signer is authorized
66        if !cad.signer.IsAuthorized(ctx, signer) {
67            return ctx, sdkerrors.Wrap(
68                sdkerrors.ErrUnauthorized,
69                fmt.Sprintf("signer %s is not authorized", signer.String()),
70            )
71        }
72        
73        // Additional custom checks
74        if err := cad.signer.VerifySignature(ctx, signer, sigTx); err != nil {
75            return ctx, err
76        }
77    }
78    
79    return next(ctx, tx, simulate)
80}

Role-Based Access Control:

 1package keeper
 2
 3// Role represents user role
 4type Role uint8
 5
 6const (
 7    RoleUser Role = iota
 8    RoleAdmin
 9    RoleModerator
10)
11
12// HasRole checks if account has role
13func (k Keeper) HasRole(ctx sdk.Context, addr sdk.AccAddress, role Role) bool {
14    accountRole := k.GetAccountRole(ctx, addr)
15    return accountRole >= role
16}
17
18// RequireRole ensures account has required role
19func (k Keeper) RequireRole(ctx sdk.Context, addr sdk.AccAddress, role Role) error {
20    if !k.HasRole(ctx, addr, role) {
21        return sdkerrors.Wrap(
22            sdkerrors.ErrUnauthorized,
23            fmt.Sprintf("account %s does not have required role", addr.String()),
24        )
25    }
26    return nil
27}
28
29// In handler
30func (k Keeper) AdminAction(ctx sdk.Context, msg types.MsgAdminAction) error {
31    // Check admin role
32    if err := k.RequireRole(ctx, msg.Signer, RoleAdmin); err != nil {
33        return err
34    }
35    
36    // Perform admin action
37    return k.DoAdminAction(ctx, msg)
38}

Q3: How do you implement custom fee models and fee distribution?

Answer:

Custom Fee Decorator:

 1package ante
 2
 3import (
 4    sdk "github.com/cosmos/cosmos-sdk/types"
 5    "github.com/cosmos/cosmos-sdk/x/auth/ante"
 6)
 7
 8// CustomFeeDecorator implements custom fee logic
 9type CustomFeeDecorator struct {
10    accountKeeper ante.AccountKeeper
11    bankKeeper    BankKeeper
12    feeKeeper     FeeKeeper
13}
14
15func NewCustomFeeDecorator(ak ante.AccountKeeper, bk BankKeeper, fk FeeKeeper) CustomFeeDecorator {
16    return CustomFeeDecorator{
17        accountKeeper: ak,
18        bankKeeper:    bk,
19        feeKeeper:     fk,
20    }
21}
22
23func (cfd CustomFeeDecorator) AnteHandle(
24    ctx sdk.Context,
25    tx sdk.Tx,
26    simulate bool,
27    next sdk.AnteHandler,
28) (sdk.Context, error) {
29    feeTx, ok := tx.(sdk.FeeTx)
30    if !ok {
31        return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
32    }
33    
34    // Get fee
35    fee := feeTx.GetFee()
36    
37    // Calculate custom fee based on message type
38    customFee := cfd.calculateCustomFee(ctx, tx)
39    
40    // Use higher of standard or custom fee
41    if customFee.IsAllGT(fee) {
42        fee = customFee
43    }
44    
45    // Get payer
46    payer := feeTx.FeePayer()
47    if payer == nil {
48        payer = feeTx.GetSigners()[0]
49    }
50    
51    // Deduct fee
52    if err := cfd.bankKeeper.SendCoinsFromAccountToModule(
53        ctx,
54        payer,
55        types.FeeCollectorName,
56        fee,
57    ); err != nil {
58        return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fee: %s", err)
59    }
60    
61    // Distribute fee
62    cfd.feeKeeper.DistributeFee(ctx, fee, tx)
63    
64    return next(ctx, tx, simulate)
65}
66
67func (cfd CustomFeeDecorator) calculateCustomFee(ctx sdk.Context, tx sdk.Tx) sdk.Coins {
68    // Calculate fee based on message types
69    var totalFee sdk.Coins
70    
71    for _, msg := range tx.GetMsgs() {
72        switch m := msg.(type) {
73        case *types.MsgComplexOperation:
74            // Higher fee for complex operations
75            totalFee = totalFee.Add(sdk.NewCoin("stake", sdk.NewInt(1000)))
76        case *types.MsgSimpleOperation:
77            // Lower fee for simple operations
78            totalFee = totalFee.Add(sdk.NewCoin("stake", sdk.NewInt(100)))
79        default:
80            // Default fee
81            totalFee = totalFee.Add(sdk.NewCoin("stake", sdk.NewInt(500)))
82        }
83    }
84    
85    return totalFee
86}

Fee Distribution:

 1package keeper
 2
 3// DistributeFee distributes fees to validators and treasury
 4func (k Keeper) DistributeFee(ctx sdk.Context, fee sdk.Coins, tx sdk.Tx) {
 5    // Get distribution parameters
 6    params := k.GetParams(ctx)
 7    
 8    // Calculate shares
 9    validatorShare := fee.MulInt(sdk.NewIntFromUint64(params.ValidatorFeeShare))
10    treasuryShare := fee.MulInt(sdk.NewIntFromUint64(params.TreasuryFeeShare))
11    
12    // Distribute to validators
13    k.distributeToValidators(ctx, validatorShare)
14    
15    // Send to treasury
16    k.bankKeeper.SendCoinsFromModuleToModule(
17        ctx,
18        types.FeeCollectorName,
19        types.TreasuryModuleName,
20        treasuryShare,
21    )
22}

Q4: How do you implement custom query pagination and filtering?

Answer:

Pagination:

 1package keeper
 2
 3import (
 4    "github.com/cosmos/cosmos-sdk/store/prefix"
 5    "github.com/cosmos/cosmos-sdk/types/query"
 6)
 7
 8// QueryAllPosts with pagination
 9func (k Keeper) QueryAllPosts(
10    ctx sdk.Context,
11    req *types.QueryAllPostsRequest,
12) (*types.QueryAllPostsResponse, error) {
13    if req == nil {
14        return nil, status.Error(codes.InvalidArgument, "invalid request")
15    }
16    
17    var posts []types.Post
18    store := ctx.KVStore(k.storeKey)
19    postStore := prefix.NewStore(store, types.PostKeyPrefix)
20    
21    // Parse pagination
22    pageRes, err := query.Paginate(postStore, req.Pagination, func(key []byte, value []byte) error {
23        var post types.Post
24        if err := k.cdc.Unmarshal(value, &post); err != nil {
25            return err
26        }
27        
28        // Apply filters
29        if req.Filter != nil {
30            if !k.matchesFilter(post, req.Filter) {
31                return nil // Skip this post
32            }
33        }
34        
35        posts = append(posts, post)
36        return nil
37    })
38    
39    if err != nil {
40        return nil, status.Error(codes.Internal, err.Error())
41    }
42    
43    return &types.QueryAllPostsResponse{
44        Posts:      posts,
45        Pagination: pageRes,
46    }, nil
47}
48
49// matchesFilter checks if post matches filter criteria
50func (k Keeper) matchesFilter(post types.Post, filter *types.PostFilter) bool {
51    if filter == nil {
52        return true
53    }
54    
55    // Filter by creator
56    if filter.Creator != "" {
57        if post.Creator != filter.Creator {
58            return false
59        }
60    }
61    
62    // Filter by title contains
63    if filter.TitleContains != "" {
64        if !strings.Contains(strings.ToLower(post.Title), strings.ToLower(filter.TitleContains)) {
65            return false
66        }
67    }
68    
69    // Filter by date range
70    if filter.CreatedAfter != nil {
71        if post.CreatedAt.Before(*filter.CreatedAfter) {
72            return false
73        }
74    }
75    
76    if filter.CreatedBefore != nil {
77        if post.CreatedAt.After(*filter.CreatedBefore) {
78            return false
79        }
80    }
81    
82    return true
83}

Index-Based Queries:

 1// Create index for efficient queries
 2func (k Keeper) IndexPostsByCreator(ctx sdk.Context) {
 3    store := ctx.KVStore(k.storeKey)
 4    postStore := prefix.NewStore(store, types.PostKeyPrefix)
 5    
 6    iterator := sdk.KVStorePrefixIterator(postStore, []byte{})
 7    defer iterator.Close()
 8    
 9    for ; iterator.Valid(); iterator.Next() {
10        var post types.Post
11        k.cdc.MustUnmarshal(iterator.Value(), &post)
12        
13        // Store in creator index
14        creatorKey := types.GetPostByCreatorKey(post.Creator, post.Id)
15        store.Set(creatorKey, iterator.Key())
16    }
17}
18
19// QueryPostsByCreator uses index
20func (k Keeper) QueryPostsByCreator(
21    ctx sdk.Context,
22    creator string,
23    pagination *query.PageRequest,
24) ([]types.Post, *query.PageResponse, error) {
25    store := ctx.KVStore(k.storeKey)
26    creatorStore := prefix.NewStore(store, types.GetPostByCreatorKeyPrefix(creator))
27    
28    var posts []types.Post
29    
30    pageRes, err := query.Paginate(creatorStore, pagination, func(key []byte, value []byte) error {
31        // Get actual post key from index
32        postKey := value
33        
34        // Get post
35        postBytes := store.Get(postKey)
36        var post types.Post
37        k.cdc.MustUnmarshal(postBytes, &post)
38        posts = append(posts, post)
39        return nil
40    })
41    
42    return posts, pageRes, err
43}

Q5: How do you implement upgrade handlers and migration logic?

Answer:

Upgrade Handler:

 1package app
 2
 3import (
 4    "github.com/cosmos/cosmos-sdk/types/module"
 5    upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
 6)
 7
 8// RegisterUpgradeHandlers registers upgrade handlers
 9func (app *App) RegisterUpgradeHandlers() {
10    app.UpgradeKeeper.SetUpgradeHandler("v2", func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
11        // Perform migrations
12        return app.mm.RunMigrations(ctx, app.configurator, vm)
13    })
14}
15
16// Custom migration
17func (app *App) migrateV1ToV2(ctx sdk.Context) error {
18    // Migrate state
19    store := ctx.KVStore(app.keys[types.StoreKey])
20    
21    // Example: Migrate old format to new format
22    iterator := sdk.KVStorePrefixIterator(store, []byte("old_prefix"))
23    defer iterator.Close()
24    
25    for ; iterator.Valid(); iterator.Next() {
26        key := iterator.Key()
27        value := iterator.Value()
28        
29        // Transform data
30        newKey := migrateKey(key)
31        newValue := migrateValue(value)
32        
33        // Store in new format
34        store.Set(newKey, newValue)
35        
36        // Delete old key
37        store.Delete(key)
38    }
39    
40    return nil
41}
42
43// Version-specific upgrade
44func (app *App) RegisterUpgradeHandlers() {
45    app.UpgradeKeeper.SetUpgradeHandler("v2.0.0", func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
46        // Run module migrations
47        return app.mm.RunMigrations(ctx, app.configurator, vm)
48    })
49    
50    app.UpgradeKeeper.SetUpgradeHandler("v2.1.0", func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
51        // Custom migration logic
52        if err := app.migrateV1ToV2(ctx); err != nil {
53            return vm, err
54        }
55        
56        // Continue with module migrations
57        return app.mm.RunMigrations(ctx, app.configurator, vm)
58    })
59}

Module Migration:

 1package keeper
 2
 3// RegisterStoreDecoder registers migration decoders
 4func (k Keeper) RegisterStoreDecoder(store sdk.StoreDecoderRegistry) {
 5    store[types.StoreKey] = func(version uint64) func(sdk.KVStore) error {
 6        switch version {
 7        case 0:
 8            return migrateV0ToV1
 9        case 1:
10            return migrateV1ToV2
11        default:
12            return nil
13        }
14    }
15}
16
17func migrateV0ToV1(store sdk.KVStore) error {
18    // Migration logic
19    return nil
20}

Q6: How do you implement event indexing and event queries?

Answer:

Event Emission:

 1package keeper
 2
 3// EmitOrderEvent emits order-related events
 4func (k Keeper) EmitOrderEvent(
 5    ctx sdk.Context,
 6    eventType string,
 7    orderId uint64,
 8    attributes map[string]string,
 9) {
10    event := sdk.NewEvent(
11        eventType,
12        sdk.NewAttribute(types.AttributeKeyOrderId, fmt.Sprintf("%d", orderId)),
13    )
14    
15    // Add custom attributes
16    for key, value := range attributes {
17        event = event.AppendAttributes(sdk.NewAttribute(key, value))
18    }
19    
20    ctx.EventManager().EmitEvent(event)
21}
22
23// EmitTypedEvent emits typed events (better for indexing)
24func (k Keeper) EmitTypedEvent(ctx sdk.Context, event proto.Message) {
25    ctx.EventManager().EmitTypedEvent(event)
26}

Event Querying:

 1package keeper
 2
 3// QueryEvents queries events by type and attributes
 4func (k Keeper) QueryEvents(
 5    ctx sdk.Context,
 6    eventType string,
 7    attributes map[string]string,
 8    pagination *query.PageRequest,
 9) (*types.QueryEventsResponse, error) {
10    // Query events from event store
11    events := k.eventStore.QueryEvents(
12        ctx,
13        eventType,
14        attributes,
15        pagination,
16    )
17    
18    return &types.QueryEventsResponse{
19        Events:     events,
20        Pagination: pagination,
21    }, nil
22}

Event Indexing:

 1// Index events for efficient querying
 2type EventIndexer struct {
 3    store sdk.KVStore
 4}
 5
 6func (ei EventIndexer) IndexEvent(event sdk.Event) {
 7    // Index by event type
 8    typeKey := types.GetEventTypeKey(event.Type)
 9    ei.store.Set(typeKey, []byte{1})
10    
11    // Index by attributes
12    for _, attr := range event.Attributes {
13        attrKey := types.GetEventAttributeKey(event.Type, attr.Key, attr.Value)
14        ei.store.Set(attrKey, []byte{1})
15    }
16}

Q7: How do you implement custom transaction validation and ordering?

Answer:

Custom Mempool:

 1package mempool
 2
 3import (
 4    "github.com/cosmos/cosmos-sdk/types"
 5    "github.com/cosmos/cosmos-sdk/types/mempool"
 6)
 7
 8// PriorityMempool implements priority-based ordering
 9type PriorityMempool struct {
10    transactions []sdk.Tx
11    priorityFunc func(sdk.Tx) int64
12}
13
14func NewPriorityMempool(priorityFunc func(sdk.Tx) int64) *PriorityMempool {
15    return &PriorityMempool{
16        transactions: make([]sdk.Tx, 0),
17        priorityFunc: priorityFunc,
18    }
19}
20
21func (mp *PriorityMempool) Insert(ctx sdk.Context, tx sdk.Tx) error {
22    // Calculate priority
23    priority := mp.priorityFunc(tx)
24    
25    // Insert in sorted order
26    inserted := false
27    for i, existingTx := range mp.transactions {
28        if mp.priorityFunc(existingTx) < priority {
29            // Insert here
30            mp.transactions = append(
31                mp.transactions[:i],
32                append([]sdk.Tx{tx}, mp.transactions[i:]...)...,
33            )
34            inserted = true
35            break
36        }
37    }
38    
39    if !inserted {
40        mp.transactions = append(mp.transactions, tx)
41    }
42    
43    return nil
44}
45
46func (mp *PriorityMempool) Select(ctx sdk.Context, maxTxs [][]byte) [][]byte {
47    selected := make([][]byte, 0, len(maxTxs))
48    
49    for i, tx := range mp.transactions {
50        if i >= len(maxTxs) {
51            break
52        }
53        selected = append(selected, tx.GetSigners()[0].Bytes())
54    }
55    
56    return selected
57}
58
59// Custom validation
60func (mp *PriorityMempool) ValidateTx(ctx sdk.Context, tx sdk.Tx) error {
61    // Custom validation logic
62    if err := mp.validateNonce(ctx, tx); err != nil {
63        return err
64    }
65    
66    if err := mp.validateGas(ctx, tx); err != nil {
67        return err
68    }
69    
70    return nil
71}

Q8: How do you implement inter-module communication and hooks?

Answer:

Hooks Interface:

 1package types
 2
 3// Hooks defines module hooks
 4type Hooks interface {
 5    AfterOrderCreated(ctx sdk.Context, orderId uint64)
 6    AfterOrderCancelled(ctx sdk.Context, orderId uint64)
 7    AfterOrderCompleted(ctx sdk.Context, orderId uint64)
 8}
 9
10var _ Hooks = Hooks{}
11
12// Hooks is a wrapper struct
13type Hooks struct{}
14
15func (Hooks) AfterOrderCreated(ctx sdk.Context, orderId uint64)    {}
16func (Hooks) AfterOrderCancelled(ctx sdk.Context, orderId uint64)  {}
17func (Hooks) AfterOrderCompleted(ctx sdk.Context, orderId uint64)  {}

Keeper with Hooks:

 1package keeper
 2
 3type Keeper struct {
 4    storeKey sdk.StoreKey
 5    hooks    types.Hooks
 6}
 7
 8// SetHooks sets hooks
 9func (k *Keeper) SetHooks(hooks types.Hooks) {
10    if k.hooks != nil {
11        panic("cannot set hooks twice")
12    }
13    k.hooks = hooks
14}
15
16// CreateOrder with hooks
17func (k Keeper) CreateOrder(ctx sdk.Context, order types.Order) error {
18    // Create order
19    k.SetOrder(ctx, order)
20    
21    // Call hooks
22    if k.hooks != nil {
23        k.hooks.AfterOrderCreated(ctx, order.Id)
24    }
25    
26    return nil
27}

Module Using Hooks:

 1package keeper
 2
 3type NotificationKeeper struct {
 4    orderKeeper types.OrderKeeper
 5}
 6
 7// Implement hooks
 8func (nk NotificationKeeper) AfterOrderCreated(ctx sdk.Context, orderId uint64) {
 9    // Send notification
10    order, _ := nk.orderKeeper.GetOrder(ctx, orderId)
11    nk.SendNotification(ctx, order.Buyer, "Order created")
12}
13
14// Register hooks
15func (app *App) SetupHooks() {
16    orderKeeper := app.OrderKeeper
17    notificationKeeper := app.NotificationKeeper
18    
19    orderKeeper.SetHooks(notificationKeeper)
20}

Q9: How do you implement custom consensus parameters and governance?

Answer:

Custom Parameters:

 1package types
 2
 3// Params defines module parameters
 4type Params struct {
 5    MaxOrderAmount    sdk.Int
 6    MinOrderAmount    sdk.Int
 7    OrderTimeout      time.Duration
 8    FeePercentage     sdk.Dec
 9}
10
11// DefaultParams returns default parameters
12func DefaultParams() Params {
13    return Params{
14        MaxOrderAmount: sdk.NewInt(1000000),
15        MinOrderAmount: sdk.NewInt(100),
16        OrderTimeout:  24 * time.Hour,
17        FeePercentage: sdk.NewDecWithPrec(1, 2), // 1%
18    }
19}

Parameter Management:

 1package keeper
 2
 3// GetParams gets parameters
 4func (k Keeper) GetParams(ctx sdk.Context) types.Params {
 5    store := ctx.KVStore(k.storeKey)
 6    bz := store.Get(types.ParamsKey)
 7    if bz == nil {
 8        return types.DefaultParams()
 9    }
10    
11    var params types.Params
12    k.cdc.MustUnmarshal(bz, &params)
13    return params
14}
15
16// SetParams sets parameters
17func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
18    store := ctx.KVStore(k.storeKey)
19    bz := k.cdc.MustMarshal(&params)
20    store.Set(types.ParamsKey, bz)
21}

Governance Proposal:

 1package types
 2
 3// UpdateParamsProposal is a governance proposal
 4type UpdateParamsProposal struct {
 5    Title       string
 6    Description string
 7    Params      Params
 8}
 9
10// ValidateBasic validates proposal
11func (p UpdateParamsProposal) ValidateBasic() error {
12    if p.Title == "" {
13        return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "title cannot be empty")
14    }
15    if p.Description == "" {
16        return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "description cannot be empty")
17    }
18    return p.Params.Validate()
19}
20
21// Handler for proposal
22func (k Keeper) HandleUpdateParamsProposal(ctx sdk.Context, p UpdateParamsProposal) error {
23    k.SetParams(ctx, p.Params)
24    return nil
25}

Q10: How do you optimize gas usage in Cosmos SDK transactions?

Answer:

Gas Optimization Techniques:

  1. Use uint64 instead of string for IDs:
 1// Bad: Uses more gas
 2type Post struct {
 3    Id      string  // Expensive
 4    Title   string
 5}
 6
 7// Good: Uses less gas
 8type Post struct {
 9    Id      uint64  // Cheap
10    Title   string
11}
  1. Pack structs efficiently:
 1// Bad: Wastes storage
 2type Order struct {
 3    Id      uint64  // 8 bytes
 4    Status  uint8   // 1 byte (but takes 8 bytes due to alignment)
 5    Amount  sdk.Int
 6}
 7
 8// Good: Packed efficiently
 9type Order struct {
10    Id      uint64
11    Status  uint8
12    _       [7]byte // Padding
13    Amount  sdk.Int
14}
  1. Use iterator instead of loading all:
 1// Bad: Loads all into memory
 2func (k Keeper) GetAllOrders(ctx sdk.Context) []Order {
 3    store := ctx.KVStore(k.storeKey)
 4    iterator := sdk.KVStorePrefixIterator(store, []byte{})
 5    defer iterator.Close()
 6    
 7    var orders []Order
 8    for ; iterator.Valid(); iterator.Next() {
 9        var order Order
10        k.cdc.MustUnmarshal(iterator.Value(), &order)
11        orders = append(orders, order) // Expensive append
12    }
13    return orders
14}
15
16// Good: Process one at a time
17func (k Keeper) ProcessOrders(ctx sdk.Context, processor func(Order) error) error {
18    store := ctx.KVStore(k.storeKey)
19    iterator := sdk.KVStorePrefixIterator(store, []byte{})
20    defer iterator.Close()
21    
22    for ; iterator.Valid(); iterator.Next() {
23        var order Order
24        k.cdc.MustUnmarshal(iterator.Value(), &order)
25        if err := processor(order); err != nil {
26            return err
27        }
28    }
29    return nil
30}
  1. Cache expensive computations:
 1// Cache computed values
 2type Keeper struct {
 3    storeKey sdk.StoreKey
 4    cache    map[string]interface{}
 5}
 6
 7func (k Keeper) GetExpensiveValue(ctx sdk.Context, key string) sdk.Int {
 8    // Check cache first
 9    if cached, exists := k.cache[key]; exists {
10        return cached.(sdk.Int)
11    }
12    
13    // Compute
14    value := k.computeExpensiveValue(ctx, key)
15    
16    // Cache
17    k.cache[key] = value
18    
19    return value
20}
  1. Use events instead of storing redundant data:
 1// Bad: Store redundant data
 2type Order struct {
 3    Id          uint64
 4    CreatedAt   time.Time
 5    UpdatedAt   time.Time  // Redundant if we can derive from events
 6}
 7
 8// Good: Use events for history
 9func (k Keeper) CreateOrder(ctx sdk.Context, order Order) {
10    k.SetOrder(ctx, order)
11    
12    // Emit event (cheaper than storing)
13    ctx.EventManager().EmitEvent(
14        sdk.NewEvent(
15            types.EventTypeOrderCreated,
16            sdk.NewAttribute(types.AttributeKeyOrderId, fmt.Sprintf("%d", order.Id)),
17            sdk.NewAttribute(types.AttributeKeyTimestamp, ctx.BlockTime().String()),
18        ),
19    )
20}

Related Snippets