Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add consumer genesis time query #2366

Merged
merged 13 commits into from
Nov 5, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `[x/provider]` Add query for consumer genesis time,
which corresponds to creation time of consumer clients.
([\#2366](https://github.com/cosmos/interchain-security/pull/2366))
75 changes: 73 additions & 2 deletions docs/docs/build/modules/02-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,29 @@ power_shaping_params:

</details>

##### Consumer Genesis Time

The `consumer-genesis-time` command allows to query the genesis time of the consumer chain associated with the consumer id.

```bash
interchain-security-pd query provider consumer-genesis-time [consumer-id] [flags]
```

<details>
<summary>Example</summary>

```bash
interchain-security-pd query provider consumer-genesis-time 0
```

Output:

```bash
genesis_time: "2024-10-18T08:13:23.507178095Z"
```

</details>

#### Transactions

The `tx` commands allows users to interact with the `provider` module.
Expand Down Expand Up @@ -2409,7 +2432,7 @@ Output:

#### Throttle State

The `QueryThrottleState` queries the main on-chain state relevant to slash packet throttling.
The `QueryThrottleState` endpoint queries the main on-chain state relevant to slash packet throttling.

```bash
interchain_security.ccv.provider.v1.Query/QueryThrottleState
Expand Down Expand Up @@ -2801,7 +2824,7 @@ Output:

#### Consumer Chain

The `QueryConsumerChain` command allows to query the consumer chain associated with the consumer id.
The `QueryConsumerChain` endpoint allows to query the consumer chain associated with the consumer id.

```bash
interchain_security.ccv.provider.v1.Query/QueryConsumerChain
Expand Down Expand Up @@ -2850,6 +2873,29 @@ grpcurl -plaintext -d '{"consumer_id": "0"}' localhost:9090 interchain_security.

</details>

#### Consumer Genesis Time

The `QueryConsumerGenesisTime` endpoint allows to query the genesis time of the consumer chain associated with the consumer id.

```bash
interchain_security.ccv.provider.v1.Query/QueryConsumerGenesisTime
```

<details>
<summary>Example</summary>

```bash
grpcurl -plaintext -d '{"consumer_id": "0"}' localhost:9090 interchain_security.ccv.provider.v1.Query/QueryConsumerGenesisTime
```

```json
{
"genesisTime": "2024-10-18T08:13:23.507178095Z"
}
```

</details>

### REST

A user can query the `provider` module using REST endpoints.
Expand Down Expand Up @@ -3524,3 +3570,28 @@ Output:
```

</details>

#### Consumer Genesis Time

The `consumer_genesis_time` endpoint allows to query the genesis time of the consumer chain associated with the consumer id.

```bash
interchain_security/ccv/provider/consumer_genesis_time/{consumer_id}
```

<details>
<summary>Example</summary>

```bash
curl http://localhost:1317/interchain_security/ccv/provider/consumer_genesis_time/0
```

Output:

```json
{
"genesis_time":"2024-10-18T08:29:46.153234Z"
}
```

</details>
17 changes: 17 additions & 0 deletions proto/interchain_security/ccv/provider/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ service Query {
option (google.api.http).get =
"/interchain_security/ccv/provider/consumer_chain/{consumer_id}";
}

// QueryConsumerGenesisTime returns the genesis time
// of the consumer chain associated with the provided consumer id
rpc QueryConsumerGenesisTime(QueryConsumerGenesisTimeRequest)
returns (QueryConsumerGenesisTimeResponse) {
option (google.api.http).get =
"/interchain_security/ccv/provider/consumer_genesis_time/{consumer_id}";
}
}

message QueryConsumerGenesisRequest {
Expand Down Expand Up @@ -390,3 +398,12 @@ message QueryConsumerChainResponse {
ConsumerInitializationParameters init_params = 6;
PowerShapingParameters power_shaping_params = 7;
}

message QueryConsumerGenesisTimeRequest {
string consumer_id = 1;
}

message QueryConsumerGenesisTimeResponse {
google.protobuf.Timestamp genesis_time = 1
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
}
28 changes: 28 additions & 0 deletions x/ccv/provider/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func NewQueryCmd() *cobra.Command {
cmd.AddCommand(CmdBlocksUntilNextEpoch())
cmd.AddCommand(CmdConsumerIdFromClientId())
cmd.AddCommand(CmdConsumerChain())
cmd.AddCommand(CmdConsumerGenesisTime())
return cmd
}

Expand Down Expand Up @@ -584,3 +585,30 @@ func CmdConsumerChain() *cobra.Command {

return cmd
}

func CmdConsumerGenesisTime() *cobra.Command {
cmd := &cobra.Command{
Use: "consumer-genesis-time [consumer-id]",
Short: "Query the genesis time of the consumer chain associated with the consumer id",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryConsumerGenesisTimeRequest{ConsumerId: args[0]}
res, err := queryClient.QueryConsumerGenesisTime(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
57 changes: 57 additions & 0 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/binary"
"fmt"
"sort"
"time"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -627,3 +628,59 @@ func (k Keeper) QueryConsumerChain(goCtx context.Context, req *types.QueryConsum
PowerShapingParams: &powerParams,
}, nil
}

// QueryConsumerGenesisTime returns the genesis time
// of the consumer chain associated with the provided consumer id
func (k Keeper) QueryConsumerGenesisTime(goCtx context.Context, req *types.QueryConsumerGenesisTimeRequest) (*types.QueryConsumerGenesisTimeResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

consumerId := req.ConsumerId
if err := ccvtypes.ValidateConsumerId(consumerId); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
ctx := sdk.UnwrapSDKContext(goCtx)

// Get consumer initialization params. If they aren't found,
// it means that there is no consumer for that consumerId.
params, err := k.GetConsumerInitializationParameters(ctx, consumerId)
if err != nil {
return nil, status.Errorf(
codes.InvalidArgument,
"cannot get consumer genesis time for consumer Id: %s: %s",
consumerId, types.ErrUnknownConsumerId,
)
}

// Get the consumer clientId. If it isn't found, it means
// that the consumer hasn't been launched or has been stopped and deleted.
clientID, ok := k.GetConsumerClientId(ctx, consumerId)
if !ok {
return nil, status.Errorf(
codes.InvalidArgument,
"cannot get consumer genesis time for consumer Id: %s: consumer hasn't been launched or has been stopped and deleted",
consumerId,
)
}

// Get the consensus state of the consumer client at the initial height,
// for which the timestamps corresponds to the consumer genesis time
cs, ok := k.clientKeeper.GetClientConsensusState(
ctx,
clientID,
params.InitialHeight,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't old consensus states pruned? If yes, this query would stop working after some time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, needs checking.

However, we can make it so that the query runs for chains that haven't yet started (passed spawntime).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those consumers will not have a client and thus no genesis time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@insumity The reason for this query is starting the consumer chain -- creating the genesis file with a correct timestamp that will not result in expired consumer clients on the provider. The consensus state will not be pruned at least until a new client update is received by the provider (otherwise the client update will fail). By this time, the consumer chain is already running so the query is no longer needed.

Copy link
Contributor

@MSalopek MSalopek Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought he was saying that after starting a chain (making it run, with relaying enabled) the initial height consensus state would get pruned. Thus, state at block 1 would not be queryable from GetClientConsensusState after a while.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consensus states are eventually pruned, but it takes a while. Otherwise client updates would not work. So for sure, the initial consensus state will remain on the provider for a while. The important part is that it will remain there for sure until either the consumer chain launches or the consumer light client on the provider expires.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the explanation.

)
if !ok {
return nil, status.Errorf(
codes.InvalidArgument,
"cannot get consumer genesis time for consumer Id: %s: cannot find consensus state for initial height: %s",
consumerId,
params.InitialHeight,
)
}

return &types.QueryConsumerGenesisTimeResponse{
GenesisTime: time.Unix(0, int64(cs.GetTimestamp())),
}, nil
}
Loading
Loading