-
Notifications
You must be signed in to change notification settings - Fork 586
/
client_state.go
198 lines (162 loc) · 7.56 KB
/
client_state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package localhost
import (
"bytes"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types"
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)
var _ exported.ClientState = (*ClientState)(nil)
// NewClientState creates a new 09-localhost ClientState instance.
func NewClientState(height clienttypes.Height) exported.ClientState {
return &ClientState{
LatestHeight: height,
}
}
// ClientType returns the 09-localhost client type.
func (cs ClientState) ClientType() string {
return exported.Localhost
}
// GetLatestHeight returns the 09-localhost client state latest height.
func (cs ClientState) GetLatestHeight() exported.Height {
return cs.LatestHeight
}
// Status always returns Active. The 09-localhost status cannot be changed.
func (cs ClientState) Status(_ sdk.Context, _ sdk.KVStore, _ codec.BinaryCodec) exported.Status {
return exported.Active
}
// Validate performs a basic validation of the client state fields.
func (cs ClientState) Validate() error {
if cs.LatestHeight.RevisionHeight == 0 {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "local revision height cannot be zero")
}
return nil
}
// ZeroCustomFields returns the same client state since there are no custom fields in the 09-localhost client state.
func (cs ClientState) ZeroCustomFields() exported.ClientState {
return &cs
}
// Initialize ensures that initial consensus state for localhost is nil.
func (cs ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error {
if consState != nil {
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.")
}
clientState := ClientState{
LatestHeight: clienttypes.GetSelfHeight(ctx),
}
clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &clientState))
return nil
}
// GetTimestampAtHeight returns the current block time retrieved from the application context. The localhost client does not store consensus states and thus
// cannot provide a timestamp for the provided height.
func (cs ClientState) GetTimestampAtHeight(ctx sdk.Context, _ sdk.KVStore, _ codec.BinaryCodec, _ exported.Height) (uint64, error) {
return uint64(ctx.BlockTime().UnixNano()), nil
}
// VerifyMembership is a generic proof verification method which verifies the existence of a given key and value within the IBC store.
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
// The caller must provide the full IBC store.
func (cs ClientState) VerifyMembership(
ctx sdk.Context,
store sdk.KVStore,
_ codec.BinaryCodec,
_ exported.Height,
_ uint64,
_ uint64,
proof []byte,
path exported.Path,
value []byte,
) error {
// ensure the proof provided is the expected sentintel localhost client proof
if !bytes.Equal(proof, SentinelProof) {
return sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "expected %s, got %s", string(SentinelProof), string(proof))
}
merklePath, ok := path.(commitmenttypes.MerklePath)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
}
if len(merklePath.GetKeyPath()) != 2 {
return sdkerrors.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
}
// The commitment prefix (eg: "ibc") is omitted when operating on the core IBC store
bz := store.Get([]byte(merklePath.KeyPath[1]))
if bz == nil {
return sdkerrors.Wrapf(clienttypes.ErrFailedMembershipVerification, "value not found for path %s", path)
}
if !bytes.Equal(bz, value) {
return sdkerrors.Wrapf(clienttypes.ErrFailedMembershipVerification, "value provided does not equal value stored at path: %s", path)
}
return nil
}
// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath within the IBC store.
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
// The caller must provide the full IBC store.
func (cs ClientState) VerifyNonMembership(
ctx sdk.Context,
store sdk.KVStore,
_ codec.BinaryCodec,
_ exported.Height,
_ uint64,
_ uint64,
proof []byte,
path exported.Path,
) error {
// ensure the proof provided is the expected sentintel localhost client proof
if !bytes.Equal(proof, SentinelProof) {
return sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "expected %s, got %s", string(SentinelProof), string(proof))
}
merklePath, ok := path.(commitmenttypes.MerklePath)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
}
if len(merklePath.GetKeyPath()) != 2 {
return sdkerrors.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
}
// The commitment prefix (eg: "ibc") is omitted when operating on the core IBC store
if store.Has([]byte(merklePath.KeyPath[1])) {
return sdkerrors.Wrapf(clienttypes.ErrFailedNonMembershipVerification, "value found for path %s", path)
}
return nil
}
// VerifyClientMessage is unsupported by the 09-localhost client type and returns an error.
func (cs ClientState) VerifyClientMessage(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage) error {
return sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client message verification is unsupported by the localhost client")
}
// CheckForMisbehaviour is unsupported by the 09-localhost client type and performs a no-op, returning false.
func (cs ClientState) CheckForMisbehaviour(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage) bool {
return false
}
// UpdateStateOnMisbehaviour is unsupported by the 09-localhost client type and performs a no-op.
func (cs ClientState) UpdateStateOnMisbehaviour(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, _ exported.ClientMessage) {
}
// UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState.
// Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified.
func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) []exported.Height {
height := clienttypes.GetSelfHeight(ctx)
cs.LatestHeight = height
clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &cs))
return []exported.Height{height}
}
// ExportMetadata is a no-op for the 09-localhost client.
func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata {
return nil
}
// CheckSubstituteAndUpdateState returns an error. The localhost cannot be modified by
// proposals.
func (cs ClientState) CheckSubstituteAndUpdateState(_ sdk.Context, _ codec.BinaryCodec, _, _ sdk.KVStore, _ exported.ClientState) error {
return sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal")
}
// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded
func (cs ClientState) VerifyUpgradeAndUpdateState(
_ sdk.Context,
_ codec.BinaryCodec,
_ sdk.KVStore,
_ exported.ClientState,
_ exported.ConsensusState,
_,
_ []byte,
) error {
return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client")
}