200 lines
5.5 KiB
Go
200 lines
5.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
|
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
|
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
|
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
|
ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/client"
|
|
"github.com/cosmos/cosmos-sdk/x/ibc/exported"
|
|
)
|
|
|
|
// QueryClientState returns a client state. If prove is true, it performs an ABCI store query
|
|
// in order to retrieve the merkle proof. Otherwise, it uses the gRPC query client.
|
|
func QueryClientState(
|
|
clientCtx client.Context, clientID string, prove bool,
|
|
) (*types.QueryClientStateResponse, error) {
|
|
if prove {
|
|
return QueryClientStateABCI(clientCtx, clientID)
|
|
}
|
|
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
req := &types.QueryClientStateRequest{
|
|
ClientId: clientID,
|
|
}
|
|
|
|
return queryClient.ClientState(context.Background(), req)
|
|
}
|
|
|
|
// QueryClientStateABCI queries the store to get the light client state and a merkle proof.
|
|
func QueryClientStateABCI(
|
|
clientCtx client.Context, clientID string,
|
|
) (*types.QueryClientStateResponse, error) {
|
|
key := host.FullKeyClientPath(clientID, host.KeyClientState())
|
|
|
|
value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// check if client exists
|
|
if len(value) == 0 {
|
|
return nil, sdkerrors.Wrap(types.ErrClientNotFound, clientID)
|
|
}
|
|
|
|
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
|
|
|
|
clientState, err := types.UnmarshalClientState(cdc, value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
anyClientState, err := types.PackClientState(clientState)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
clientStateRes := types.NewQueryClientStateResponse(clientID, anyClientState, proofBz, proofHeight)
|
|
return clientStateRes, nil
|
|
}
|
|
|
|
// QueryConsensusState returns a consensus state. If prove is true, it performs an ABCI store
|
|
// query in order to retrieve the merkle proof. Otherwise, it uses the gRPC query client.
|
|
func QueryConsensusState(
|
|
clientCtx client.Context, clientID string, height exported.Height, prove, latestHeight bool,
|
|
) (*types.QueryConsensusStateResponse, error) {
|
|
if prove {
|
|
return QueryConsensusStateABCI(clientCtx, clientID, height)
|
|
}
|
|
|
|
queryClient := types.NewQueryClient(clientCtx)
|
|
req := &types.QueryConsensusStateRequest{
|
|
ClientId: clientID,
|
|
EpochNumber: height.GetEpochNumber(),
|
|
EpochHeight: height.GetEpochHeight(),
|
|
LatestHeight: latestHeight,
|
|
}
|
|
|
|
return queryClient.ConsensusState(context.Background(), req)
|
|
}
|
|
|
|
// QueryConsensusStateABCI queries the store to get the consensus state of a light client and a
|
|
// merkle proof of its existence or non-existence.
|
|
func QueryConsensusStateABCI(
|
|
clientCtx client.Context, clientID string, height exported.Height,
|
|
) (*types.QueryConsensusStateResponse, error) {
|
|
key := host.FullKeyClientPath(clientID, host.KeyConsensusState(height))
|
|
|
|
value, proofBz, proofHeight, err := ibcclient.QueryTendermintProof(clientCtx, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// check if consensus state exists
|
|
if len(value) == 0 {
|
|
return nil, sdkerrors.Wrap(types.ErrConsensusStateNotFound, clientID)
|
|
}
|
|
|
|
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
|
|
|
|
cs, err := types.UnmarshalConsensusState(cdc, value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
anyConsensusState, err := types.PackConsensusState(cs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewQueryConsensusStateResponse(clientID, anyConsensusState, proofBz, proofHeight), nil
|
|
}
|
|
|
|
// QueryTendermintHeader takes a client context and returns the appropriate
|
|
// tendermint header
|
|
func QueryTendermintHeader(clientCtx client.Context) (ibctmtypes.Header, int64, error) {
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return ibctmtypes.Header{}, 0, err
|
|
}
|
|
|
|
info, err := node.ABCIInfo()
|
|
if err != nil {
|
|
return ibctmtypes.Header{}, 0, err
|
|
}
|
|
|
|
height := info.Response.LastBlockHeight
|
|
|
|
commit, err := node.Commit(&height)
|
|
if err != nil {
|
|
return ibctmtypes.Header{}, 0, err
|
|
}
|
|
|
|
page := 0
|
|
count := 10_000
|
|
|
|
validators, err := node.Validators(&height, &page, &count)
|
|
if err != nil {
|
|
return ibctmtypes.Header{}, 0, err
|
|
}
|
|
|
|
protoCommit := commit.SignedHeader.ToProto()
|
|
protoValset, err := tmtypes.NewValidatorSet(validators.Validators).ToProto()
|
|
if err != nil {
|
|
return ibctmtypes.Header{}, 0, err
|
|
}
|
|
|
|
header := ibctmtypes.Header{
|
|
SignedHeader: protoCommit,
|
|
ValidatorSet: protoValset,
|
|
}
|
|
|
|
return header, height, nil
|
|
}
|
|
|
|
// QueryNodeConsensusState takes a client context and returns the appropriate
|
|
// tendermint consensus state
|
|
func QueryNodeConsensusState(clientCtx client.Context) (*ibctmtypes.ConsensusState, int64, error) {
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return &ibctmtypes.ConsensusState{}, 0, err
|
|
}
|
|
|
|
info, err := node.ABCIInfo()
|
|
if err != nil {
|
|
return &ibctmtypes.ConsensusState{}, 0, err
|
|
}
|
|
|
|
height := info.Response.LastBlockHeight
|
|
|
|
commit, err := node.Commit(&height)
|
|
if err != nil {
|
|
return &ibctmtypes.ConsensusState{}, 0, err
|
|
}
|
|
|
|
page := 1
|
|
count := 10_000
|
|
|
|
nextHeight := height + 1
|
|
nextVals, err := node.Validators(&nextHeight, &page, &count)
|
|
if err != nil {
|
|
return &ibctmtypes.ConsensusState{}, 0, err
|
|
}
|
|
|
|
state := &ibctmtypes.ConsensusState{
|
|
Timestamp: commit.Time,
|
|
Root: commitmenttypes.NewMerkleRoot(commit.AppHash),
|
|
NextValidatorsHash: tmtypes.NewValidatorSet(nextVals.Validators).Hash(),
|
|
}
|
|
|
|
return state, height, nil
|
|
}
|