github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/core/02-client/keeper/client.go (about) 1 package keeper 2 3 import ( 4 "encoding/hex" 5 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 8 "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types" 9 "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/exported" 10 ) 11 12 // CreateClient creates a new client state and populates it with a given consensus 13 // state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create 14 func (k Keeper) CreateClient( 15 ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, 16 ) (string, error) { 17 params := k.GetParams(ctx) 18 if !params.IsAllowedClient(clientState.ClientType()) { 19 return "", sdkerrors.Wrapf( 20 types.ErrInvalidClientType, 21 "client state type %s is not registered in the allowlist", clientState.ClientType(), 22 ) 23 } 24 25 clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType()) 26 27 k.SetClientState(ctx, clientID, clientState) 28 k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) 29 30 // verifies initial consensus state against client state and initializes client store with any client-specific metadata 31 // e.g. set ProcessedTime in Tendermint clients 32 if err := clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, clientID), consensusState); err != nil { 33 return "", err 34 } 35 36 // check if consensus state is nil in case the created client is Localhost 37 if consensusState != nil { 38 k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState) 39 } 40 41 k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) 42 43 return clientID, nil 44 } 45 46 // UpdateClient updates the consensus state and the state root from a provided header. 47 func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error { 48 clientState, found := k.GetClientState(ctx, clientID) 49 if !found { 50 return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) 51 } 52 clientStore := k.ClientStore(ctx, clientID) 53 // prevent update if the client is frozen before or at header height 54 if status := clientState.Status(ctx, clientStore, k.cdc); status != exported.Active { 55 return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status) 56 } 57 58 eventType := types.EventTypeUpdateClient 59 60 // Any writes made in CheckHeaderAndUpdateState are persisted on both valid updates and misbehaviour updates. 61 // Light client implementations are responsible for writing the correct metadata (if any) in either case. 62 newClientState, newConsensusState, err := clientState.CheckHeaderAndUpdateState(ctx, k.cdc, clientStore, header) 63 if err != nil { 64 return sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID) 65 } 66 67 // emit the full header in events 68 var ( 69 headerStr string 70 consensusHeight exported.Height 71 ) 72 if header != nil { 73 // Marshal the Header as an Any and encode the resulting bytes to hex. 74 // This prevents the event value from containing invalid UTF-8 characters 75 // which may cause data to be lost when JSON encoding/decoding. 76 headerStr = hex.EncodeToString(types.MustMarshalHeader(k.cdc, header)) 77 // set default consensus height with header height 78 consensusHeight = header.GetHeight() 79 80 } 81 82 // set new client state regardless of if update is valid update or misbehaviour 83 k.SetClientState(ctx, clientID, newClientState) 84 // If client state is not frozen after clientState CheckHeaderAndUpdateState, 85 // then update was valid. Write the update state changes, and set new consensus state. 86 // Else the update was proof of misbehaviour and we must emit appropriate misbehaviour events. 87 if status := newClientState.Status(ctx, clientStore, k.cdc); status != exported.Frozen { 88 // if update is not misbehaviour then update the consensus state 89 // we don't set consensus state for localhost client 90 if header != nil && clientID != exported.Localhost { 91 k.SetClientConsensusState(ctx, clientID, header.GetHeight(), newConsensusState) 92 } else { 93 consensusHeight = types.GetSelfHeight(ctx) 94 } 95 96 k.Logger(ctx).Info("client state updated", "client-id", clientID, "height", consensusHeight.String()) 97 98 } else { 99 // set eventType to SubmitMisbehaviour 100 eventType = types.EventTypeSubmitMisbehaviour 101 102 k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID) 103 } 104 // emit the full header in events 105 106 // emitting events in the keeper emits for both begin block and handler client updates 107 ctx.EventManager().EmitEvent( 108 sdk.NewEvent( 109 eventType, 110 sdk.NewAttribute(types.AttributeKeyClientID, clientID), 111 sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), 112 sdk.NewAttribute(types.AttributeKeyConsensusHeight, consensusHeight.String()), 113 sdk.NewAttribute(types.AttributeKeyHeader, headerStr), 114 ), 115 ) 116 117 return nil 118 } 119 120 // UpgradeClient upgrades the client to a new client state if this new client was committed to 121 // by the old client at the specified upgrade height 122 func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, 123 proofUpgradeClient, proofUpgradeConsState []byte) error { 124 clientState, found := k.GetClientState(ctx, clientID) 125 if !found { 126 return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) 127 } 128 129 clientStore := k.ClientStore(ctx, clientID) 130 131 if status := clientState.Status(ctx, clientStore, k.cdc); status != exported.Active { 132 return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status) 133 } 134 135 updatedClientState, updatedConsState, err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, 136 upgradedClient, upgradedConsState, proofUpgradeClient, proofUpgradeConsState) 137 if err != nil { 138 return sdkerrors.Wrapf(err, "cannot upgrade client with ID %s", clientID) 139 } 140 141 k.SetClientState(ctx, clientID, updatedClientState) 142 k.SetClientConsensusState(ctx, clientID, updatedClientState.GetLatestHeight(), updatedConsState) 143 144 k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", updatedClientState.GetLatestHeight().String()) 145 146 // emitting events in the keeper emits for client upgrades 147 ctx.EventManager().EmitEvent( 148 sdk.NewEvent( 149 types.EventTypeUpgradeClient, 150 sdk.NewAttribute(types.AttributeKeyClientID, clientID), 151 sdk.NewAttribute(types.AttributeKeyClientType, updatedClientState.ClientType()), 152 sdk.NewAttribute(types.AttributeKeyConsensusHeight, updatedClientState.GetLatestHeight().String()), 153 ), 154 ) 155 156 return nil 157 } 158 159 // CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the 160 // client if so. 161 func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour exported.Misbehaviour) error { 162 clientState, found := k.GetClientState(ctx, misbehaviour.GetClientID()) 163 if !found { 164 return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID()) 165 } 166 167 clientStore := k.ClientStore(ctx, misbehaviour.GetClientID()) 168 169 if status := clientState.Status(ctx, clientStore, k.cdc); status != exported.Active { 170 return sdkerrors.Wrapf(types.ErrClientNotActive, "cannot process misbehaviour for client (%s) with status %s", misbehaviour.GetClientID(), status) 171 } 172 173 if err := misbehaviour.ValidateBasic(); err != nil { 174 return err 175 } 176 177 clientState, err := clientState.CheckMisbehaviourAndUpdateState(ctx, k.cdc, clientStore, misbehaviour) 178 if err != nil { 179 return err 180 } 181 182 k.SetClientState(ctx, misbehaviour.GetClientID(), clientState) 183 k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", misbehaviour.GetClientID()) 184 185 return nil 186 }