-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
483 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package client | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
light_client_types "github.com/pokt-network/pocket/ibc/client/light_clients/types" | ||
"github.com/pokt-network/pocket/ibc/client/types" | ||
ibc_types "github.com/pokt-network/pocket/ibc/types" | ||
"github.com/pokt-network/pocket/shared/codec" | ||
"github.com/pokt-network/pocket/shared/modules" | ||
util_types "github.com/pokt-network/pocket/utility/types" | ||
"google.golang.org/protobuf/types/known/durationpb" | ||
) | ||
|
||
// GetHostConsensusState returns the ConsensusState at the given height for the | ||
// host chain, the Pocket network. It then serialises this and packs it into a | ||
// ConsensusState object for use in a WASM client | ||
func (c *clientManager) GetHostConsensusState(height modules.Height) (modules.ConsensusState, error) { | ||
blockStore := c.GetBus().GetPersistenceModule().GetBlockStore() | ||
block, err := blockStore.GetBlock(height.GetRevisionHeight()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
pocketConsState := &light_client_types.PocketConsensusState{ | ||
Timestamp: block.BlockHeader.Timestamp, | ||
StateHash: block.BlockHeader.StateHash, | ||
StateTreeHashes: block.BlockHeader.StateTreeHashes, | ||
NextValSetHash: block.BlockHeader.NextValSetHash, | ||
} | ||
consBz, err := codec.GetCodec().Marshal(pocketConsState) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return types.NewConsensusState(consBz, uint64(pocketConsState.Timestamp.AsTime().UnixNano())), nil | ||
} | ||
|
||
// GetHostClientState returns the ClientState at the given height for the host | ||
// chain, the Pocket network. | ||
// | ||
// This function is used to validate the state of a client running on a | ||
// counterparty chain. | ||
func (c *clientManager) GetHostClientState(height modules.Height) (modules.ClientState, error) { | ||
blockStore := c.GetBus().GetPersistenceModule().GetBlockStore() | ||
block, err := blockStore.GetBlock(height.GetRevisionHeight()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
rCtx, err := c.GetBus().GetPersistenceModule().NewReadContext(int64(height.GetRevisionHeight())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer rCtx.Release() | ||
unbondingBlocks, err := rCtx.GetIntParam(util_types.ValidatorUnstakingBlocksParamName, int64(height.GetRevisionHeight())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// TODO_AFTER(#705): use the actual MinimumBlockTime once set | ||
blockTime := time.Minute * 15 | ||
unbondingPeriod := blockTime * time.Duration(unbondingBlocks) // approx minutes per block * blocks | ||
pocketClient := &light_client_types.PocketClientState{ | ||
NetworkId: block.BlockHeader.NetworkId, | ||
TrustLevel: &light_client_types.Fraction{Numerator: 2, Denominator: 3}, | ||
TrustingPeriod: durationpb.New(unbondingPeriod), | ||
UnbondingPeriod: durationpb.New(unbondingPeriod), | ||
MaxClockDrift: durationpb.New(blockTime), // DISCUSS: What is a reasonable MaxClockDrift? | ||
LatestHeight: &types.Height{ | ||
RevisionNumber: height.GetRevisionNumber(), | ||
RevisionHeight: height.GetRevisionHeight(), | ||
}, | ||
ProofSpec: ibc_types.SmtSpec, | ||
} | ||
clientBz, err := codec.GetCodec().Marshal(pocketClient) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &types.ClientState{ | ||
Data: clientBz, | ||
RecentHeight: pocketClient.LatestHeight, | ||
}, nil | ||
} | ||
|
||
// VerifyHostClientState verifies that a ClientState for a light client running | ||
// on a counterparty chain is valid, by checking it against the result of | ||
// GetHostClientState(counterpartyClientState.GetLatestHeight()) | ||
func (c *clientManager) VerifyHostClientState(counterparty modules.ClientState) error { | ||
hostState, err := c.GetHostClientState(c.GetCurrentHeight()) | ||
if err != nil { | ||
return err | ||
} | ||
poktHost := new(light_client_types.PocketClientState) | ||
err = codec.GetCodec().Unmarshal(hostState.GetData(), poktHost) | ||
if err != nil { | ||
return err | ||
} | ||
poktCounter := new(light_client_types.PocketClientState) | ||
err = codec.GetCodec().Unmarshal(counterparty.GetData(), poktCounter) | ||
if err != nil { | ||
return errors.New("counterparty client state is not a PocketClientState") | ||
} | ||
|
||
if poktCounter.FrozenHeight > 0 { | ||
return errors.New("counterparty client state is frozen") | ||
} | ||
if poktCounter.NetworkId != poktHost.NetworkId { | ||
return errors.New("counterparty client state has different network id") | ||
} | ||
if poktCounter.LatestHeight.RevisionNumber != poktHost.LatestHeight.RevisionNumber { | ||
return errors.New("counterparty client state has different revision number") | ||
} | ||
if poktCounter.GetLatestHeight().GTE(poktHost.GetLatestHeight()) { | ||
return errors.New("counterparty client state has a height greater than or equal to the host client state") | ||
} | ||
if poktCounter.TrustLevel.LT(&light_client_types.Fraction{Numerator: 2, Denominator: 3}) || | ||
poktCounter.TrustLevel.GT(&light_client_types.Fraction{Numerator: 1, Denominator: 1}) { | ||
return errors.New("counterparty client state trust level is not in the accepted range") | ||
} | ||
if !poktCounter.ProofSpec.ConvertToIcs23ProofSpec().SpecEquals(poktHost.ProofSpec.ConvertToIcs23ProofSpec()) { | ||
return errors.New("counterparty client state has different proof spec") | ||
} | ||
if poktCounter.UnbondingPeriod != poktHost.UnbondingPeriod { | ||
return errors.New("counterparty client state has different unbonding period") | ||
} | ||
if poktCounter.UnbondingPeriod.AsDuration().Nanoseconds() < poktHost.TrustingPeriod.AsDuration().Nanoseconds() { | ||
return errors.New("counterparty client state unbonding period is less than trusting period") | ||
} | ||
|
||
// RESEARCH: Look into upgrade paths, their use and if they should just be equal | ||
|
||
return nil | ||
} | ||
|
||
// GetCurrentHeight returns the current IBC client height of the network | ||
// TODO_AFTER(#705): Use actual revision number | ||
func (h *clientManager) GetCurrentHeight() modules.Height { | ||
return &types.Height{ | ||
RevisionNumber: 1, | ||
RevisionHeight: h.GetBus().GetConsensusModule().CurrentHeight(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package types | ||
|
||
import ics23 "github.com/cosmos/ics23/go" | ||
|
||
var SmtSpec = &ProofSpec{ | ||
LeafSpec: &LeafOp{ | ||
Hash: HashOp_SHA256, | ||
PrehashKey: HashOp_SHA256, | ||
PrehashValue: HashOp_SHA256, | ||
Length: LengthOp_NO_PREFIX, | ||
Prefix: []byte{0}, | ||
}, | ||
InnerSpec: &InnerSpec{ | ||
ChildOrder: []int32{0, 1}, | ||
ChildSize: 32, | ||
MinPrefixLength: 1, | ||
MaxPrefixLength: 1, | ||
EmptyChild: make([]byte, 32), | ||
Hash: HashOp_SHA256, | ||
}, | ||
MaxDepth: 256, | ||
PrehashKeyBeforeComparison: true, | ||
} | ||
|
||
func (p *ProofSpec) ConvertToIcs23ProofSpec() *ics23.ProofSpec { | ||
ics := new(ics23.ProofSpec) | ||
ics.LeafSpec = p.LeafSpec.ConvertToIcs23LeafOp() | ||
ics.InnerSpec = p.InnerSpec.ConvertToIcs23InnerSpec() | ||
ics.MaxDepth = p.MaxDepth | ||
ics.MinDepth = p.MinDepth | ||
ics.PrehashKeyBeforeComparison = p.PrehashKeyBeforeComparison | ||
return ics | ||
} | ||
|
||
func (l *LeafOp) ConvertToIcs23LeafOp() *ics23.LeafOp { | ||
ics := new(ics23.LeafOp) | ||
ics.Hash = l.Hash.ConvertToIcs23HashOp() | ||
ics.PrehashKey = l.PrehashKey.ConvertToIcs23HashOp() | ||
ics.PrehashValue = l.PrehashValue.ConvertToIcs23HashOp() | ||
ics.Length = l.Length.ConvertToIcs23LenthOp() | ||
ics.Prefix = l.Prefix | ||
return ics | ||
} | ||
|
||
func (i *InnerSpec) ConvertToIcs23InnerSpec() *ics23.InnerSpec { | ||
ics := new(ics23.InnerSpec) | ||
ics.ChildOrder = i.ChildOrder | ||
ics.MinPrefixLength = i.MinPrefixLength | ||
ics.MaxPrefixLength = i.MaxPrefixLength | ||
ics.EmptyChild = i.EmptyChild | ||
ics.Hash = i.Hash.ConvertToIcs23HashOp() | ||
return ics | ||
} | ||
|
||
func (h HashOp) ConvertToIcs23HashOp() ics23.HashOp { | ||
switch h { | ||
case HashOp_NO_HASH: | ||
return ics23.HashOp_NO_HASH | ||
case HashOp_SHA256: | ||
return ics23.HashOp_SHA256 | ||
case HashOp_SHA512: | ||
return ics23.HashOp_SHA512 | ||
case HashOp_KECCAK: | ||
return ics23.HashOp_KECCAK | ||
case HashOp_RIPEMD160: | ||
return ics23.HashOp_RIPEMD160 | ||
case HashOp_BITCOIN: | ||
return ics23.HashOp_BITCOIN | ||
case HashOp_SHA512_256: | ||
return ics23.HashOp_SHA512_256 | ||
default: | ||
panic("unknown hash op") | ||
} | ||
} | ||
|
||
func (l LengthOp) ConvertToIcs23LenthOp() ics23.LengthOp { | ||
switch l { | ||
case LengthOp_NO_PREFIX: | ||
return ics23.LengthOp_NO_PREFIX | ||
case LengthOp_VAR_PROTO: | ||
return ics23.LengthOp_VAR_PROTO | ||
case LengthOp_VAR_RLP: | ||
return ics23.LengthOp_VAR_RLP | ||
case LengthOp_FIXED32_BIG: | ||
return ics23.LengthOp_FIXED32_BIG | ||
case LengthOp_FIXED32_LITTLE: | ||
return ics23.LengthOp_FIXED32_LITTLE | ||
case LengthOp_FIXED64_BIG: | ||
return ics23.LengthOp_FIXED64_BIG | ||
case LengthOp_FIXED64_LITTLE: | ||
return ics23.LengthOp_FIXED64_LITTLE | ||
case LengthOp_REQUIRE_32_BYTES: | ||
return ics23.LengthOp_REQUIRE_32_BYTES | ||
case LengthOp_REQUIRE_64_BYTES: | ||
return ics23.LengthOp_REQUIRE_64_BYTES | ||
default: | ||
panic("unknown length op") | ||
} | ||
} | ||
|
||
func (i *InnerOp) ConvertToIcs23InnerOp() *ics23.InnerOp { | ||
ics := new(ics23.InnerOp) | ||
ics.Hash = i.Hash.ConvertToIcs23HashOp() | ||
ics.Prefix = i.Prefix | ||
ics.Suffix = i.Suffix | ||
return ics | ||
} |
Oops, something went wrong.