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

[IBC] Add ICS-02 Client Interfaces #932

Merged
merged 10 commits into from
Jul 26, 2023
Merged
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ protogen_local: go_protoc-go-inject-tag ## Generate go structures for all of the
make download_ics23_proto; \
fi
$(PROTOC_SHARED) -I=./ibc/types/proto --go_out=./ibc/types ./ibc/types/proto/*.proto
$(PROTOC_SHARED) -I=./ibc/client/types/proto --go_out=./ibc/client/types ./ibc/client/types/proto/*.proto
$(PROTOC_SHARED) -I=./ibc/client/types/proto -I=./ibc/client/light_clients/types/proto -I=./shared/core/types/proto -I=./ibc/types/proto --go_out=./ibc/client/light_clients/types ./ibc/client/light_clients/types/proto/*.proto

# echo "View generated proto files by running: make protogen_show"

Expand Down
59 changes: 59 additions & 0 deletions ibc/client/light_clients/types/proto/pocket.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
syntax = "proto3";

package core;

option go_package = "github.com/pokt-network/pocket/ibc/client/light_client/types";

import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "proofs.proto";
import "wasm.proto";
import "block.proto";

// PocketConsensusState defines the ibc client consensus state for Pocket
message PocketConsensusState {
google.protobuf.Timestamp timestamp = 1; // unix nano timestamp of the block
string state_hash = 2; // hex encoded root state tree hash
map<string, string> state_tree_hashes = 3; // map of state tree hashes; map[TreeName]hex(TreeRootHash)
string next_val_set_hash = 4; // hex encoded sha3_256 hash of the next validator set
}

// PocketClientState defines the ibc client state for Pocket
message PocketClientState {
Copy link
Member

Choose a reason for hiding this comment

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

TIL some stuff from the parametesr in this proto

string network_id = 1; // network identifier string
Fraction trust_level = 2; // fraction of the validator set that is required to sign off on new blocks
google.protobuf.Duration trusting_period = 3; // the duration of the period since the LastestTimestamp where the state can be upgraded
google.protobuf.Duration unbonding_period = 4; // the duration of the staking unbonding period
google.protobuf.Duration max_clock_drift = 5; // the max duration a new header's time can be in the future
Height latest_height = 6; // the latest height the client was updated to
uint64 frozen_height = 7; // the height at which the client was frozen due to a misbehaviour
ProofSpec proof_spec = 8; // ics23 proof spec used in verifying proofs
// RESEARCH: Figure out exactly what this is for in tendermint, why it is needed and if we need it also
// repeated string upgrade_path = 9; // the upgrade path for the new client state
}

// Fraction defines a positive rational number
message Fraction {
uint64 numerator = 1;
uint64 denominator = 2;
}

// PocketHeader defines the ibc client header for the Pocket network
message PocketHeader {
BlockHeader block_header = 1; // pocket consensus block header
ValidatorSet validator_set = 2; // new validator set for the updating client
// the consensus state at trusted_height must be within the unbonding_period to correctly verify the new header
Height trusted_height = 3; // height of the ConsensusState stored used to verify the new header
// trusted_validators must hash to the ConsensusState.NextValSetHash as this is the last trusted validator set
h5law marked this conversation as resolved.
Show resolved Hide resolved
// hashed using SHA3Hash(validatorSetBytes) in shared/crypto/sha3.go
ValidatorSet trusted_validators = 4; // already stored validator set used to verify the update
}

// PocketMisbehaviour defines the ibc client misbehaviour for the Pocket network
//
// The two conflicting headers are submitted as evidence to verify the Pocket
// network has misbehaved.
message PocketMisbehaviour {
PocketHeader header_1 = 1; // the first header
PocketHeader header_2 = 2; // the second header
}
35 changes: 35 additions & 0 deletions ibc/client/types/proto/wasm.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
syntax = "proto3";

package core;

option go_package = "github.com/pokt-network/pocket/ibc/client/types";

// ClientState for a Wasm light client
message ClientState {
bytes data = 1; // opaque data passed to the wasm client
bytes wasm_checksum = 2; // checksum of the wasm client code
Height recent_height = 3; // latest height of the client
}

// ConsensusState for a Wasm light client
message ConsensusState {
bytes data = 1; // opaque data passed to the wasm client
uint64 timestamp = 2; // unix nano timestamp of the block
}

// Header for a Wasm light client
message Header {
bytes data = 1; // opaque data passed to the wasm client
Height height = 2; // height of the header
}

// Misbehaviour for a Wasm light client
message Misbehaviour {
bytes data = 1; // opaque data passed to the wasm client
}

// Height represents the height of a client
message Height {
uint64 revision_number = 1;
uint64 revision_height = 2;
}
1 change: 1 addition & 0 deletions shared/modules/bus_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ type Bus interface {
GetIBCHost() IBCHostSubmodule
GetBulkStoreCacher() BulkStoreCacher
GetEventLogger() EventLogger
GetClientManager() ClientManager
}
212 changes: 212 additions & 0 deletions shared/modules/ibc_client_module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package modules

//go:generate mockgen -destination=./mocks/ibc_client_module_mock.go github.com/pokt-network/pocket/shared/modules ClientManager

import (
"google.golang.org/protobuf/proto"
)

type ClientStatus string

const (
ClientManagerModuleName = "client_manager"

// Client Status types
ActiveStatus ClientStatus = "active"
ExpiredStatus ClientStatus = "expired"
FrozenStatus ClientStatus = "frozen"
UnauthorizedStatus ClientStatus = "unauthorized"
UnknownStatus ClientStatus = "unknown"
)

type ClientManagerOption func(ClientManager)

type clientManagerFactory = FactoryWithOptions[ClientManager, ClientManagerOption]

// ClientManager is the interface that defines the methods needed to interact with an
// IBC light client it manages the different lifecycle methods for the different clients
// https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics
type ClientManager interface {
Submodule
clientManagerFactory

// === Client Lifecycle Management ===

// CreateClient creates a new client with the given client state and initial consensus state
// and initialises its unique identifier in the IBC store
CreateClient(ClientState, ConsensusState) (string, error)

// UpdateClient updates an existing client with the given ClientMessage, given that
// the ClientMessage can be verified using the existing ClientState and ConsensusState
UpdateClient(identifier string, clientMessage ClientMessage) error

// UpgradeClient upgrades an existing client with the given identifier using the
// ClientState and ConsenusState provided. It can only do so if the new client
// was committed to by the old client at the specified upgrade height
UpgradeClient(
identifier string,
clientState ClientState, consensusState ConsensusState,
proofUpgradeClient, proofUpgradeConsState []byte,
) error

// === Client Queries ===

// GetConsensusState returns the ConsensusState at the given height for the given client
GetConsensusState(identifier string, height Height) (ConsensusState, error)

// GetClientState returns the ClientState for the given client
GetClientState(identifier string) (ClientState, error)

// GetHostConsensusState returns the ConsensusState at the given height for the host chain
GetHostConsensusState(height Height) (ConsensusState, error)

// GetHostClientState returns the ClientState at the provided height for the host chain
GetHostClientState(height Height) (ClientState, error)

// GetCurrentHeight returns the current IBC client height of the network
GetCurrentHeight() (Height, error)

// VerifyHostClientState verifies the client state for a client running on a
// counterparty chain is valid, checking against the current host client state
VerifyHostClientState(ClientState) error
}

// ClientState is an interface that defines the methods required by a clients
// implementation of their own client state object
//
// ClientState is an opaque data structure defined by a client type. It may keep
// arbitrary internal state to track verified roots and past misbehaviours.
type ClientState interface {
proto.Message

GetData() []byte
GetWasmChecksum() []byte
ClientType() string
GetLatestHeight() Height
Validate() error

// Status returns the status of the client. Only Active clients are allowed
// to process packets.
Status(clientStore ProvableStore) ClientStatus

// GetTimestampAtHeight must return the timestamp for the consensus state
// associated with the provided height.
GetTimestampAtHeight(clientStore ProvableStore, height Height) (uint64, error)

// Initialise is called upon client creation, it allows the client to perform
// validation on the initial consensus state and set the client state,
// consensus state and any client-specific metadata necessary for correct
// light client operation in the provided client store.
Initialise(clientStore ProvableStore, consensusState ConsensusState) error

// VerifyMembership is a generic proof verification method which verifies a
// proof of the existence of a value at a given CommitmentPath at the
// specified height. The path is expected to be the full CommitmentPath
VerifyMembership(
clientStore ProvableStore,
height Height,
delayTimePeriod, delayBlockPeriod uint64,
proof, path, value []byte,
) error

// VerifyNonMembership is a generic proof verification method which verifies
// the absence of a given CommitmentPath at a specified height. The path is
// expected to be the full CommitmentPath
VerifyNonMembership(
clientStore ProvableStore,
height Height,
delayTimePeriod, delayBlockPeriod uint64,
proof, path []byte,
) error

// VerifyClientMessage verifies a ClientMessage. A ClientMessage could be a
// Header, Misbehaviour, or batch update. It must handle each type of
// ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState,
// and UpdateStateOnMisbehaviour will assume that the content of the
// ClientMessage has been verified and can be trusted. An error should be
// returned if the ClientMessage fails to verify.
VerifyClientMessage(clientStore ProvableStore, clientMsg ClientMessage) error

// Checks for evidence of a misbehaviour in Header or Misbehaviour type.
// It assumes the ClientMessage has already been verified.
CheckForMisbehaviour(clientStore ProvableStore, clientMsg ClientMessage) bool

// UpdateStateOnMisbehaviour should perform appropriate state changes on a
// client state given that misbehaviour has been detected and verified
UpdateStateOnMisbehaviour(clientStore ProvableStore, clientMsg ClientMessage) error

// UpdateState updates and stores as necessary any associated information
// for an IBC client, such as the ClientState and corresponding ConsensusState.
// Upon successful update, a consensus height is returned.
// It assumes the ClientMessage has already been verified.
UpdateState(clientStore ProvableStore, clientMsg ClientMessage) (Height, error)

// Upgrade functions
// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last
// height committed by the current revision. Clients are responsible for ensuring that the planned last
// height of the current revision is somehow encoded in the proof verification process.
// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty
// may be cancelled or modified before the last planned height.
// If the upgrade is verified, the upgraded client and consensus states must be set in the client store.
VerifyUpgradeAndUpdateState(
clientStore ProvableStore,
newClient ClientState,
newConsState ConsensusState,
proofUpgradeClient,
proofUpgradeConsState []byte,
) error
}

// ConsensusState is an interface that defines the methods required by a clients
// implementation of their own consensus state object
//
// ConsensusState is an opaque data structure defined by a client type, used by the
// validity predicate to verify new commits & state roots. Likely the structure will
// contain the last commit produced by the consensus process, including signatures
// and validator set metadata.
type ConsensusState interface {
proto.Message

GetData() []byte
ClientType() string
GetTimestamp() uint64
ValidateBasic() error
}

// ClientMessage is an interface that defines the methods required by a clients
// implementation of their own client message object
//
// A ClientMessage is an opaque data structure defined by a client type which
// provides information to update the client. ClientMessages can be submitted
// to an associated client to add new ConsensusState(s) and/or update the
// ClientState. They likely contain a height, a proof, a commitment root, and
// possibly updates to the validity predicate.
type ClientMessage interface {
proto.Message

GetData() []byte
ClientType() string
ValidateBasic() error
}

// Height is an interface that defines the methods required by a clients
// implementation of their own height object
//
// Heights usually have two components: revision number and revision height.
type Height interface {
IsZero() bool
LT(Height) bool
LTE(Height) bool
EQ(Height) bool
GT(Height) bool
GTE(Height) bool
Increment() Height
Decrement() Height
GetRevisionNumber() uint64
GetRevisionHeight() uint64
ToString() string // must define a determinstic `String()` method not the generated protobuf method
}

func (s ClientStatus) String() string {
return string(s)
}
Loading