diff --git a/go.mod b/go.mod index 7170eb81ed8..bc826c3dcfc 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.8.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/celestiaorg/nmt v0.20.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index f34e899c49d..5e6d295bdf8 100644 --- a/go.sum +++ b/go.sum @@ -283,6 +283,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/celestiaorg/nmt v0.20.0 h1:9i7ultZ8Wv5ytt8ZRaxKQ5KOOMo4A2K2T/aPGjIlSas= +github.com/celestiaorg/nmt v0.20.0/go.mod h1:Oz15Ub6YPez9uJV0heoU4WpFctxazuIhKyUtaYNio7E= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= diff --git a/modules/light-clients/07-celestia/celestia.pb.go b/modules/light-clients/07-celestia/celestia.pb.go new file mode 100644 index 00000000000..41f7416c7cc --- /dev/null +++ b/modules/light-clients/07-celestia/celestia.pb.go @@ -0,0 +1,1405 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/lightclients/celestia/v1/celestia.proto + +package celestia + +import ( + fmt "fmt" + crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + _07_tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ClientState from Tendermint tracks the current validator set, latest height, +// and a possible frozen height. +type ClientState struct { + BaseClient *_07_tendermint.ClientState `protobuf:"bytes,1,opt,name=base_client,json=baseClient,proto3" json:"base_client,omitempty"` +} + +func (m *ClientState) Reset() { *m = ClientState{} } +func (m *ClientState) String() string { return proto.CompactTextString(m) } +func (*ClientState) ProtoMessage() {} +func (*ClientState) Descriptor() ([]byte, []int) { + return fileDescriptor_1a7b0753ec3219d3, []int{0} +} +func (m *ClientState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ClientState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ClientState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ClientState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClientState.Merge(m, src) +} +func (m *ClientState) XXX_Size() int { + return m.Size() +} +func (m *ClientState) XXX_DiscardUnknown() { + xxx_messageInfo_ClientState.DiscardUnknown(m) +} + +var xxx_messageInfo_ClientState proto.InternalMessageInfo + +// ShareProof is an NMT proof that a set of shares exist in a set of rows and a +// Merkle proof that those rows exist in a Merkle tree with a given data root. +type ShareProof struct { + Data [][]byte `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + ShareProofs []*NMTProof `protobuf:"bytes,2,rep,name=share_proofs,json=shareProofs,proto3" json:"share_proofs,omitempty"` + NamespaceId []byte `protobuf:"bytes,3,opt,name=namespace_id,json=namespaceId,proto3" json:"namespace_id,omitempty"` + RowProof *RowProof `protobuf:"bytes,4,opt,name=row_proof,json=rowProof,proto3" json:"row_proof,omitempty"` + NamespaceVersion uint32 `protobuf:"varint,5,opt,name=namespace_version,json=namespaceVersion,proto3" json:"namespace_version,omitempty"` +} + +func (m *ShareProof) Reset() { *m = ShareProof{} } +func (m *ShareProof) String() string { return proto.CompactTextString(m) } +func (*ShareProof) ProtoMessage() {} +func (*ShareProof) Descriptor() ([]byte, []int) { + return fileDescriptor_1a7b0753ec3219d3, []int{1} +} +func (m *ShareProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ShareProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ShareProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ShareProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShareProof.Merge(m, src) +} +func (m *ShareProof) XXX_Size() int { + return m.Size() +} +func (m *ShareProof) XXX_DiscardUnknown() { + xxx_messageInfo_ShareProof.DiscardUnknown(m) +} + +var xxx_messageInfo_ShareProof proto.InternalMessageInfo + +func (m *ShareProof) GetData() [][]byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *ShareProof) GetShareProofs() []*NMTProof { + if m != nil { + return m.ShareProofs + } + return nil +} + +func (m *ShareProof) GetNamespaceId() []byte { + if m != nil { + return m.NamespaceId + } + return nil +} + +func (m *ShareProof) GetRowProof() *RowProof { + if m != nil { + return m.RowProof + } + return nil +} + +func (m *ShareProof) GetNamespaceVersion() uint32 { + if m != nil { + return m.NamespaceVersion + } + return 0 +} + +// RowProof is a Merkle proof that a set of rows exist in a Merkle tree with a +// given data root. +type RowProof struct { + RowRoots [][]byte `protobuf:"bytes,1,rep,name=row_roots,json=rowRoots,proto3" json:"row_roots,omitempty"` + Proofs []*crypto.Proof `protobuf:"bytes,2,rep,name=proofs,proto3" json:"proofs,omitempty"` + Root []byte `protobuf:"bytes,3,opt,name=root,proto3" json:"root,omitempty"` + StartRow uint32 `protobuf:"varint,4,opt,name=start_row,json=startRow,proto3" json:"start_row,omitempty"` + EndRow uint32 `protobuf:"varint,5,opt,name=end_row,json=endRow,proto3" json:"end_row,omitempty"` +} + +func (m *RowProof) Reset() { *m = RowProof{} } +func (m *RowProof) String() string { return proto.CompactTextString(m) } +func (*RowProof) ProtoMessage() {} +func (*RowProof) Descriptor() ([]byte, []int) { + return fileDescriptor_1a7b0753ec3219d3, []int{2} +} +func (m *RowProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RowProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RowProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RowProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_RowProof.Merge(m, src) +} +func (m *RowProof) XXX_Size() int { + return m.Size() +} +func (m *RowProof) XXX_DiscardUnknown() { + xxx_messageInfo_RowProof.DiscardUnknown(m) +} + +var xxx_messageInfo_RowProof proto.InternalMessageInfo + +func (m *RowProof) GetRowRoots() [][]byte { + if m != nil { + return m.RowRoots + } + return nil +} + +func (m *RowProof) GetProofs() []*crypto.Proof { + if m != nil { + return m.Proofs + } + return nil +} + +func (m *RowProof) GetRoot() []byte { + if m != nil { + return m.Root + } + return nil +} + +func (m *RowProof) GetStartRow() uint32 { + if m != nil { + return m.StartRow + } + return 0 +} + +func (m *RowProof) GetEndRow() uint32 { + if m != nil { + return m.EndRow + } + return 0 +} + +// NMTProof is a proof of a namespace.ID in an NMT. +// In case this proof proves the absence of a namespace.ID +// in a tree it also contains the leaf hashes of the range +// where that namespace would be. +type NMTProof struct { + // Start index of this proof. + Start int32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` + // End index of this proof. + End int32 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + // Nodes that together with the corresponding leaf values can be used to + // recompute the root and verify this proof. Nodes should consist of the max + // and min namespaces along with the actual hash, resulting in each being 48 + // bytes each + Nodes [][]byte `protobuf:"bytes,3,rep,name=nodes,proto3" json:"nodes,omitempty"` + // leafHash are nil if the namespace is present in the NMT. In case the + // namespace to be proved is in the min/max range of the tree but absent, this + // will contain the leaf hash necessary to verify the proof of absence. Leaf + // hashes should consist of the namespace along with the actual hash, + // resulting 40 bytes total. + LeafHash []byte `protobuf:"bytes,4,opt,name=leaf_hash,json=leafHash,proto3" json:"leaf_hash,omitempty"` +} + +func (m *NMTProof) Reset() { *m = NMTProof{} } +func (m *NMTProof) String() string { return proto.CompactTextString(m) } +func (*NMTProof) ProtoMessage() {} +func (*NMTProof) Descriptor() ([]byte, []int) { + return fileDescriptor_1a7b0753ec3219d3, []int{3} +} +func (m *NMTProof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NMTProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NMTProof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NMTProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_NMTProof.Merge(m, src) +} +func (m *NMTProof) XXX_Size() int { + return m.Size() +} +func (m *NMTProof) XXX_DiscardUnknown() { + xxx_messageInfo_NMTProof.DiscardUnknown(m) +} + +var xxx_messageInfo_NMTProof proto.InternalMessageInfo + +func (m *NMTProof) GetStart() int32 { + if m != nil { + return m.Start + } + return 0 +} + +func (m *NMTProof) GetEnd() int32 { + if m != nil { + return m.End + } + return 0 +} + +func (m *NMTProof) GetNodes() [][]byte { + if m != nil { + return m.Nodes + } + return nil +} + +func (m *NMTProof) GetLeafHash() []byte { + if m != nil { + return m.LeafHash + } + return nil +} + +func init() { + proto.RegisterType((*ClientState)(nil), "ibc.lightclients.celestia.v1.ClientState") + proto.RegisterType((*ShareProof)(nil), "ibc.lightclients.celestia.v1.ShareProof") + proto.RegisterType((*RowProof)(nil), "ibc.lightclients.celestia.v1.RowProof") + proto.RegisterType((*NMTProof)(nil), "ibc.lightclients.celestia.v1.NMTProof") +} + +func init() { + proto.RegisterFile("ibc/lightclients/celestia/v1/celestia.proto", fileDescriptor_1a7b0753ec3219d3) +} + +var fileDescriptor_1a7b0753ec3219d3 = []byte{ + // 523 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x52, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0x6e, 0xb6, 0x3f, 0xac, 0x93, 0x2e, 0xac, 0xc3, 0x82, 0x61, 0xd5, 0x58, 0x7b, 0x90, 0x42, + 0x69, 0x66, 0xbb, 0x1e, 0x14, 0xbd, 0xb9, 0x20, 0x2e, 0xa8, 0xc8, 0xac, 0x78, 0xf0, 0x52, 0xa7, + 0xc9, 0x6c, 0x13, 0x48, 0xf2, 0xca, 0xcc, 0x6c, 0x82, 0x37, 0x8f, 0x1e, 0xfd, 0x13, 0x04, 0xff, + 0x19, 0x8f, 0x7b, 0xf4, 0x28, 0xed, 0x3f, 0x22, 0x33, 0x93, 0xc4, 0xc8, 0x82, 0xde, 0xbe, 0xf7, + 0xcd, 0x7b, 0xdf, 0xf7, 0xde, 0x9b, 0x87, 0x66, 0xc9, 0x2a, 0x24, 0x69, 0xb2, 0x8e, 0x55, 0x98, + 0x26, 0x3c, 0x57, 0x92, 0x84, 0x3c, 0xe5, 0x52, 0x25, 0x8c, 0x14, 0x8b, 0x06, 0x07, 0x1b, 0x01, + 0x0a, 0xf0, 0xdd, 0x64, 0x15, 0x06, 0xed, 0xe4, 0xa0, 0x49, 0x28, 0x16, 0x47, 0xf7, 0x14, 0xcf, + 0x23, 0x2e, 0xb2, 0x24, 0x57, 0x24, 0x14, 0x9f, 0x36, 0x0a, 0xc8, 0x46, 0x00, 0x5c, 0xd8, 0xe2, + 0xa3, 0xc3, 0x35, 0xac, 0xc1, 0x40, 0xa2, 0x51, 0xc5, 0x92, 0x6b, 0xfe, 0x2d, 0x95, 0x62, 0xd1, + 0x8a, 0x6c, 0xc1, 0x84, 0x21, 0xf7, 0xd4, 0x64, 0x9e, 0x2b, 0xa6, 0x38, 0x7e, 0x85, 0xdc, 0x15, + 0x93, 0x7c, 0x69, 0xab, 0x3d, 0x67, 0xec, 0x4c, 0xdd, 0x93, 0x59, 0x70, 0xad, 0xd1, 0x96, 0x4e, + 0xb1, 0x08, 0x5a, 0x0a, 0x14, 0xe9, 0x7a, 0x4b, 0x3c, 0xed, 0x7d, 0xf9, 0x76, 0xbf, 0x33, 0xf9, + 0xbc, 0x87, 0xd0, 0x79, 0xcc, 0x04, 0x7f, 0xab, 0xdb, 0xc7, 0x18, 0xf5, 0x22, 0xa6, 0x98, 0xe7, + 0x8c, 0xbb, 0xd3, 0x11, 0x35, 0x18, 0x9f, 0xa1, 0x91, 0xd4, 0x19, 0x4b, 0x33, 0xa1, 0xf4, 0xf6, + 0xc6, 0xdd, 0xa9, 0x7b, 0xf2, 0x30, 0xf8, 0xd7, 0x82, 0x82, 0x37, 0xaf, 0xdf, 0x19, 0x45, 0xea, + 0xca, 0x46, 0x5d, 0xe2, 0x07, 0x68, 0x94, 0xb3, 0x8c, 0xcb, 0x0d, 0x0b, 0xf9, 0x32, 0x89, 0xbc, + 0xee, 0xd8, 0x99, 0x8e, 0xa8, 0xdb, 0x70, 0x67, 0x11, 0x3e, 0x45, 0x37, 0x05, 0x94, 0xd6, 0xcb, + 0xeb, 0x99, 0x11, 0xff, 0x63, 0x45, 0xa1, 0xb4, 0x56, 0x43, 0x51, 0x21, 0x3c, 0x43, 0xb7, 0xfe, + 0xf8, 0x14, 0x5c, 0xc8, 0x04, 0x72, 0xaf, 0x3f, 0x76, 0xa6, 0xfb, 0xf4, 0xa0, 0x79, 0x78, 0x6f, + 0xf9, 0xc9, 0x77, 0x07, 0x0d, 0x6b, 0x0d, 0x7c, 0xc7, 0xda, 0x0b, 0x00, 0x25, 0xab, 0x2d, 0x68, + 0x59, 0xaa, 0x63, 0x7c, 0x8c, 0x06, 0x7f, 0xed, 0xc0, 0x6b, 0xaf, 0xda, 0x9e, 0x41, 0x60, 0x5b, + 0xa9, 0xf2, 0xf4, 0x3e, 0xb5, 0x54, 0x35, 0xa8, 0xc1, 0xda, 0x42, 0x2a, 0x26, 0xd4, 0x52, 0x40, + 0x69, 0x26, 0xdc, 0xa7, 0x43, 0x43, 0x50, 0x28, 0xf1, 0x6d, 0x74, 0x83, 0xe7, 0x91, 0x79, 0xb2, + 0xfd, 0x0e, 0x78, 0x1e, 0x51, 0x28, 0x27, 0x1c, 0x0d, 0xeb, 0x9d, 0xe2, 0x43, 0xd4, 0x37, 0x05, + 0xe6, 0x04, 0xfa, 0xd4, 0x06, 0xf8, 0x00, 0x75, 0x79, 0x1e, 0x79, 0x7b, 0x86, 0xd3, 0x50, 0xe7, + 0xe5, 0x10, 0x71, 0xe9, 0x75, 0xcd, 0x20, 0x36, 0xd0, 0xfe, 0x29, 0x67, 0x17, 0xcb, 0x98, 0xc9, + 0xd8, 0xf8, 0x8f, 0xe8, 0x50, 0x13, 0x2f, 0x99, 0x8c, 0x9f, 0x7f, 0xfc, 0xb1, 0xf5, 0x9d, 0xab, + 0xad, 0xef, 0xfc, 0xda, 0xfa, 0xce, 0xd7, 0x9d, 0xdf, 0xb9, 0xda, 0xf9, 0x9d, 0x9f, 0x3b, 0xbf, + 0xf3, 0xe1, 0xc5, 0x3a, 0x51, 0xf1, 0xe5, 0x2a, 0x08, 0x21, 0x23, 0x21, 0xc8, 0x0c, 0xa4, 0xbe, + 0xe7, 0xf9, 0x1a, 0x48, 0xf1, 0x84, 0x64, 0x10, 0x5d, 0xa6, 0x5c, 0xda, 0xeb, 0x9e, 0xd7, 0xe7, + 0x7d, 0xfc, 0x78, 0x5e, 0x7f, 0xd4, 0xb3, 0x1a, 0xac, 0x06, 0xe6, 0xb6, 0x1f, 0xfd, 0x0e, 0x00, + 0x00, 0xff, 0xff, 0xbd, 0xdc, 0x10, 0x6a, 0x8e, 0x03, 0x00, 0x00, +} + +func (m *ClientState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ClientState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BaseClient != nil { + { + size, err := m.BaseClient.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCelestia(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ShareProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShareProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ShareProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NamespaceVersion != 0 { + i = encodeVarintCelestia(dAtA, i, uint64(m.NamespaceVersion)) + i-- + dAtA[i] = 0x28 + } + if m.RowProof != nil { + { + size, err := m.RowProof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCelestia(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.NamespaceId) > 0 { + i -= len(m.NamespaceId) + copy(dAtA[i:], m.NamespaceId) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.NamespaceId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ShareProofs) > 0 { + for iNdEx := len(m.ShareProofs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ShareProofs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCelestia(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Data) > 0 { + for iNdEx := len(m.Data) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Data[iNdEx]) + copy(dAtA[i:], m.Data[iNdEx]) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.Data[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RowProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RowProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RowProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EndRow != 0 { + i = encodeVarintCelestia(dAtA, i, uint64(m.EndRow)) + i-- + dAtA[i] = 0x28 + } + if m.StartRow != 0 { + i = encodeVarintCelestia(dAtA, i, uint64(m.StartRow)) + i-- + dAtA[i] = 0x20 + } + if len(m.Root) > 0 { + i -= len(m.Root) + copy(dAtA[i:], m.Root) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.Root))) + i-- + dAtA[i] = 0x1a + } + if len(m.Proofs) > 0 { + for iNdEx := len(m.Proofs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Proofs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCelestia(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.RowRoots) > 0 { + for iNdEx := len(m.RowRoots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RowRoots[iNdEx]) + copy(dAtA[i:], m.RowRoots[iNdEx]) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.RowRoots[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *NMTProof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NMTProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NMTProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.LeafHash) > 0 { + i -= len(m.LeafHash) + copy(dAtA[i:], m.LeafHash) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.LeafHash))) + i-- + dAtA[i] = 0x22 + } + if len(m.Nodes) > 0 { + for iNdEx := len(m.Nodes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Nodes[iNdEx]) + copy(dAtA[i:], m.Nodes[iNdEx]) + i = encodeVarintCelestia(dAtA, i, uint64(len(m.Nodes[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.End != 0 { + i = encodeVarintCelestia(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x10 + } + if m.Start != 0 { + i = encodeVarintCelestia(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintCelestia(dAtA []byte, offset int, v uint64) int { + offset -= sovCelestia(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ClientState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseClient != nil { + l = m.BaseClient.Size() + n += 1 + l + sovCelestia(uint64(l)) + } + return n +} + +func (m *ShareProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Data) > 0 { + for _, b := range m.Data { + l = len(b) + n += 1 + l + sovCelestia(uint64(l)) + } + } + if len(m.ShareProofs) > 0 { + for _, e := range m.ShareProofs { + l = e.Size() + n += 1 + l + sovCelestia(uint64(l)) + } + } + l = len(m.NamespaceId) + if l > 0 { + n += 1 + l + sovCelestia(uint64(l)) + } + if m.RowProof != nil { + l = m.RowProof.Size() + n += 1 + l + sovCelestia(uint64(l)) + } + if m.NamespaceVersion != 0 { + n += 1 + sovCelestia(uint64(m.NamespaceVersion)) + } + return n +} + +func (m *RowProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RowRoots) > 0 { + for _, b := range m.RowRoots { + l = len(b) + n += 1 + l + sovCelestia(uint64(l)) + } + } + if len(m.Proofs) > 0 { + for _, e := range m.Proofs { + l = e.Size() + n += 1 + l + sovCelestia(uint64(l)) + } + } + l = len(m.Root) + if l > 0 { + n += 1 + l + sovCelestia(uint64(l)) + } + if m.StartRow != 0 { + n += 1 + sovCelestia(uint64(m.StartRow)) + } + if m.EndRow != 0 { + n += 1 + sovCelestia(uint64(m.EndRow)) + } + return n +} + +func (m *NMTProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Start != 0 { + n += 1 + sovCelestia(uint64(m.Start)) + } + if m.End != 0 { + n += 1 + sovCelestia(uint64(m.End)) + } + if len(m.Nodes) > 0 { + for _, b := range m.Nodes { + l = len(b) + n += 1 + l + sovCelestia(uint64(l)) + } + } + l = len(m.LeafHash) + if l > 0 { + n += 1 + l + sovCelestia(uint64(l)) + } + return n +} + +func sovCelestia(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCelestia(x uint64) (n int) { + return sovCelestia(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ClientState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ClientState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ClientState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseClient", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseClient == nil { + m.BaseClient = &_07_tendermint.ClientState{} + } + if err := m.BaseClient.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCelestia(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCelestia + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ShareProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShareProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShareProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data, make([]byte, postIndex-iNdEx)) + copy(m.Data[len(m.Data)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ShareProofs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ShareProofs = append(m.ShareProofs, &NMTProof{}) + if err := m.ShareProofs[len(m.ShareProofs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NamespaceId = append(m.NamespaceId[:0], dAtA[iNdEx:postIndex]...) + if m.NamespaceId == nil { + m.NamespaceId = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RowProof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RowProof == nil { + m.RowProof = &RowProof{} + } + if err := m.RowProof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceVersion", wireType) + } + m.NamespaceVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NamespaceVersion |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCelestia(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCelestia + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RowProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RowProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RowProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RowRoots", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RowRoots = append(m.RowRoots, make([]byte, postIndex-iNdEx)) + copy(m.RowRoots[len(m.RowRoots)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proofs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proofs = append(m.Proofs, &crypto.Proof{}) + if err := m.Proofs[len(m.Proofs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Root", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Root = append(m.Root[:0], dAtA[iNdEx:postIndex]...) + if m.Root == nil { + m.Root = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartRow", wireType) + } + m.StartRow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartRow |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndRow", wireType) + } + m.EndRow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndRow |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCelestia(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCelestia + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NMTProof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NMTProof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NMTProof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) + } + m.End = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.End |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Nodes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Nodes = append(m.Nodes, make([]byte, postIndex-iNdEx)) + copy(m.Nodes[len(m.Nodes)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LeafHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCelestia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCelestia + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCelestia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LeafHash = append(m.LeafHash[:0], dAtA[iNdEx:postIndex]...) + if m.LeafHash == nil { + m.LeafHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCelestia(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCelestia + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCelestia(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCelestia + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCelestia + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCelestia + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCelestia + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCelestia + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCelestia + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCelestia = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCelestia = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCelestia = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/light-clients/07-celestia/client_state.go b/modules/light-clients/07-celestia/client_state.go new file mode 100644 index 00000000000..cb4bee24b41 --- /dev/null +++ b/modules/light-clients/07-celestia/client_state.go @@ -0,0 +1,125 @@ +package celestia + +import ( + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" +) + +var _ exported.ClientState = (*ClientState)(nil) + +// ClientType implements exported.ClientState. +func (*ClientState) ClientType() string { + return ModuleName +} + +// GetLatestHeight implements exported.ClientState. +func (cs *ClientState) GetLatestHeight() exported.Height { + return cs.BaseClient.GetLatestHeight() +} + +// GetTimestampAtHeight implements exported.ClientState. +func (cs *ClientState) GetTimestampAtHeight(ctx sdk.Context, clientStore storetypes.KVStore, cdc codec.BinaryCodec, height exported.Height) (uint64, error) { + return cs.BaseClient.GetTimestampAtHeight(ctx, clientStore, cdc, height) +} + +// Status implements exported.ClientState. +func (cs *ClientState) Status(ctx sdk.Context, clientStore storetypes.KVStore, cdc codec.BinaryCodec) exported.Status { + return cs.BaseClient.Status(ctx, clientStore, cdc) +} + +// Initialize implements exported.ClientState. +func (cs *ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, consensusState exported.ConsensusState) error { + return cs.BaseClient.Initialize(ctx, cdc, clientStore, consensusState) +} + +// Validate implements exported.ClientState. +func (cs *ClientState) Validate() error { + return cs.BaseClient.Validate() +} + +// VerifyMembership implements exported.ClientState. +// TODO: Revise and look into delay periods for this. +// TODO: Validate key path and value against the shareProof extracted from proof bytes. +func (cs *ClientState) VerifyMembership(ctx sdk.Context, clientStore storetypes.KVStore, cdc codec.BinaryCodec, height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, path exported.Path, value []byte) error { + if cs.BaseClient.GetLatestHeight().LT(height) { + return errorsmod.Wrapf( + ibcerrors.ErrInvalidHeight, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + ) + } + + if err := verifyDelayPeriodPassed(ctx, clientStore, height, delayTimePeriod, delayBlockPeriod); err != nil { + return err + } + + var shareProofProto ShareProof + if err := cdc.Unmarshal(proof, &shareProofProto); err != nil { + return err + } + + shareProof, err := shareProofFromProto(&shareProofProto) + if err != nil { + return err + } + + consensusState, found := ibctm.GetConsensusState(clientStore, cdc, height) + if !found { + return errorsmod.Wrap(clienttypes.ErrConsensusStateNotFound, "please ensure the proof was constructed against a height that exists on the client") + } + + return shareProof.Validate(consensusState.GetRoot().GetHash()) +} + +// VerifyNonMembership implements exported.ClientState. +func (*ClientState) VerifyNonMembership(ctx sdk.Context, clientStore storetypes.KVStore, cdc codec.BinaryCodec, height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, path exported.Path) error { + panic("unimplemented") +} + +// verifyDelayPeriodPassed will ensure that at least delayTimePeriod amount of time and delayBlockPeriod number of blocks have passed +// since consensus state was submitted before allowing verification to continue. +func verifyDelayPeriodPassed(ctx sdk.Context, store storetypes.KVStore, proofHeight exported.Height, delayTimePeriod, delayBlockPeriod uint64) error { + if delayTimePeriod != 0 { + // check that executing chain's timestamp has passed consensusState's processed time + delay time period + processedTime, ok := ibctm.GetProcessedTime(store, proofHeight) + if !ok { + return errorsmod.Wrapf(ibctm.ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight) + } + + currentTimestamp := uint64(ctx.BlockTime().UnixNano()) + validTime := processedTime + delayTimePeriod + + // NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error + if currentTimestamp < validTime { + return errorsmod.Wrapf(ibctm.ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d", + validTime, currentTimestamp) + } + + } + + if delayBlockPeriod != 0 { + // check that executing chain's height has passed consensusState's processed height + delay block period + processedHeight, ok := ibctm.GetProcessedHeight(store, proofHeight) + if !ok { + return errorsmod.Wrapf(ibctm.ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight) + } + + currentHeight := clienttypes.GetSelfHeight(ctx) + validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod) + + // NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error + if currentHeight.LT(validHeight) { + return errorsmod.Wrapf(ibctm.ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s", + validHeight, currentHeight) + } + } + + return nil +} diff --git a/modules/light-clients/07-celestia/codec.go b/modules/light-clients/07-celestia/codec.go new file mode 100644 index 00000000000..5f2b85f11ae --- /dev/null +++ b/modules/light-clients/07-celestia/codec.go @@ -0,0 +1,16 @@ +package celestia + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// RegisterInterfaces registers the celestia concrete client-related +// implementations and interfaces. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*exported.ClientState)(nil), + &ClientState{}, + ) +} diff --git a/modules/light-clients/07-celestia/genesis.go b/modules/light-clients/07-celestia/genesis.go new file mode 100644 index 00000000000..8750c71ba88 --- /dev/null +++ b/modules/light-clients/07-celestia/genesis.go @@ -0,0 +1,12 @@ +package celestia + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// ExportMetadata implements exported.ClientState. +func (cs *ClientState) ExportMetadata(clientStore storetypes.KVStore) []exported.GenesisMetadata { + return cs.BaseClient.ExportMetadata(clientStore) +} diff --git a/modules/light-clients/07-celestia/keys.go b/modules/light-clients/07-celestia/keys.go new file mode 100644 index 00000000000..652b7cc3cbf --- /dev/null +++ b/modules/light-clients/07-celestia/keys.go @@ -0,0 +1,5 @@ +package celestia + +const ( + ModuleName = "07-celestia" +) diff --git a/modules/light-clients/07-celestia/module.go b/modules/light-clients/07-celestia/module.go new file mode 100644 index 00000000000..db618a57dd0 --- /dev/null +++ b/modules/light-clients/07-celestia/module.go @@ -0,0 +1,84 @@ +package celestia + +import ( + "encoding/json" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "cosmossdk.io/core/appmodule" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +var ( + _ module.AppModuleBasic = (*AppModuleBasic)(nil) + _ appmodule.AppModule = (*AppModule)(nil) +) + +// AppModuleBasic defines the basic application module used by the celestia light client. +// Only the RegisterInterfaces function needs to be implemented. All other function perform +// a no-op. +type AppModuleBasic struct{} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (AppModuleBasic) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (AppModuleBasic) IsAppModule() {} + +// Name returns the celestia module name. +func (AppModuleBasic) Name() string { + return ModuleName +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (AppModule) IsAppModule() {} + +// RegisterLegacyAminoCodec performs a no-op. The celestia client does not support amino. +func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} + +// RegisterInterfaces registers module concrete types into protobuf Any. This allows core IBC +// to unmarshal celestia light client types. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + RegisterInterfaces(registry) +} + +// DefaultGenesis performs a no-op. Genesis is not supported for the celestia light client. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return nil +} + +// ValidateGenesis performs a no-op. Genesis is not supported for the celestia light client. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + return nil +} + +// RegisterGRPCGatewayRoutes performs a no-op. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {} + +// GetTxCmd performs a no-op. Please see the 02-client cli commands. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +// GetQueryCmd performs a no-op. Please see the 02-client cli commands. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return nil +} + +// AppModule is the application module for the celestia client module +type AppModule struct { + AppModuleBasic +} + +// NewAppModule creates a new celestia client module +func NewAppModule() AppModule { + return AppModule{} +} diff --git a/modules/light-clients/07-celestia/row_proof.go b/modules/light-clients/07-celestia/row_proof.go new file mode 100644 index 00000000000..50ae7f2e12d --- /dev/null +++ b/modules/light-clients/07-celestia/row_proof.go @@ -0,0 +1,75 @@ +package celestia + +import ( + "errors" + "fmt" + + "github.com/cometbft/cometbft/crypto/merkle" + tmbytes "github.com/cometbft/cometbft/libs/bytes" +) + +// RowProof is a Merkle proof that a set of rows exist in a Merkle tree with a +// given data root. +type rowProof struct { + // RowRoots are the roots of the rows being proven. + RowRoots []tmbytes.HexBytes `json:"row_roots"` + // Proofs is a list of Merkle proofs where each proof proves that a row + // exists in a Merkle tree with a given data root. + Proofs []*merkle.Proof `json:"proofs"` + StartRow uint32 `json:"start_row"` + EndRow uint32 `json:"end_row"` +} + +// Validate performs checks on the fields of this RowProof. Returns an error if +// the proof fails validation. If the proof passes validation, this function +// attempts to verify the proof. It returns nil if the proof is valid. +func (rp rowProof) Validate(root []byte) error { + // HACKHACK performing subtraction with unsigned integers is unsafe. + if int(rp.EndRow-rp.StartRow+1) != len(rp.RowRoots) { + return fmt.Errorf("the number of rows %d must equal the number of row roots %d", int(rp.EndRow-rp.StartRow+1), len(rp.RowRoots)) + } + if len(rp.Proofs) != len(rp.RowRoots) { + return fmt.Errorf("the number of proofs %d must equal the number of row roots %d", len(rp.Proofs), len(rp.RowRoots)) + } + if !rp.VerifyProof(root) { + return errors.New("row proof failed to verify") + } + + return nil +} + +// VerifyProof verifies that all the row roots in this RowProof exist in a +// Merkle tree with the given root. Returns true if all proofs are valid. +func (rp rowProof) VerifyProof(root []byte) bool { + for i, proof := range rp.Proofs { + err := proof.Verify(root, rp.RowRoots[i]) + if err != nil { + return false + } + } + return true +} + +func rowProofFromProto(p *RowProof) rowProof { + if p == nil { + return rowProof{} + } + rowRoots := make([]tmbytes.HexBytes, len(p.RowRoots)) + rowProofs := make([]*merkle.Proof, len(p.Proofs)) + for i := range p.Proofs { + rowRoots[i] = p.RowRoots[i] + rowProofs[i] = &merkle.Proof{ + Total: p.Proofs[i].Total, + Index: p.Proofs[i].Index, + LeafHash: p.Proofs[i].LeafHash, + Aunts: p.Proofs[i].Aunts, + } + } + + return rowProof{ + RowRoots: rowRoots, + Proofs: rowProofs, + StartRow: p.StartRow, + EndRow: p.EndRow, + } +} diff --git a/modules/light-clients/07-celestia/share_proof.go b/modules/light-clients/07-celestia/share_proof.go new file mode 100644 index 00000000000..9aa0483b142 --- /dev/null +++ b/modules/light-clients/07-celestia/share_proof.go @@ -0,0 +1,136 @@ +package celestia + +import ( + "crypto/sha256" + "errors" + "fmt" + "math" + + "github.com/celestiaorg/nmt" + + "github.com/cometbft/cometbft/proto/tendermint/crypto" +) + +// ShareProof is an NMT proof that a set of shares exist in a set of rows and a +// Merkle proof that those rows exist in a Merkle tree with a given data root. +type shareProof struct { + // Data are the raw shares that are being proven. + Data [][]byte `json:"data"` + // ShareProofs are NMT proofs that the shares in Data exist in a set of + // rows. There will be one ShareProof per row that the shares occupy. + ShareProofs []*NMTProof `json:"share_proofs"` + // NamespaceID is the namespace id of the shares being proven. This + // namespace id is used when verifying the proof. If the namespace id doesn't + // match the namespace of the shares, the proof will fail verification. + NamespaceID []byte `json:"namespace_id"` + RowProof rowProof `json:"row_proof"` + NamespaceVersion uint32 `json:"namespace_version"` +} + +func (sp shareProof) ToProto() ShareProof { + // TODO consider extracting a ToProto function for RowProof + rowRoots := make([][]byte, len(sp.RowProof.RowRoots)) + rowProofs := make([]*crypto.Proof, len(sp.RowProof.Proofs)) + for i := range sp.RowProof.RowRoots { + rowRoots[i] = sp.RowProof.RowRoots[i].Bytes() + rowProofs[i] = sp.RowProof.Proofs[i].ToProto() + } + pbtp := ShareProof{ + Data: sp.Data, + ShareProofs: sp.ShareProofs, + NamespaceId: sp.NamespaceID, + RowProof: &RowProof{ + RowRoots: rowRoots, + Proofs: rowProofs, + StartRow: sp.RowProof.StartRow, + EndRow: sp.RowProof.EndRow, + }, + NamespaceVersion: sp.NamespaceVersion, + } + + return pbtp +} + +// shareProofFromProto creates a ShareProof from a proto message. +// Expects the proof to be pre-validated. +func shareProofFromProto(pb *ShareProof) (shareProof, error) { + if pb == nil { + return shareProof{}, fmt.Errorf("nil share proof protobuf") + } + + return shareProof{ + RowProof: rowProofFromProto(pb.RowProof), + Data: pb.Data, + ShareProofs: pb.ShareProofs, + NamespaceID: pb.NamespaceId, + NamespaceVersion: pb.NamespaceVersion, + }, nil +} + +// Validate runs basic validations on the proof then verifies if it is consistent. +// It returns nil if the proof is valid. Otherwise, it returns a sensible error. +// The `root` is the block data root that the shares to be proven belong to. +// Note: these proofs are tested on the app side. +func (sp shareProof) Validate(root []byte) error { + numberOfSharesInProofs := int32(0) + for _, proof := range sp.ShareProofs { + // the range is not inclusive from the left. + numberOfSharesInProofs += proof.End - proof.Start + } + + if len(sp.ShareProofs) != len(sp.RowProof.RowRoots) { + return fmt.Errorf("the number of share proofs %d must equal the number of row roots %d", len(sp.ShareProofs), len(sp.RowProof.RowRoots)) + } + if len(sp.Data) != int(numberOfSharesInProofs) { + return fmt.Errorf("the number of shares %d must equal the number of shares in share proofs %d", len(sp.Data), numberOfSharesInProofs) + } + + for _, proof := range sp.ShareProofs { + if proof.Start < 0 { + return errors.New("proof index cannot be negative") + } + if (proof.End - proof.Start) <= 0 { + return errors.New("proof total must be positive") + } + } + + if err := sp.RowProof.Validate(root); err != nil { + return err + } + + if ok := sp.VerifyProof(); !ok { + return errors.New("share proof failed to verify") + } + + return nil +} + +func (sp shareProof) VerifyProof() bool { + cursor := int32(0) + for i, proof := range sp.ShareProofs { + nmtProof := nmt.NewInclusionProof( + int(proof.Start), + int(proof.End), + proof.Nodes, + true, + ) + sharesUsed := proof.End - proof.Start + if sp.NamespaceVersion > math.MaxUint8 { + return false + } + // Consider extracting celestia-app's namespace package. We can't use it + // here because that would introduce a circulcar import. + namespace := append([]byte{uint8(sp.NamespaceVersion)}, sp.NamespaceID...) + valid := nmtProof.VerifyInclusion( + sha256.New(), + namespace, + sp.Data[cursor:sharesUsed+cursor], + sp.RowProof.RowRoots[i], + ) + if !valid { + return false + } + cursor += sharesUsed + } + return true +} diff --git a/modules/light-clients/07-celestia/update.go b/modules/light-clients/07-celestia/update.go new file mode 100644 index 00000000000..9010382a46f --- /dev/null +++ b/modules/light-clients/07-celestia/update.go @@ -0,0 +1,60 @@ +package celestia + +import ( + fmt "fmt" + + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" +) + +// VerifyClientMessage implements exported.ClientState. +func (cs *ClientState) VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg exported.ClientMessage) error { + return cs.BaseClient.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) +} + +// UpdateState implements exported.ClientState. +func (cs *ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg exported.ClientMessage) []exported.Height { + header, ok := clientMsg.(*ibctm.Header) + if !ok { + panic(fmt.Errorf("expected type %T, got %T", &ibctm.Header{}, clientMsg)) + } + + // perform regular 07-tendermint client update step + heights := cs.BaseClient.UpdateState(ctx, cdc, clientStore, clientMsg) + + // overwrite the consensus state with a new consensus state containing the data hash as commitment root + consensusState := &ibctm.ConsensusState{ + Timestamp: header.GetTime(), + Root: commitmenttypes.NewMerkleRoot(header.Header.GetDataHash()), + NextValidatorsHash: header.Header.NextValidatorsHash, + } + + setConsensusState(clientStore, cdc, consensusState, header.GetHeight()) + + return heights +} + +// setConsensusState stores the consensus state at the given height. +func setConsensusState(clientStore storetypes.KVStore, cdc codec.BinaryCodec, consensusState *ibctm.ConsensusState, height exported.Height) { + key := host.ConsensusStateKey(height) + val := clienttypes.MustMarshalConsensusState(cdc, consensusState) + clientStore.Set(key, val) +} + +// CheckForMisbehaviour implements exported.ClientState. +func (cs *ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg exported.ClientMessage) bool { + return cs.BaseClient.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) +} + +// UpdateStateOnMisbehaviour implements exported.ClientState. +func (cs *ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg exported.ClientMessage) { + cs.BaseClient.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) +} diff --git a/modules/light-clients/07-celestia/upgrade.go b/modules/light-clients/07-celestia/upgrade.go new file mode 100644 index 00000000000..ab0981f1cac --- /dev/null +++ b/modules/light-clients/07-celestia/upgrade.go @@ -0,0 +1,25 @@ +package celestia + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// CheckSubstituteAndUpdateState implements exported.ClientState. +func (cs *ClientState) CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore storetypes.KVStore, substituteClientStore storetypes.KVStore, substituteClient exported.ClientState) error { + return cs.BaseClient.CheckSubstituteAndUpdateState(ctx, cdc, subjectClientStore, subjectClientStore, substituteClient) +} + +// VerifyUpgradeAndUpdateState implements exported.ClientState. +func (*ClientState) VerifyUpgradeAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, store storetypes.KVStore, newClient exported.ClientState, newConsState exported.ConsensusState, upgradeClientProof []byte, upgradeConsensusStateProof []byte) error { + panic("unimplemented") +} + +// ZeroCustomFields implements exported.ClientState. +func (*ClientState) ZeroCustomFields() exported.ClientState { + panic("unimplemented") +} diff --git a/proto/ibc/lightclients/celestia/v1/celestia.proto b/proto/ibc/lightclients/celestia/v1/celestia.proto new file mode 100644 index 00000000000..c608b9ef531 --- /dev/null +++ b/proto/ibc/lightclients/celestia/v1/celestia.proto @@ -0,0 +1,59 @@ +syntax = "proto3"; + +package ibc.lightclients.celestia.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/07-celestia;celestia"; + +import "tendermint/crypto/proof.proto"; +import "gogoproto/gogo.proto"; +import "ibc/lightclients/tendermint/v1/tendermint.proto"; + +// ClientState from Tendermint tracks the current validator set, latest height, +// and a possible frozen height. +message ClientState { + option (gogoproto.goproto_getters) = false; + + ibc.lightclients.tendermint.v1.ClientState base_client = 1; +} + +// ShareProof is an NMT proof that a set of shares exist in a set of rows and a +// Merkle proof that those rows exist in a Merkle tree with a given data root. +message ShareProof { + repeated bytes data = 1; + repeated NMTProof share_proofs = 2; + bytes namespace_id = 3; + RowProof row_proof = 4; + uint32 namespace_version = 5; +} + +// RowProof is a Merkle proof that a set of rows exist in a Merkle tree with a +// given data root. +message RowProof { + repeated bytes row_roots = 1; + repeated .tendermint.crypto.Proof proofs = 2; + bytes root = 3; + uint32 start_row = 4; + uint32 end_row = 5; +} + +// NMTProof is a proof of a namespace.ID in an NMT. +// In case this proof proves the absence of a namespace.ID +// in a tree it also contains the leaf hashes of the range +// where that namespace would be. +message NMTProof { + // Start index of this proof. + int32 start = 1; + // End index of this proof. + int32 end = 2; + // Nodes that together with the corresponding leaf values can be used to + // recompute the root and verify this proof. Nodes should consist of the max + // and min namespaces along with the actual hash, resulting in each being 48 + // bytes each + repeated bytes nodes = 3; + // leafHash are nil if the namespace is present in the NMT. In case the + // namespace to be proved is in the min/max range of the tree but absent, this + // will contain the leaf hash necessary to verify the proof of absence. Leaf + // hashes should consist of the namespace along with the actual hash, + // resulting 40 bytes total. + bytes leaf_hash = 4; +} \ No newline at end of file