-
Notifications
You must be signed in to change notification settings - Fork 136
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
Create Parent Proposal and use gov-created client in Handshake #5
Changes from 5 commits
ad4701c
3ea732e
579107f
c4ba227
2b40e28
2969826
5d0f184
b4c88ab
5b2cdd9
f938899
c12825c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ option go_package = "github.com/cosmos/interchain-security/x/ccv/types"; | |
|
||
import "gogoproto/gogo.proto"; | ||
import "tendermint/abci/types.proto"; | ||
import "google/protobuf/any.proto"; | ||
import "google/protobuf/timestamp.proto"; | ||
|
||
// This packet is sent from parent chain to baby chain if the validator set for baby chain | ||
// changes (due to new bonding/unbonding messages or slashing events) | ||
|
@@ -30,3 +32,28 @@ enum Status { | |
// channel is invalid and can no longer process packets | ||
STATUS_INVALID = 3 [(gogoproto.enumvalue_customname) = "INVALID"]; | ||
} | ||
|
||
// CreateChildChainProposal is a governance proposal on the parent chain to spawn a new child chain. | ||
// If it passes, then all validators on the parent chain are expected to validate the child chain at spawn time | ||
// or get slashed. It is recommended that spawn time occurs after the proposal end time. | ||
message CreateChildChainProposal { | ||
option (gogoproto.goproto_getters) = false; | ||
option (gogoproto.goproto_stringer) = false; | ||
|
||
// the title of the proposal | ||
string title = 1; | ||
// the description of the proposal | ||
string description = 2; | ||
// the proposed chain-id of the new child chain, must be different from all other child chain ids of the executing | ||
// parent chain. | ||
string chain_id = 3 [(gogoproto.moretags) = "yaml:\"chain_id\""]; | ||
// the proposed client state of new child chain. | ||
// Since it contains no consensus information, this may be created before child chain is created. | ||
google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""]; | ||
// genesis hash with no staking information included. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
i.e without the genesis module included? We should also specify in the comment that this is the child chain's genesis hash There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. Basically without any |
||
bytes genesis_hash = 5 [(gogoproto.moretags) = "yaml:\"genesis_hash\""]; | ||
// spawn time is the time on the parent chain at which the child chain genesis is finalized and all validators | ||
// will be responsible for starting their child chain validator node. | ||
google.protobuf.Timestamp spawn_time = 6 | ||
[(gogoproto.moretags) = "yaml:\"spawn_time\"", (gogoproto.stdtime) = true, (gogoproto.nullable) = false]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package keeper | ||
|
||
import ( | ||
"encoding/binary" | ||
"strings" | ||
"time" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" | ||
commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types" | ||
"github.com/cosmos/ibc-go/modules/core/exported" | ||
ibcexported "github.com/cosmos/ibc-go/modules/core/exported" | ||
ibctmtypes "github.com/cosmos/ibc-go/modules/light-clients/07-tendermint/types" | ||
"github.com/cosmos/interchain-security/x/ccv/parent/types" | ||
ccv "github.com/cosmos/interchain-security/x/ccv/types" | ||
) | ||
|
||
// CreateChildChainProposal will receive the child chain's client state from the proposal. | ||
// If the spawn time has already passed, then set the child chain. Otherwise store the client | ||
// as a pending client, and set once spawn time has passed. | ||
func (k Keeper) CreateChildChainProposal(ctx sdk.Context, p *ccv.CreateChildChainProposal) error { | ||
clientState, err := clienttypes.UnpackClientState(p.ClientState) | ||
if err != nil { | ||
return err | ||
} | ||
if ctx.BlockTime().After(p.SpawnTime) { | ||
err = k.CreateChildClient(ctx, p.ChainId, clientState) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
k.SetPendingClient(ctx, p.SpawnTime, p.ChainId, clientState) | ||
return nil | ||
} | ||
|
||
// CreateChildClient will create the CCV client for the given child chain. The CCV channel must be built | ||
// on top of the CCV client to ensure connection with the right child chain. | ||
func (k Keeper) CreateChildClient(ctx sdk.Context, chainID string, clientState ibcexported.ClientState) error { | ||
// TODO: Allow for current validators to set different keys | ||
consensusState := ibctmtypes.NewConsensusState(ctx.BlockTime(), commitmenttypes.NewMerkleRoot([]byte(ibctmtypes.SentinelRoot)), ctx.BlockHeader().NextValidatorsHash) | ||
clientID, err := k.clientKeeper.CreateClient(ctx, clientState, consensusState) | ||
if err != nil { | ||
return err | ||
} | ||
k.SetChildClient(ctx, chainID, clientID) | ||
return nil | ||
} | ||
|
||
// SetChildClient sets the clientID for the given chainID | ||
func (k Keeper) SetChildClient(ctx sdk.Context, chainID, clientID string) { | ||
store := ctx.KVStore(k.storeKey) | ||
store.Set(types.ChainToClientKey(chainID), []byte(clientID)) | ||
} | ||
|
||
// GetChildClient returns the clientID for the given chainID. | ||
func (k Keeper) GetChildClient(ctx sdk.Context, chainID string) string { | ||
store := ctx.KVStore(k.storeKey) | ||
return string(store.Get(types.ChainToClientKey(chainID))) | ||
} | ||
|
||
// SetPendingClient sets an IdentifiedClient for the given timestamp | ||
func (k Keeper) SetPendingClient(ctx sdk.Context, timestamp time.Time, chainID string, clientState ibcexported.ClientState) error { | ||
store := ctx.KVStore(k.storeKey) | ||
bz, err := k.cdc.MarshalInterface(clientState) | ||
if err != nil { | ||
return err | ||
} | ||
store.Set(types.PendingClientKey(timestamp, chainID), bz) | ||
return nil | ||
} | ||
|
||
// GetPendingClient gets an IdentifiedClient for the given timestamp | ||
func (k Keeper) GetPendingClient(ctx sdk.Context, timestamp time.Time, chainID string) ibcexported.ClientState { | ||
store := ctx.KVStore(k.storeKey) | ||
bz := store.Get(types.PendingClientKey(timestamp, chainID)) | ||
if bz == nil { | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil | ||
} | ||
return clienttypes.MustUnmarshalClientState(k.cdc, bz) | ||
} | ||
|
||
// IteratePendingClients iterates over the pending clients in order and sets the child client if the spawn time has passed, | ||
// otherwise it will break out of loop and return. | ||
func (k Keeper) IteratePendingClients(ctx sdk.Context) { | ||
store := ctx.KVStore(k.storeKey) | ||
iterator := sdk.KVStorePrefixIterator(store, []byte(types.PendingClientKeyPrefix+"/")) | ||
defer iterator.Close() | ||
|
||
if !iterator.Valid() { | ||
return | ||
} | ||
|
||
for ; iterator.Valid(); iterator.Next() { | ||
suffixKey := iterator.Key() | ||
// splitKey contains the bigendian time in the first element and the chainID in the second element/ | ||
splitKey := strings.Split(string(suffixKey), "/") | ||
|
||
timeNano := binary.BigEndian.Uint64([]byte(splitKey[0])) | ||
spawnTime := time.Unix(0, int64(timeNano)) | ||
var cs exported.ClientState | ||
k.cdc.UnmarshalInterface(iterator.Value(), cs) | ||
|
||
if ctx.BlockTime().After(spawnTime) { | ||
k.CreateChildClient(ctx, splitKey[1], cs) | ||
} else { | ||
break | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the chain created in this repo is able to be both parent and child, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, though I believe the default genesis disables the child module.