diff --git a/api/cosmos/store/v2/commit_info.pulsar.go b/api/cosmos/store/v2/commit_info.pulsar.go new file mode 100644 index 000000000000..572f80f0be48 --- /dev/null +++ b/api/cosmos/store/v2/commit_info.pulsar.go @@ -0,0 +1,2048 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package storev2 + +import ( + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" +) + +var _ protoreflect.List = (*_CommitInfo_2_list)(nil) + +type _CommitInfo_2_list struct { + list *[]*StoreInfo +} + +func (x *_CommitInfo_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_CommitInfo_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_CommitInfo_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*StoreInfo) + (*x.list)[i] = concreteValue +} + +func (x *_CommitInfo_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*StoreInfo) + *x.list = append(*x.list, concreteValue) +} + +func (x *_CommitInfo_2_list) AppendMutable() protoreflect.Value { + v := new(StoreInfo) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_CommitInfo_2_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_CommitInfo_2_list) NewElement() protoreflect.Value { + v := new(StoreInfo) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_CommitInfo_2_list) IsValid() bool { + return x.list != nil +} + +var ( + md_CommitInfo protoreflect.MessageDescriptor + fd_CommitInfo_version protoreflect.FieldDescriptor + fd_CommitInfo_store_infos protoreflect.FieldDescriptor + fd_CommitInfo_timestamp protoreflect.FieldDescriptor + fd_CommitInfo_commit_hash protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_store_v2_commit_info_proto_init() + md_CommitInfo = File_cosmos_store_v2_commit_info_proto.Messages().ByName("CommitInfo") + fd_CommitInfo_version = md_CommitInfo.Fields().ByName("version") + fd_CommitInfo_store_infos = md_CommitInfo.Fields().ByName("store_infos") + fd_CommitInfo_timestamp = md_CommitInfo.Fields().ByName("timestamp") + fd_CommitInfo_commit_hash = md_CommitInfo.Fields().ByName("commit_hash") +} + +var _ protoreflect.Message = (*fastReflection_CommitInfo)(nil) + +type fastReflection_CommitInfo CommitInfo + +func (x *CommitInfo) ProtoReflect() protoreflect.Message { + return (*fastReflection_CommitInfo)(x) +} + +func (x *CommitInfo) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_CommitInfo_messageType fastReflection_CommitInfo_messageType +var _ protoreflect.MessageType = fastReflection_CommitInfo_messageType{} + +type fastReflection_CommitInfo_messageType struct{} + +func (x fastReflection_CommitInfo_messageType) Zero() protoreflect.Message { + return (*fastReflection_CommitInfo)(nil) +} +func (x fastReflection_CommitInfo_messageType) New() protoreflect.Message { + return new(fastReflection_CommitInfo) +} +func (x fastReflection_CommitInfo_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_CommitInfo +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_CommitInfo) Descriptor() protoreflect.MessageDescriptor { + return md_CommitInfo +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_CommitInfo) Type() protoreflect.MessageType { + return _fastReflection_CommitInfo_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_CommitInfo) New() protoreflect.Message { + return new(fastReflection_CommitInfo) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_CommitInfo) Interface() protoreflect.ProtoMessage { + return (*CommitInfo)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_CommitInfo) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Version != int64(0) { + value := protoreflect.ValueOfInt64(x.Version) + if !f(fd_CommitInfo_version, value) { + return + } + } + if len(x.StoreInfos) != 0 { + value := protoreflect.ValueOfList(&_CommitInfo_2_list{list: &x.StoreInfos}) + if !f(fd_CommitInfo_store_infos, value) { + return + } + } + if x.Timestamp != nil { + value := protoreflect.ValueOfMessage(x.Timestamp.ProtoReflect()) + if !f(fd_CommitInfo_timestamp, value) { + return + } + } + if len(x.CommitHash) != 0 { + value := protoreflect.ValueOfBytes(x.CommitHash) + if !f(fd_CommitInfo_commit_hash, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_CommitInfo) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.store.v2.CommitInfo.version": + return x.Version != int64(0) + case "cosmos.store.v2.CommitInfo.store_infos": + return len(x.StoreInfos) != 0 + case "cosmos.store.v2.CommitInfo.timestamp": + return x.Timestamp != nil + case "cosmos.store.v2.CommitInfo.commit_hash": + return len(x.CommitHash) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitInfo) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.store.v2.CommitInfo.version": + x.Version = int64(0) + case "cosmos.store.v2.CommitInfo.store_infos": + x.StoreInfos = nil + case "cosmos.store.v2.CommitInfo.timestamp": + x.Timestamp = nil + case "cosmos.store.v2.CommitInfo.commit_hash": + x.CommitHash = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_CommitInfo) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.store.v2.CommitInfo.version": + value := x.Version + return protoreflect.ValueOfInt64(value) + case "cosmos.store.v2.CommitInfo.store_infos": + if len(x.StoreInfos) == 0 { + return protoreflect.ValueOfList(&_CommitInfo_2_list{}) + } + listValue := &_CommitInfo_2_list{list: &x.StoreInfos} + return protoreflect.ValueOfList(listValue) + case "cosmos.store.v2.CommitInfo.timestamp": + value := x.Timestamp + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "cosmos.store.v2.CommitInfo.commit_hash": + value := x.CommitHash + return protoreflect.ValueOfBytes(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitInfo) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.store.v2.CommitInfo.version": + x.Version = value.Int() + case "cosmos.store.v2.CommitInfo.store_infos": + lv := value.List() + clv := lv.(*_CommitInfo_2_list) + x.StoreInfos = *clv.list + case "cosmos.store.v2.CommitInfo.timestamp": + x.Timestamp = value.Message().Interface().(*timestamppb.Timestamp) + case "cosmos.store.v2.CommitInfo.commit_hash": + x.CommitHash = value.Bytes() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitInfo) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.CommitInfo.store_infos": + if x.StoreInfos == nil { + x.StoreInfos = []*StoreInfo{} + } + value := &_CommitInfo_2_list{list: &x.StoreInfos} + return protoreflect.ValueOfList(value) + case "cosmos.store.v2.CommitInfo.timestamp": + if x.Timestamp == nil { + x.Timestamp = new(timestamppb.Timestamp) + } + return protoreflect.ValueOfMessage(x.Timestamp.ProtoReflect()) + case "cosmos.store.v2.CommitInfo.version": + panic(fmt.Errorf("field version of message cosmos.store.v2.CommitInfo is not mutable")) + case "cosmos.store.v2.CommitInfo.commit_hash": + panic(fmt.Errorf("field commit_hash of message cosmos.store.v2.CommitInfo is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_CommitInfo) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.CommitInfo.version": + return protoreflect.ValueOfInt64(int64(0)) + case "cosmos.store.v2.CommitInfo.store_infos": + list := []*StoreInfo{} + return protoreflect.ValueOfList(&_CommitInfo_2_list{list: &list}) + case "cosmos.store.v2.CommitInfo.timestamp": + m := new(timestamppb.Timestamp) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "cosmos.store.v2.CommitInfo.commit_hash": + return protoreflect.ValueOfBytes(nil) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitInfo does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_CommitInfo) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.store.v2.CommitInfo", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_CommitInfo) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitInfo) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_CommitInfo) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_CommitInfo) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*CommitInfo) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Version != 0 { + n += 1 + runtime.Sov(uint64(x.Version)) + } + if len(x.StoreInfos) > 0 { + for _, e := range x.StoreInfos { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.Timestamp != nil { + l = options.Size(x.Timestamp) + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.CommitHash) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*CommitInfo) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.CommitHash) > 0 { + i -= len(x.CommitHash) + copy(dAtA[i:], x.CommitHash) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.CommitHash))) + i-- + dAtA[i] = 0x22 + } + if x.Timestamp != nil { + encoded, err := options.Marshal(x.Timestamp) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x1a + } + if len(x.StoreInfos) > 0 { + for iNdEx := len(x.StoreInfos) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.StoreInfos[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + } + if x.Version != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Version)) + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*CommitInfo) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, 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 protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: CommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: CommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + x.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field StoreInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.StoreInfos = append(x.StoreInfos, &StoreInfo{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.StoreInfos[len(x.StoreInfos)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.Timestamp == nil { + x.Timestamp = ×tamppb.Timestamp{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Timestamp); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CommitHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.CommitHash = append(x.CommitHash[:0], dAtA[iNdEx:postIndex]...) + if x.CommitHash == nil { + x.CommitHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_StoreInfo protoreflect.MessageDescriptor + fd_StoreInfo_name protoreflect.FieldDescriptor + fd_StoreInfo_commit_id protoreflect.FieldDescriptor + fd_StoreInfo_structure protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_store_v2_commit_info_proto_init() + md_StoreInfo = File_cosmos_store_v2_commit_info_proto.Messages().ByName("StoreInfo") + fd_StoreInfo_name = md_StoreInfo.Fields().ByName("name") + fd_StoreInfo_commit_id = md_StoreInfo.Fields().ByName("commit_id") + fd_StoreInfo_structure = md_StoreInfo.Fields().ByName("structure") +} + +var _ protoreflect.Message = (*fastReflection_StoreInfo)(nil) + +type fastReflection_StoreInfo StoreInfo + +func (x *StoreInfo) ProtoReflect() protoreflect.Message { + return (*fastReflection_StoreInfo)(x) +} + +func (x *StoreInfo) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_StoreInfo_messageType fastReflection_StoreInfo_messageType +var _ protoreflect.MessageType = fastReflection_StoreInfo_messageType{} + +type fastReflection_StoreInfo_messageType struct{} + +func (x fastReflection_StoreInfo_messageType) Zero() protoreflect.Message { + return (*fastReflection_StoreInfo)(nil) +} +func (x fastReflection_StoreInfo_messageType) New() protoreflect.Message { + return new(fastReflection_StoreInfo) +} +func (x fastReflection_StoreInfo_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_StoreInfo +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_StoreInfo) Descriptor() protoreflect.MessageDescriptor { + return md_StoreInfo +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_StoreInfo) Type() protoreflect.MessageType { + return _fastReflection_StoreInfo_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_StoreInfo) New() protoreflect.Message { + return new(fastReflection_StoreInfo) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_StoreInfo) Interface() protoreflect.ProtoMessage { + return (*StoreInfo)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_StoreInfo) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Name != "" { + value := protoreflect.ValueOfString(x.Name) + if !f(fd_StoreInfo_name, value) { + return + } + } + if x.CommitId != nil { + value := protoreflect.ValueOfMessage(x.CommitId.ProtoReflect()) + if !f(fd_StoreInfo_commit_id, value) { + return + } + } + if x.Structure != "" { + value := protoreflect.ValueOfString(x.Structure) + if !f(fd_StoreInfo_structure, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_StoreInfo) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.store.v2.StoreInfo.name": + return x.Name != "" + case "cosmos.store.v2.StoreInfo.commit_id": + return x.CommitId != nil + case "cosmos.store.v2.StoreInfo.structure": + return x.Structure != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_StoreInfo) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.store.v2.StoreInfo.name": + x.Name = "" + case "cosmos.store.v2.StoreInfo.commit_id": + x.CommitId = nil + case "cosmos.store.v2.StoreInfo.structure": + x.Structure = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_StoreInfo) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.store.v2.StoreInfo.name": + value := x.Name + return protoreflect.ValueOfString(value) + case "cosmos.store.v2.StoreInfo.commit_id": + value := x.CommitId + return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "cosmos.store.v2.StoreInfo.structure": + value := x.Structure + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_StoreInfo) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.store.v2.StoreInfo.name": + x.Name = value.Interface().(string) + case "cosmos.store.v2.StoreInfo.commit_id": + x.CommitId = value.Message().Interface().(*CommitID) + case "cosmos.store.v2.StoreInfo.structure": + x.Structure = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_StoreInfo) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.StoreInfo.commit_id": + if x.CommitId == nil { + x.CommitId = new(CommitID) + } + return protoreflect.ValueOfMessage(x.CommitId.ProtoReflect()) + case "cosmos.store.v2.StoreInfo.name": + panic(fmt.Errorf("field name of message cosmos.store.v2.StoreInfo is not mutable")) + case "cosmos.store.v2.StoreInfo.structure": + panic(fmt.Errorf("field structure of message cosmos.store.v2.StoreInfo is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_StoreInfo) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.StoreInfo.name": + return protoreflect.ValueOfString("") + case "cosmos.store.v2.StoreInfo.commit_id": + m := new(CommitID) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "cosmos.store.v2.StoreInfo.structure": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.StoreInfo")) + } + panic(fmt.Errorf("message cosmos.store.v2.StoreInfo does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_StoreInfo) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.store.v2.StoreInfo", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_StoreInfo) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_StoreInfo) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_StoreInfo) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_StoreInfo) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*StoreInfo) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Name) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.CommitId != nil { + l = options.Size(x.CommitId) + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Structure) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*StoreInfo) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Structure) > 0 { + i -= len(x.Structure) + copy(dAtA[i:], x.Structure) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Structure))) + i-- + dAtA[i] = 0x1a + } + if x.CommitId != nil { + encoded, err := options.Marshal(x.CommitId) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Name) > 0 { + i -= len(x.Name) + copy(dAtA[i:], x.Name) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Name))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*StoreInfo) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, 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 protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: StoreInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: StoreInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field CommitId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.CommitId == nil { + x.CommitId = &CommitID{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.CommitId); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Structure", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Structure = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_CommitID protoreflect.MessageDescriptor + fd_CommitID_version protoreflect.FieldDescriptor + fd_CommitID_hash protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_store_v2_commit_info_proto_init() + md_CommitID = File_cosmos_store_v2_commit_info_proto.Messages().ByName("CommitID") + fd_CommitID_version = md_CommitID.Fields().ByName("version") + fd_CommitID_hash = md_CommitID.Fields().ByName("hash") +} + +var _ protoreflect.Message = (*fastReflection_CommitID)(nil) + +type fastReflection_CommitID CommitID + +func (x *CommitID) ProtoReflect() protoreflect.Message { + return (*fastReflection_CommitID)(x) +} + +func (x *CommitID) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_CommitID_messageType fastReflection_CommitID_messageType +var _ protoreflect.MessageType = fastReflection_CommitID_messageType{} + +type fastReflection_CommitID_messageType struct{} + +func (x fastReflection_CommitID_messageType) Zero() protoreflect.Message { + return (*fastReflection_CommitID)(nil) +} +func (x fastReflection_CommitID_messageType) New() protoreflect.Message { + return new(fastReflection_CommitID) +} +func (x fastReflection_CommitID_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_CommitID +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_CommitID) Descriptor() protoreflect.MessageDescriptor { + return md_CommitID +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_CommitID) Type() protoreflect.MessageType { + return _fastReflection_CommitID_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_CommitID) New() protoreflect.Message { + return new(fastReflection_CommitID) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_CommitID) Interface() protoreflect.ProtoMessage { + return (*CommitID)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_CommitID) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Version != int64(0) { + value := protoreflect.ValueOfInt64(x.Version) + if !f(fd_CommitID_version, value) { + return + } + } + if len(x.Hash) != 0 { + value := protoreflect.ValueOfBytes(x.Hash) + if !f(fd_CommitID_hash, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_CommitID) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.store.v2.CommitID.version": + return x.Version != int64(0) + case "cosmos.store.v2.CommitID.hash": + return len(x.Hash) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitID) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.store.v2.CommitID.version": + x.Version = int64(0) + case "cosmos.store.v2.CommitID.hash": + x.Hash = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_CommitID) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.store.v2.CommitID.version": + value := x.Version + return protoreflect.ValueOfInt64(value) + case "cosmos.store.v2.CommitID.hash": + value := x.Hash + return protoreflect.ValueOfBytes(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitID) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.store.v2.CommitID.version": + x.Version = value.Int() + case "cosmos.store.v2.CommitID.hash": + x.Hash = value.Bytes() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitID) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.CommitID.version": + panic(fmt.Errorf("field version of message cosmos.store.v2.CommitID is not mutable")) + case "cosmos.store.v2.CommitID.hash": + panic(fmt.Errorf("field hash of message cosmos.store.v2.CommitID is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_CommitID) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.store.v2.CommitID.version": + return protoreflect.ValueOfInt64(int64(0)) + case "cosmos.store.v2.CommitID.hash": + return protoreflect.ValueOfBytes(nil) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.store.v2.CommitID")) + } + panic(fmt.Errorf("message cosmos.store.v2.CommitID does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_CommitID) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.store.v2.CommitID", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_CommitID) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_CommitID) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_CommitID) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_CommitID) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*CommitID) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Version != 0 { + n += 1 + runtime.Sov(uint64(x.Version)) + } + l = len(x.Hash) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*CommitID) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Hash) > 0 { + i -= len(x.Hash) + copy(dAtA[i:], x.Hash) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Hash))) + i-- + dAtA[i] = 0x12 + } + if x.Version != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Version)) + i-- + dAtA[i] = 0x8 + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*CommitID) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, 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 protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: CommitID: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: CommitID: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + x.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Hash = append(x.Hash[:0], dAtA[iNdEx:postIndex]...) + if x.Hash == nil { + x.Hash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: cosmos/store/v2/commit_info.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// CommitInfo defines commit information used by the multi-store when committing +// a version/height. +type CommitInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + StoreInfos []*StoreInfo `protobuf:"bytes,2,rep,name=store_infos,json=storeInfos,proto3" json:"store_infos,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + CommitHash []byte `protobuf:"bytes,4,opt,name=commit_hash,json=commitHash,proto3" json:"commit_hash,omitempty"` +} + +func (x *CommitInfo) Reset() { + *x = CommitInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommitInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitInfo) ProtoMessage() {} + +// Deprecated: Use CommitInfo.ProtoReflect.Descriptor instead. +func (*CommitInfo) Descriptor() ([]byte, []int) { + return file_cosmos_store_v2_commit_info_proto_rawDescGZIP(), []int{0} +} + +func (x *CommitInfo) GetVersion() int64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *CommitInfo) GetStoreInfos() []*StoreInfo { + if x != nil { + return x.StoreInfos + } + return nil +} + +func (x *CommitInfo) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *CommitInfo) GetCommitHash() []byte { + if x != nil { + return x.CommitHash + } + return nil +} + +// StoreInfo defines store-specific commit information. It contains a reference +// between a store name and the commit ID. +type StoreInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + CommitId *CommitID `protobuf:"bytes,2,opt,name=commit_id,json=commitId,proto3" json:"commit_id,omitempty"` + Structure string `protobuf:"bytes,3,opt,name=structure,proto3" json:"structure,omitempty"` +} + +func (x *StoreInfo) Reset() { + *x = StoreInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StoreInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreInfo) ProtoMessage() {} + +// Deprecated: Use StoreInfo.ProtoReflect.Descriptor instead. +func (*StoreInfo) Descriptor() ([]byte, []int) { + return file_cosmos_store_v2_commit_info_proto_rawDescGZIP(), []int{1} +} + +func (x *StoreInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StoreInfo) GetCommitId() *CommitID { + if x != nil { + return x.CommitId + } + return nil +} + +func (x *StoreInfo) GetStructure() string { + if x != nil { + return x.Structure + } + return "" +} + +// CommitID defines the commitment information when a specific store is +// committed. +type CommitID struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *CommitID) Reset() { + *x = CommitID{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_store_v2_commit_info_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommitID) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitID) ProtoMessage() {} + +// Deprecated: Use CommitID.ProtoReflect.Descriptor instead. +func (*CommitID) Descriptor() ([]byte, []int) { + return file_cosmos_store_v2_commit_info_proto_rawDescGZIP(), []int{2} +} + +func (x *CommitID) GetVersion() int64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *CommitID) GetHash() []byte { + if x != nil { + return x.Hash + } + return nil +} + +var File_cosmos_store_v2_commit_info_proto protoreflect.FileDescriptor + +var file_cosmos_store_v2_commit_info_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, + 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2e, 0x76, 0x32, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc8, 0x01, 0x0a, 0x0a, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x73, 0x12, 0x42, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x42, 0x08, 0xc8, 0xde, 0x1f, 0x00, 0x90, 0xdf, 0x1f, 0x01, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x75, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x49, 0x44, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x49, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3e, 0x0a, + 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x3a, 0x04, 0x98, 0xa0, 0x1f, 0x00, 0x42, 0xae, 0x01, + 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x76, 0x32, 0x42, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x32, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x76, 0x32, 0xa2, 0x02, 0x03, 0x43, 0x53, 0x58, 0xaa, 0x02, 0x0f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0f, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x1b, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x56, 0x32, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_cosmos_store_v2_commit_info_proto_rawDescOnce sync.Once + file_cosmos_store_v2_commit_info_proto_rawDescData = file_cosmos_store_v2_commit_info_proto_rawDesc +) + +func file_cosmos_store_v2_commit_info_proto_rawDescGZIP() []byte { + file_cosmos_store_v2_commit_info_proto_rawDescOnce.Do(func() { + file_cosmos_store_v2_commit_info_proto_rawDescData = protoimpl.X.CompressGZIP(file_cosmos_store_v2_commit_info_proto_rawDescData) + }) + return file_cosmos_store_v2_commit_info_proto_rawDescData +} + +var file_cosmos_store_v2_commit_info_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_cosmos_store_v2_commit_info_proto_goTypes = []interface{}{ + (*CommitInfo)(nil), // 0: cosmos.store.v2.CommitInfo + (*StoreInfo)(nil), // 1: cosmos.store.v2.StoreInfo + (*CommitID)(nil), // 2: cosmos.store.v2.CommitID + (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp +} +var file_cosmos_store_v2_commit_info_proto_depIdxs = []int32{ + 1, // 0: cosmos.store.v2.CommitInfo.store_infos:type_name -> cosmos.store.v2.StoreInfo + 3, // 1: cosmos.store.v2.CommitInfo.timestamp:type_name -> google.protobuf.Timestamp + 2, // 2: cosmos.store.v2.StoreInfo.commit_id:type_name -> cosmos.store.v2.CommitID + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_cosmos_store_v2_commit_info_proto_init() } +func file_cosmos_store_v2_commit_info_proto_init() { + if File_cosmos_store_v2_commit_info_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_cosmos_store_v2_commit_info_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommitInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_store_v2_commit_info_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StoreInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_store_v2_commit_info_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommitID); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_cosmos_store_v2_commit_info_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_cosmos_store_v2_commit_info_proto_goTypes, + DependencyIndexes: file_cosmos_store_v2_commit_info_proto_depIdxs, + MessageInfos: file_cosmos_store_v2_commit_info_proto_msgTypes, + }.Build() + File_cosmos_store_v2_commit_info_proto = out.File + file_cosmos_store_v2_commit_info_proto_rawDesc = nil + file_cosmos_store_v2_commit_info_proto_goTypes = nil + file_cosmos_store_v2_commit_info_proto_depIdxs = nil +} diff --git a/proto/cosmos/store/v2/commit_info.proto b/proto/cosmos/store/v2/commit_info.proto new file mode 100644 index 000000000000..18987f34e0ac --- /dev/null +++ b/proto/cosmos/store/v2/commit_info.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; +package cosmos.store.v2; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "cosmossdk.io/store/v2/proof"; + +// CommitInfo defines commit information used by the multi-store when committing +// a version/height. +message CommitInfo { + int64 version = 1; + repeated StoreInfo store_infos = 2; + google.protobuf.Timestamp timestamp = 3 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes commit_hash = 4; +} + +// StoreInfo defines store-specific commit information. It contains a reference +// between a store name and the commit ID. +// +message StoreInfo { + string name = 1; + CommitID commit_id = 2; + string structure = 3; +} + +// CommitID defines the commitment information when a specific store is +// committed. +message CommitID { + option (gogoproto.goproto_stringer) = false; + + int64 version = 1; + bytes hash = 2; +} diff --git a/scripts/init-simapp-v2.sh b/scripts/init-simapp-v2.sh index 02fb379f8e2c..794a771b0d75 100755 --- a/scripts/init-simapp-v2.sh +++ b/scripts/init-simapp-v2.sh @@ -11,8 +11,24 @@ $SIMD_BIN config set client keyring-backend test $SIMD_BIN config set client keyring-default-keyname alice $SIMD_BIN config set app rest.enable true $SIMD_BIN config set app telemetry.prometheus-retention-time 600 +<<<<<<< HEAD $SIMD_BIN keys add alice --indiscreet $SIMD_BIN keys add bob --indiscreet +======= +sed -i '' 's/timeout_commit = "5s"/timeout_commit = "1s"/' "$SIMD_HOME"/config/config.toml +sed -i '' 's/prometheus = false/prometheus = true/' "$SIMD_HOME"/config/config.toml + +$SIMD_BIN keys add alice --indiscreet +$SIMD_BIN keys add bob --indiscreet +aliases="" +for i in $(seq 10); do + alias=$(dd if=/dev/urandom bs=16 count=24 2> /dev/null | base64 | head -c 32) + $SIMD_BIN keys add "$alias" --indiscreet + aliases="$aliases $alias" +done +echo "Generated aliases: $aliases" + +>>>>>>> 064c9ba63 (feat(store/v2): build the migration manager in the root store factory (#22336)) $SIMD_BIN init simapp-v2-node --chain-id simapp-v2-chain # to change the voting_period jq '.app_state.gov.params.voting_period = "600s"' $SIMD_HOME/config/genesis.json > temp.json && mv temp.json $SIMD_HOME/config/genesis.json diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 35dcdc7824de..6fdfc331ea7e 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -914,7 +914,7 @@ func assertStoreLatestVersion(t *testing.T, store types.Store, target uint64) { require.Equal(t, target, version) commitInfo, err := store.GetStateCommitment().GetCommitInfo(version) require.NoError(t, err) - require.Equal(t, target, commitInfo.Version) + require.Equal(t, target, uint64(commitInfo.Version)) } func TestOptimisticExecution(t *testing.T) { diff --git a/server/v2/cometbft/internal/mock/mock_store.go b/server/v2/cometbft/internal/mock/mock_store.go index 8cb4542ac41e..7097aea83211 100644 --- a/server/v2/cometbft/internal/mock/mock_store.go +++ b/server/v2/cometbft/internal/mock/mock_store.go @@ -37,7 +37,7 @@ func (s *MockStore) GetLatestVersion() (uint64, error) { return 0, err } - return lastCommitID.Version, nil + return uint64(lastCommitID.Version), nil } func (s *MockStore) StateLatest() (uint64, corestore.ReaderMap, error) { @@ -99,7 +99,7 @@ func (s *MockStore) LastCommitID() (proof.CommitID, error) { v, err := s.GetStateCommitment().GetLatestVersion() bz := sha256.Sum256([]byte{}) return proof.CommitID{ - Version: v, + Version: int64(v), Hash: bz[:], }, err } diff --git a/server/v2/server.go b/server/v2/server.go new file mode 100644 index 000000000000..6036be1508cf --- /dev/null +++ b/server/v2/server.go @@ -0,0 +1,251 @@ +package serverv2 + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/pelletier/go-toml/v2" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" +) + +// ServerComponent is a server component that can be started and stopped. +type ServerComponent[T transaction.Tx] interface { + // Name returns the name of the server component. + Name() string + + // Start starts the server component. + Start(context.Context) error + // Stop stops the server component. + // Once Stop has been called on a server component, it may not be reused. + Stop(context.Context) error +} + +// HasStartFlags is a server component that has start flags. +type HasStartFlags interface { + // StartCmdFlags returns server start flags. + // Those flags should be prefixed with the server name. + // They are then merged with the server config in one viper instance. + StartCmdFlags() *pflag.FlagSet +} + +// HasConfig is a server component that has a config. +type HasConfig interface { + Config() any +} + +// ConfigWriter is a server component that can write its config to a file. +type ConfigWriter interface { + WriteConfig(path string) error +} + +// HasCLICommands is a server component that has CLI commands. +type HasCLICommands interface { + CLICommands() CLIConfig +} + +// CLIConfig defines the CLI configuration for a component server. +type CLIConfig struct { + // Commands defines the main command of a server component. + Commands []*cobra.Command + // Queries defines the query commands of a server component. + // Those commands are meant to be added in the root query command. + Queries []*cobra.Command + // Txs defines the tx commands of a server component. + // Those commands are meant to be added in the root tx command. + Txs []*cobra.Command +} + +const ( + serverName = "server" +) + +var _ ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) + +// Server is the top-level server component which contains all other server components. +type Server[T transaction.Tx] struct { + components []ServerComponent[T] + config ServerConfig +} + +func NewServer[T transaction.Tx]( + config ServerConfig, + components ...ServerComponent[T], +) *Server[T] { + return &Server[T]{ + config: config, + components: components, + } +} + +func (s *Server[T]) Name() string { + return serverName +} + +// Start starts all components concurrently. +func (s *Server[T]) Start(ctx context.Context) error { + logger := GetLoggerFromContext(ctx).With(log.ModuleKey, s.Name()) + logger.Info("starting servers...") + + resCh := make(chan error, len(s.components)) + for _, mod := range s.components { + go func() { + resCh <- mod.Start(ctx) + }() + } + + for i := 0; i < len(s.components); i++ { + select { + case err := <-resCh: + if err != nil { + return fmt.Errorf("failed to start servers: %w", err) + } + case <-ctx.Done(): + return nil + } + } + + <-ctx.Done() + + return nil +} + +// Stop stops all server components synchronously. +func (s *Server[T]) Stop(ctx context.Context) error { + logger := GetLoggerFromContext(ctx).With(log.ModuleKey, s.Name()) + logger.Info("stopping servers...") + + var err error + for _, mod := range s.components { + err = errors.Join(err, mod.Stop(ctx)) + } + + return err +} + +// CLICommands returns all CLI commands of all components. +func (s *Server[T]) CLICommands() CLIConfig { + compart := func(name string, cmds ...*cobra.Command) *cobra.Command { + if len(cmds) == 1 && strings.HasPrefix(cmds[0].Use, name) { + return cmds[0] + } + + subCmd := &cobra.Command{ + Use: name, + Short: fmt.Sprintf("Commands from the %s server component", name), + } + subCmd.AddCommand(cmds...) + + return subCmd + } + + commands := CLIConfig{} + for _, mod := range s.components { + if climod, ok := mod.(HasCLICommands); ok { + srvCmd := climod.CLICommands() + + if len(srvCmd.Commands) > 0 { + commands.Commands = append(commands.Commands, compart(mod.Name(), srvCmd.Commands...)) + } + + if len(srvCmd.Txs) > 0 { + commands.Txs = append(commands.Txs, compart(mod.Name(), srvCmd.Txs...)) + } + + if len(srvCmd.Queries) > 0 { + commands.Queries = append(commands.Queries, compart(mod.Name(), srvCmd.Queries...)) + } + } + } + + return commands +} + +// Config returns config of the server component +func (s *Server[T]) Config() ServerConfig { + return s.config +} + +// Configs returns all configs of all server components. +func (s *Server[T]) Configs() map[string]any { + cfgs := make(map[string]any) + + // add server component config + cfgs[s.Name()] = s.config + + // add other components' config + for _, mod := range s.components { + if configmod, ok := mod.(HasConfig); ok { + cfg := configmod.Config() + cfgs[mod.Name()] = cfg + } + } + + return cfgs +} + +func (s *Server[T]) StartCmdFlags() *pflag.FlagSet { + flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError) + flags.String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") + flags.String(FlagCPUProfiling, "", "Enable CPU profiling and write to the specified file") + flags.IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary") + + return flags +} + +// WriteConfig writes the config to the given path. +// Note: it does not use viper.WriteConfigAs because we do not want to store flag values in the config. +func (s *Server[T]) WriteConfig(configPath string) error { + cfgs := s.Configs() + b, err := toml.Marshal(cfgs) + if err != nil { + return err + } + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + if err := os.MkdirAll(configPath, os.ModePerm); err != nil { + return err + } + } + + if err := os.WriteFile(filepath.Join(configPath, "app.toml"), b, 0o600); err != nil { + return fmt.Errorf("failed to write config: %w", err) + } + + for _, component := range s.components { + // undocumented interface to write the component default config in another file than app.toml + // it is used by cometbft for backward compatibility + // it should not be used by other components + if mod, ok := component.(interface{ WriteCustomConfigAt(string) error }); ok { + if err := mod.WriteCustomConfigAt(configPath); err != nil { + return err + } + } + } + + return nil +} + +// StartFlags returns all flags of all server components. +func (s *Server[T]) StartFlags() []*pflag.FlagSet { + flags := []*pflag.FlagSet{} + + // add server component flags + flags = append(flags, s.StartCmdFlags()) + + // add other components' start cmd flags + for _, mod := range s.components { + if startmod, ok := mod.(HasStartFlags); ok { + flags = append(flags, startmod.StartCmdFlags()) + } + } + + return flags +} diff --git a/simapp/v2/app_config.go b/simapp/v2/app_config.go index 086063dab237..cfc58c3ce74e 100644 --- a/simapp/v2/app_config.go +++ b/simapp/v2/app_config.go @@ -36,6 +36,10 @@ import ( _ "cosmossdk.io/x/authz/module" // import for side-effects _ "cosmossdk.io/x/bank" // import for side-effects banktypes "cosmossdk.io/x/bank/types" +<<<<<<< HEAD +======= + _ "cosmossdk.io/x/bank/v2" // import for side-effects +>>>>>>> 064c9ba63 (feat(store/v2): build the migration manager in the root store factory (#22336)) _ "cosmossdk.io/x/circuit" // import for side-effects circuittypes "cosmossdk.io/x/circuit/types" _ "cosmossdk.io/x/consensus" // import for side-effects @@ -153,6 +157,10 @@ var ( accounts.ModuleName, authtypes.ModuleName, banktypes.ModuleName, +<<<<<<< HEAD +======= + // bankv2types.ModuleName, +>>>>>>> 064c9ba63 (feat(store/v2): build the migration manager in the root store factory (#22336)) distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, @@ -293,6 +301,13 @@ var ( Name: epochstypes.ModuleName, Config: appconfig.WrapAny(&epochsmodulev1.Module{}), }, +<<<<<<< HEAD +======= + // { + // Name: bankv2types.ModuleName, + // Config: appconfig.WrapAny(&bankmodulev2.Module{}), + // }, +>>>>>>> 064c9ba63 (feat(store/v2): build the migration manager in the root store factory (#22336)) }, } ) diff --git a/store/v2/commitment/iavl/exporter.go b/store/v2/commitment/iavl/exporter.go new file mode 100644 index 000000000000..7d7c1a5b75fc --- /dev/null +++ b/store/v2/commitment/iavl/exporter.go @@ -0,0 +1,53 @@ +package iavl + +import ( + "errors" + + "github.com/cosmos/iavl" + + "cosmossdk.io/store/v2/commitment" + snapshotstypes "cosmossdk.io/store/v2/snapshots/types" +) + +// Exporter is a wrapper around iavl.Exporter. +type Exporter struct { + exporter *iavl.Exporter +} + +// Next returns the next item in the exporter. +func (e *Exporter) Next() (*snapshotstypes.SnapshotIAVLItem, error) { + item, err := e.exporter.Next() + if err != nil { + if errors.Is(err, iavl.ErrorExportDone) { + return nil, commitment.ErrorExportDone + } + return nil, err + } + + return &snapshotstypes.SnapshotIAVLItem{ + Key: item.Key, + Value: item.Value, + Version: item.Version, + Height: int32(item.Height), + }, nil +} + +// Close closes the exporter. +func (e *Exporter) Close() error { + e.exporter.Close() + + return nil +} + +// EmptyExporter is a Exporter for an empty tree. +type EmptyExporter struct{} + +// Next returns ExportDone. +func (e *EmptyExporter) Next() (*snapshotstypes.SnapshotIAVLItem, error) { + return nil, commitment.ErrorExportDone +} + +// Close does nothing. +func (e *EmptyExporter) Close() error { + return nil +} diff --git a/store/v2/commitment/iavl/tree.go b/store/v2/commitment/iavl/tree.go new file mode 100644 index 000000000000..9b7d1641ab68 --- /dev/null +++ b/store/v2/commitment/iavl/tree.go @@ -0,0 +1,223 @@ +package iavl + +import ( + "errors" + "fmt" + + "github.com/cosmos/iavl" + ics23 "github.com/cosmos/ics23/go" + + "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/commitment" +) + +var ( + _ commitment.Tree = (*IavlTree)(nil) + _ commitment.Reader = (*IavlTree)(nil) + _ store.PausablePruner = (*IavlTree)(nil) +) + +// IavlTree is a wrapper around iavl.MutableTree. +type IavlTree struct { + tree *iavl.MutableTree + // it is only used for new store key during the migration process. + initialVersion uint64 +} + +// NewIavlTree creates a new IavlTree instance. +func NewIavlTree(db corestore.KVStoreWithBatch, logger log.Logger, cfg *Config) *IavlTree { + tree := iavl.NewMutableTree(db, cfg.CacheSize, cfg.SkipFastStorageUpgrade, logger, iavl.AsyncPruningOption(true)) + return &IavlTree{ + tree: tree, + } +} + +// Remove removes the given key from the tree. +func (t *IavlTree) Remove(key []byte) error { + _, _, err := t.tree.Remove(key) + if err != nil { + return err + } + return nil +} + +// Set sets the given key-value pair in the tree. +func (t *IavlTree) Set(key, value []byte) error { + _, err := t.tree.Set(key, value) + return err +} + +// Hash returns the hash of the latest saved version of the tree. +func (t *IavlTree) Hash() []byte { + return t.tree.Hash() +} + +// Version returns the current version of the tree. +func (t *IavlTree) Version() uint64 { + return uint64(t.tree.Version()) +} + +// WorkingHash returns the working hash of the tree. +// Danger! iavl.MutableTree.WorkingHash() is a mutating operation! +// It advances the tree version by 1. +func (t *IavlTree) WorkingHash() []byte { + return t.tree.WorkingHash() +} + +// LoadVersion loads the state at the given version. +func (t *IavlTree) LoadVersion(version uint64) error { + if t.initialVersion > 0 { + // If the initial version is set and the tree is empty, + // we don't need to load the version. + latestVersion, err := t.tree.GetLatestVersion() + if err != nil { + return err + } + if latestVersion == 0 { + return nil + } + } + _, err := t.tree.LoadVersion(int64(version)) + return err +} + +// LoadVersionForOverwriting loads the state at the given version. +// Any versions greater than targetVersion will be deleted. +func (t *IavlTree) LoadVersionForOverwriting(version uint64) error { + return t.tree.LoadVersionForOverwriting(int64(version)) +} + +// Commit commits the current state to the tree. +func (t *IavlTree) Commit() ([]byte, uint64, error) { + hash, v, err := t.tree.SaveVersion() + return hash, uint64(v), err +} + +// GetProof returns a proof for the given key and version. +func (t *IavlTree) GetProof(version uint64, key []byte) (*ics23.CommitmentProof, error) { + // the mutable tree is empty at genesis & when the storekey is removed, but the immutable tree is not but the immutable tree is not empty when the storekey is removed + // by checking the latest version we can determine if we are in genesis or have a key that has been removed + lv, err := t.tree.GetLatestVersion() + if err != nil { + return nil, err + } + if lv == 0 { + return t.tree.GetProof(key) + } + + immutableTree, err := t.tree.GetImmutable(int64(version)) + if err != nil { + return nil, fmt.Errorf("failed to get immutable tree at version %d: %w", version, err) + } + + return immutableTree.GetProof(key) +} + +// Get implements the Reader interface. +func (t *IavlTree) Get(version uint64, key []byte) ([]byte, error) { + // the mutable tree is empty at genesis & when the storekey is removed, but the immutable tree is not but the immutable tree is not empty when the storekey is removed + // by checking the latest version we can determine if we are in genesis or have a key that has been removed + lv, err := t.tree.GetLatestVersion() + if err != nil { + return nil, err + } + if lv == 0 { + return t.tree.Get(key) + } + + immutableTree, err := t.tree.GetImmutable(int64(version)) + if err != nil { + return nil, fmt.Errorf("failed to get immutable tree at version %d: %w", version, err) + } + + return immutableTree.Get(key) +} + +// Iterator implements the Reader interface. +func (t *IavlTree) Iterator(version uint64, start, end []byte, ascending bool) (corestore.Iterator, error) { + // the mutable tree is empty at genesis & when the storekey is removed, but the immutable tree is not empty when the storekey is removed + // by checking the latest version we can determine if we are in genesis or have a key that has been removed + lv, err := t.tree.GetLatestVersion() + if err != nil { + return nil, err + } + if lv == 0 { + return t.tree.Iterator(start, end, ascending) + } + + immutableTree, err := t.tree.GetImmutable(int64(version)) + if err != nil { + return nil, fmt.Errorf("failed to get immutable tree at version %d: %w", version, err) + } + + return immutableTree.Iterator(start, end, ascending) +} + +// GetLatestVersion returns the latest version of the tree. +func (t *IavlTree) GetLatestVersion() (uint64, error) { + v, err := t.tree.GetLatestVersion() + return uint64(v), err +} + +// SetInitialVersion sets the initial version of the database. +func (t *IavlTree) SetInitialVersion(version uint64) error { + t.tree.SetInitialVersion(version) + t.initialVersion = version + return nil +} + +// Prune prunes all versions up to and including the provided version. +func (t *IavlTree) Prune(version uint64) error { + return t.tree.DeleteVersionsTo(int64(version)) +} + +// PausePruning pauses the pruning process. +func (t *IavlTree) PausePruning(pause bool) { + if pause { + t.tree.SetCommitting() + } else { + t.tree.UnsetCommitting() + } +} + +// Export exports the tree exporter at the given version. +func (t *IavlTree) Export(version uint64) (commitment.Exporter, error) { + if version < t.initialVersion { + return nil, errors.New("version is less than the initial version") + } + tree, err := t.tree.GetImmutable(int64(version)) + if err != nil { + return nil, err + } + exporter, err := tree.Export() + if err != nil { + return nil, err + } + + return &Exporter{ + exporter: exporter, + }, nil +} + +// Import imports the tree importer at the given version. +func (t *IavlTree) Import(version uint64) (commitment.Importer, error) { + importer, err := t.tree.Import(int64(version)) + if err != nil { + return nil, err + } + + return &Importer{ + importer: importer, + }, nil +} + +// Close closes the iavl tree. +func (t *IavlTree) Close() error { + return t.tree.Close() +} + +func (t *IavlTree) IsConcurrentSafe() bool { + return false +} diff --git a/store/v2/commitment/metadata.go b/store/v2/commitment/metadata.go new file mode 100644 index 000000000000..62ae4a3d1655 --- /dev/null +++ b/store/v2/commitment/metadata.go @@ -0,0 +1,197 @@ +package commitment + +import ( + "errors" + "fmt" + + gogotypes "github.com/cosmos/gogoproto/types" + + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2/internal/encoding" + "cosmossdk.io/store/v2/proof" +) + +const ( + commitInfoKeyFmt = "s/%d" // s/ + latestVersionKey = "s/latest" + removedStoreKeyPrefix = "s/removed/" // s/removed// +) + +// MetadataStore is a store for metadata related to the commitment store. +// It isn't metadata store role to close the underlying KVStore. +type MetadataStore struct { + kv corestore.KVStoreWithBatch +} + +// NewMetadataStore creates a new MetadataStore. +func NewMetadataStore(kv corestore.KVStoreWithBatch) *MetadataStore { + return &MetadataStore{ + kv: kv, + } +} + +// GetLatestVersion returns the latest committed version. +func (m *MetadataStore) GetLatestVersion() (uint64, error) { + value, err := m.kv.Get([]byte(latestVersionKey)) + if err != nil { + return 0, err + } + if value == nil { + return 0, nil + } + + var latestVersion int64 + if err := gogotypes.StdInt64Unmarshal(&latestVersion, value); err != nil { + return 0, err + } + + return uint64(latestVersion), nil +} + +func (m *MetadataStore) setLatestVersion(version uint64) error { + bz, err := gogotypes.StdInt64Marshal(int64(version)) // convert uint64 to int64 is safe since there will be no overflow or underflow + if err != nil { + return err + } + return m.kv.Set([]byte(latestVersionKey), bz) +} + +// GetCommitInfo returns the commit info for the given version. +func (m *MetadataStore) GetCommitInfo(version uint64) (*proof.CommitInfo, error) { + key := []byte(fmt.Sprintf(commitInfoKeyFmt, version)) + value, err := m.kv.Get(key) + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + + cInfo := &proof.CommitInfo{} + if err := cInfo.Unmarshal(value); err != nil { + return nil, err + } + + if err := migrateStoreInfo(cInfo); err != nil { + return nil, err + } + + return cInfo, nil +} + +func (m *MetadataStore) flushCommitInfo(version uint64, cInfo *proof.CommitInfo) (err error) { + // do nothing if commit info is nil, as will be the case for an empty, initializing store + if cInfo == nil { + return nil + } + + batch := m.kv.NewBatch() + defer func() { + err = errors.Join(err, batch.Close()) + }() + cInfoKey := []byte(fmt.Sprintf(commitInfoKeyFmt, version)) + value, err := cInfo.Marshal() + if err != nil { + return err + } + if err := batch.Set(cInfoKey, value); err != nil { + return err + } + + bz, err := gogotypes.StdInt64Marshal(int64(version)) // convert uint64 to int64 is safe since there will be no overflow or underflow + if err != nil { + return err + } + if err := batch.Set([]byte(latestVersionKey), bz); err != nil { + return err + } + + if err := batch.Write(); err != nil { + return err + } + return nil +} + +func (m *MetadataStore) flushRemovedStoreKeys(version uint64, storeKeys []string) (err error) { + batch := m.kv.NewBatch() + defer func() { + err = errors.Join(err, batch.Close()) + }() + + for _, storeKey := range storeKeys { + key := []byte(fmt.Sprintf("%s%s", encoding.BuildPrefixWithVersion(removedStoreKeyPrefix, version), storeKey)) + if err := batch.Set(key, []byte{}); err != nil { + return err + } + } + return batch.Write() +} + +func (m *MetadataStore) GetRemovedStoreKeys(version uint64) (storeKeys [][]byte, err error) { + end := encoding.BuildPrefixWithVersion(removedStoreKeyPrefix, version+1) + iter, err := m.kv.Iterator([]byte(removedStoreKeyPrefix), end) + if err != nil { + return nil, err + } + defer func() { + if ierr := iter.Close(); ierr != nil { + err = ierr + } + }() + + for ; iter.Valid(); iter.Next() { + storeKey := iter.Key()[len(end):] + storeKeys = append(storeKeys, storeKey) + } + return storeKeys, nil +} + +func (m *MetadataStore) deleteRemovedStoreKeys(version uint64, removeStore func(storeKey []byte, version uint64) error) (err error) { + removedStoreKeys, err := m.GetRemovedStoreKeys(version) + if err != nil { + return err + } + if len(removedStoreKeys) == 0 { + return nil + } + + batch := m.kv.NewBatch() + defer func() { + err = errors.Join(err, batch.Close()) + }() + for _, storeKey := range removedStoreKeys { + if err := removeStore(storeKey, version); err != nil { + return err + } + if err := batch.Delete(storeKey); err != nil { + return err + } + } + + return batch.Write() +} + +func (m *MetadataStore) deleteCommitInfo(version uint64) error { + cInfoKey := []byte(fmt.Sprintf(commitInfoKeyFmt, version)) + return m.kv.Delete(cInfoKey) +} + +// when in migration mode, we need to add new fields to the store info +// this will only be the case for the storev1 to storev2 migration +func migrateStoreInfo(cInfo *proof.CommitInfo) error { + for _, storeInfo := range cInfo.StoreInfos { + if storeInfo.Structure == "" { + storeInfo.Structure = "iavl" + } + } + + if cInfo.CommitHash == nil { + commitHash, _, err := cInfo.GetStoreProof([]byte{}) + if err != nil { + return err + } + + cInfo.CommitHash = commitHash + } + return nil +} diff --git a/store/v2/commitment/store.go b/store/v2/commitment/store.go new file mode 100644 index 000000000000..08c254b1992d --- /dev/null +++ b/store/v2/commitment/store.go @@ -0,0 +1,630 @@ +package commitment + +import ( + "errors" + "fmt" + "io" + "maps" + "math" + "slices" + + protoio "github.com/cosmos/gogoproto/io" + "golang.org/x/sync/errgroup" + + corelog "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/internal" + "cosmossdk.io/store/v2/internal/conv" + "cosmossdk.io/store/v2/proof" + "cosmossdk.io/store/v2/snapshots" + snapshotstypes "cosmossdk.io/store/v2/snapshots/types" +) + +var ( + _ store.Committer = (*CommitStore)(nil) + _ store.UpgradeableStore = (*CommitStore)(nil) + _ snapshots.CommitSnapshotter = (*CommitStore)(nil) + _ store.PausablePruner = (*CommitStore)(nil) + + // NOTE: It is not recommended to use the CommitStore as a reader. This is only used + // during the migration process. Generally, the SC layer does not provide a reader + // in the store/v2. + _ store.VersionedReader = (*CommitStore)(nil) +) + +// MountTreeFn is a function that mounts a tree given a store key. +// It is used to lazily mount trees when needed (e.g. during upgrade or proof generation). +type MountTreeFn func(storeKey string) (Tree, error) + +// CommitStore is a wrapper around multiple Tree objects mapped by a unique store +// key. Each store key reflects dedicated and unique usage within a module. A caller +// can construct a CommitStore with one or more store keys. It is expected that a +// RootStore use a CommitStore as an abstraction to handle multiple store keys +// and trees. +type CommitStore struct { + logger corelog.Logger + metadata *MetadataStore + multiTrees map[string]Tree + // oldTrees is a map of store keys to old trees that have been deleted or renamed. + // It is used to get the proof for the old store keys. + oldTrees map[string]Tree +} + +// NewCommitStore creates a new CommitStore instance. +func NewCommitStore(trees, oldTrees map[string]Tree, db corestore.KVStoreWithBatch, logger corelog.Logger) (*CommitStore, error) { + return &CommitStore{ + logger: logger, + multiTrees: trees, + oldTrees: oldTrees, + metadata: NewMetadataStore(db), + }, nil +} + +func (c *CommitStore) WriteChangeset(cs *corestore.Changeset) error { + eg := new(errgroup.Group) + eg.SetLimit(store.MaxWriteParallelism) + for _, pairs := range cs.Changes { + key := conv.UnsafeBytesToStr(pairs.Actor) + + tree, ok := c.multiTrees[key] + if !ok { + return fmt.Errorf("store key %s not found in multiTrees", key) + } + if tree.IsConcurrentSafe() { + eg.Go(func() error { + return writeChangeset(tree, pairs) + }) + } else { + if err := writeChangeset(tree, pairs); err != nil { + return err + } + } + } + + return eg.Wait() +} + +func writeChangeset(tree Tree, changes corestore.StateChanges) error { + for _, kv := range changes.StateChanges { + if kv.Remove { + if err := tree.Remove(kv.Key); err != nil { + return err + } + } else if err := tree.Set(kv.Key, kv.Value); err != nil { + return err + } + } + return nil +} + +func (c *CommitStore) LoadVersion(targetVersion uint64) error { + storeKeys := make([]string, 0, len(c.multiTrees)) + for storeKey := range c.multiTrees { + storeKeys = append(storeKeys, storeKey) + } + return c.loadVersion(targetVersion, storeKeys, false) +} + +func (c *CommitStore) LoadVersionForOverwriting(targetVersion uint64) error { + storeKeys := make([]string, 0, len(c.multiTrees)) + for storeKey := range c.multiTrees { + storeKeys = append(storeKeys, storeKey) + } + + return c.loadVersion(targetVersion, storeKeys, true) +} + +// LoadVersionAndUpgrade implements store.UpgradeableStore. +func (c *CommitStore) LoadVersionAndUpgrade(targetVersion uint64, upgrades *corestore.StoreUpgrades) error { + // deterministic iteration order for upgrades (as the underlying store may change and + // upgrades make store changes where the execution order may matter) + storeKeys := slices.Sorted(maps.Keys(c.multiTrees)) + removeTree := func(storeKey string) error { + if oldTree, ok := c.multiTrees[storeKey]; ok { + if err := oldTree.Close(); err != nil { + return err + } + delete(c.multiTrees, storeKey) + } + return nil + } + + newStoreKeys := make([]string, 0, len(c.multiTrees)) + removedStoreKeys := make([]string, 0) + for _, storeKey := range storeKeys { + // If it has been deleted, remove the tree. + if upgrades.IsDeleted(storeKey) { + if err := removeTree(storeKey); err != nil { + return err + } + removedStoreKeys = append(removedStoreKeys, storeKey) + continue + } + + // If it has been added, set the initial version. + if upgrades.IsAdded(storeKey) { + if err := c.multiTrees[storeKey].SetInitialVersion(targetVersion + 1); err != nil { + return err + } + // This is the empty tree, no need to load the version. + continue + } + + newStoreKeys = append(newStoreKeys, storeKey) + } + + if err := c.metadata.flushRemovedStoreKeys(targetVersion, removedStoreKeys); err != nil { + return err + } + + return c.loadVersion(targetVersion, newStoreKeys, true) +} + +func (c *CommitStore) loadVersion(targetVersion uint64, storeKeys []string, overrideAfter bool) error { + // Rollback the metadata to the target version. + latestVersion, err := c.GetLatestVersion() + if err != nil { + return err + } + if targetVersion < latestVersion { + for version := latestVersion; version > targetVersion; version-- { + if err = c.metadata.deleteCommitInfo(version); err != nil { + return err + } + } + if err := c.metadata.setLatestVersion(targetVersion); err != nil { + return err + } + } + + eg := errgroup.Group{} + eg.SetLimit(store.MaxWriteParallelism) + for _, storeKey := range storeKeys { + tree := c.multiTrees[storeKey] + if overrideAfter { + if tree.IsConcurrentSafe() { + eg.Go(func() error { + return c.multiTrees[storeKey].LoadVersionForOverwriting(targetVersion) + }) + } else { + if err := c.multiTrees[storeKey].LoadVersionForOverwriting(targetVersion); err != nil { + return err + } + } + } else { + if tree.IsConcurrentSafe() { + eg.Go(func() error { return c.multiTrees[storeKey].LoadVersion(targetVersion) }) + } else { + if err := c.multiTrees[storeKey].LoadVersion(targetVersion); err != nil { + return err + } + } + } + } + + if err := eg.Wait(); err != nil { + return err + } + + // If the target version is greater than the latest version, it is the snapshot + // restore case, we should create a new commit info for the target version. + if targetVersion > latestVersion { + cInfo, err := c.GetCommitInfo(targetVersion) + if err != nil { + return err + } + return c.metadata.flushCommitInfo(targetVersion, cInfo) + } + + return nil +} + +func (c *CommitStore) Commit(version uint64) (*proof.CommitInfo, error) { + storeInfos := make([]*proof.StoreInfo, 0, len(c.multiTrees)) + eg := new(errgroup.Group) + eg.SetLimit(store.MaxWriteParallelism) + + for storeKey, tree := range c.multiTrees { + if internal.IsMemoryStoreKey(storeKey) { + continue + } + si := &proof.StoreInfo{Name: storeKey} + storeInfos = append(storeInfos, si) + + if tree.IsConcurrentSafe() { + eg.Go(func() error { + err := c.commit(tree, si, version) + if err != nil { + return fmt.Errorf("commit fail: %s: %w", si.Name, err) + } + return nil + }) + } else { + err := c.commit(tree, si, version) + if err != nil { + return nil, err + } + } + } + + // convert storeInfos to []proof.StoreInfo + sideref := make([]*proof.StoreInfo, 0, len(c.multiTrees)) + sideref = append(sideref, storeInfos...) + + cInfo := &proof.CommitInfo{ + Version: int64(version), + StoreInfos: sideref, + } + + if err := eg.Wait(); err != nil { + return nil, err + } + + if err := c.metadata.flushCommitInfo(version, cInfo); err != nil { + return nil, err + } + + return cInfo, nil +} + +func (c *CommitStore) commit(tree Tree, si *proof.StoreInfo, expected uint64) error { + h, v, err := tree.Commit() + if err != nil { + return err + } + if v != expected { + return fmt.Errorf("commit version %d does not match the target version %d", v, expected) + } + si.CommitId = &proof.CommitID{ + Version: int64(v), + Hash: h, + } + return nil +} + +func (c *CommitStore) SetInitialVersion(version uint64) error { + for _, tree := range c.multiTrees { + if err := tree.SetInitialVersion(version); err != nil { + return err + } + } + + return nil +} + +// GetProof returns a proof for the given key and version. +func (c *CommitStore) GetProof(storeKey []byte, version uint64, key []byte) ([]proof.CommitmentOp, error) { + rawStoreKey := conv.UnsafeBytesToStr(storeKey) + tree, ok := c.multiTrees[rawStoreKey] + if !ok { + tree, ok = c.oldTrees[rawStoreKey] + if !ok { + return nil, fmt.Errorf("store %s not found", rawStoreKey) + } + } + + iProof, err := tree.GetProof(version, key) + if err != nil { + return nil, err + } + cInfo, err := c.metadata.GetCommitInfo(version) + if err != nil { + return nil, err + } + if cInfo == nil { + return nil, fmt.Errorf("commit info not found for version %d", version) + } + commitOp := proof.NewIAVLCommitmentOp(key, iProof) + _, storeCommitmentOp, err := cInfo.GetStoreProof(storeKey) + if err != nil { + return nil, err + } + + return []proof.CommitmentOp{commitOp, *storeCommitmentOp}, nil +} + +// getReader returns a reader for the given store key. It will return an error if the +// store key does not exist or the tree does not implement the Reader interface. +// WARNING: This function is only used during the migration process. The SC layer +// generally does not provide a reader for the CommitStore. +func (c *CommitStore) getReader(storeKey string) (Reader, error) { + var tree Tree + if storeTree, ok := c.oldTrees[storeKey]; ok { + tree = storeTree + } else if storeTree, ok := c.multiTrees[storeKey]; ok { + tree = storeTree + } else { + return nil, fmt.Errorf("store %s not found", storeKey) + } + + reader, ok := tree.(Reader) + if !ok { + return nil, fmt.Errorf("tree for store %s does not implement Reader", storeKey) + } + + return reader, nil +} + +// VersionExists implements store.VersionedReader. +func (c *CommitStore) VersionExists(version uint64) (bool, error) { + latestVersion, err := c.metadata.GetLatestVersion() + if err != nil { + return false, err + } + if latestVersion == 0 { + return version == 0, nil + } + + ci, err := c.metadata.GetCommitInfo(version) + return ci != nil, err +} + +// Get implements store.VersionedReader. +func (c *CommitStore) Get(storeKey []byte, version uint64, key []byte) ([]byte, error) { + reader, err := c.getReader(conv.UnsafeBytesToStr(storeKey)) + if err != nil { + return nil, err + } + + bz, err := reader.Get(version, key) + if err != nil { + return nil, fmt.Errorf("failed to get key %s from store %s: %w", key, storeKey, err) + } + + return bz, nil +} + +// Has implements store.VersionedReader. +func (c *CommitStore) Has(storeKey []byte, version uint64, key []byte) (bool, error) { + val, err := c.Get(storeKey, version, key) + return val != nil, err +} + +// Iterator implements store.VersionedReader. +func (c *CommitStore) Iterator(storeKey []byte, version uint64, start, end []byte) (corestore.Iterator, error) { + reader, err := c.getReader(conv.UnsafeBytesToStr(storeKey)) + if err != nil { + return nil, err + } + + return reader.Iterator(version, start, end, true) +} + +// ReverseIterator implements store.VersionedReader. +func (c *CommitStore) ReverseIterator(storeKey []byte, version uint64, start, end []byte) (corestore.Iterator, error) { + reader, err := c.getReader(conv.UnsafeBytesToStr(storeKey)) + if err != nil { + return nil, err + } + + return reader.Iterator(version, start, end, false) +} + +// Prune implements store.Pruner. +func (c *CommitStore) Prune(version uint64) error { + // prune the metadata + for v := version; v > 0; v-- { + if err := c.metadata.deleteCommitInfo(v); err != nil { + return err + } + } + // prune the trees + for _, tree := range c.multiTrees { + if err := tree.Prune(version); err != nil { + return err + } + } + // prune the removed store keys + if err := c.pruneRemovedStoreKeys(version); err != nil { + return err + } + + return nil +} + +func (c *CommitStore) pruneRemovedStoreKeys(version uint64) error { + clearKVStore := func(storeKey []byte, version uint64) (err error) { + tree, ok := c.oldTrees[string(storeKey)] + if !ok { + return fmt.Errorf("store %s not found in oldTrees", storeKey) + } + return tree.Prune(version) + } + return c.metadata.deleteRemovedStoreKeys(version, clearKVStore) +} + +// PausePruning implements store.PausablePruner. +func (c *CommitStore) PausePruning(pause bool) { + for _, tree := range c.multiTrees { + if pruner, ok := tree.(store.PausablePruner); ok { + pruner.PausePruning(pause) + } + } +} + +// Snapshot implements snapshotstypes.CommitSnapshotter. +func (c *CommitStore) Snapshot(version uint64, protoWriter protoio.Writer) error { + if version == 0 { + return errors.New("the snapshot version must be greater than 0") + } + + latestVersion, err := c.GetLatestVersion() + if err != nil { + return err + } + if version > latestVersion { + return fmt.Errorf("the snapshot version %d is greater than the latest version %d", version, latestVersion) + } + + for storeKey, tree := range c.multiTrees { + // TODO: check the parallelism of this loop + if err := func() error { + exporter, err := tree.Export(version) + if err != nil { + return fmt.Errorf("failed to export tree for version %d: %w", version, err) + } + defer exporter.Close() + + err = protoWriter.WriteMsg(&snapshotstypes.SnapshotItem{ + Item: &snapshotstypes.SnapshotItem_Store{ + Store: &snapshotstypes.SnapshotStoreItem{ + Name: storeKey, + }, + }, + }) + if err != nil { + return fmt.Errorf("failed to write store name: %w", err) + } + + for { + item, err := exporter.Next() + if errors.Is(err, ErrorExportDone) { + break + } else if err != nil { + return fmt.Errorf("failed to get the next export node: %w", err) + } + + if err = protoWriter.WriteMsg(&snapshotstypes.SnapshotItem{ + Item: &snapshotstypes.SnapshotItem_IAVL{ + IAVL: item, + }, + }); err != nil { + return fmt.Errorf("failed to write iavl node: %w", err) + } + } + + return nil + }(); err != nil { + return err + } + } + + return nil +} + +// Restore implements snapshotstypes.CommitSnapshotter. +func (c *CommitStore) Restore( + version uint64, + format uint32, + protoReader protoio.Reader, +) (snapshotstypes.SnapshotItem, error) { + var ( + importer Importer + snapshotItem snapshotstypes.SnapshotItem + ) + +loop: + for { + snapshotItem = snapshotstypes.SnapshotItem{} + err := protoReader.ReadMsg(&snapshotItem) + if errors.Is(err, io.EOF) { + break + } else if err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("invalid protobuf message: %w", err) + } + + switch item := snapshotItem.Item.(type) { + case *snapshotstypes.SnapshotItem_Store: + if importer != nil { + if err := importer.Commit(); err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("failed to commit importer: %w", err) + } + if err := importer.Close(); err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("failed to close importer: %w", err) + } + } + tree := c.multiTrees[item.Store.Name] + if tree == nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("store %s not found", item.Store.Name) + } + importer, err = tree.Import(version) + if err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("failed to import tree for version %d: %w", version, err) + } + defer importer.Close() + + case *snapshotstypes.SnapshotItem_IAVL: + if importer == nil { + return snapshotstypes.SnapshotItem{}, errors.New("received IAVL node item before store item") + } + node := item.IAVL + if node.Height > int32(math.MaxInt8) { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("node height %v cannot exceed %v", + item.IAVL.Height, math.MaxInt8) + } + // Protobuf does not differentiate between []byte{} and nil, but fortunately IAVL does + // not allow nil keys nor nil values for leaf nodes, so we can always set them to empty. + if node.Key == nil { + node.Key = []byte{} + } + if node.Height == 0 { + if node.Value == nil { + node.Value = []byte{} + } + } + err := importer.Add(node) + if err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("failed to add node to importer: %w", err) + } + default: + break loop + } + } + + if importer != nil { + if err := importer.Commit(); err != nil { + return snapshotstypes.SnapshotItem{}, fmt.Errorf("failed to commit importer: %w", err) + } + } + + return snapshotItem, c.LoadVersion(version) +} + +func (c *CommitStore) GetCommitInfo(version uint64) (*proof.CommitInfo, error) { + // if the commit info is already stored, return it + ci, err := c.metadata.GetCommitInfo(version) + if err != nil { + return nil, err + } + if ci != nil { + return ci, nil + } + // otherwise built the commit info from the trees + storeInfos := make([]*proof.StoreInfo, 0, len(c.multiTrees)) + for storeKey, tree := range c.multiTrees { + if internal.IsMemoryStoreKey(storeKey) { + continue + } + v := tree.Version() + if v != version { + return nil, fmt.Errorf("tree version %d does not match the target version %d", v, version) + } + storeInfos = append(storeInfos, &proof.StoreInfo{ + Name: storeKey, + CommitId: &proof.CommitID{ + Version: int64(v), + Hash: tree.Hash(), + }, + }) + } + + ci = &proof.CommitInfo{ + Version: int64(version), + StoreInfos: storeInfos, + } + return ci, nil +} + +func (c *CommitStore) GetLatestVersion() (uint64, error) { + return c.metadata.GetLatestVersion() +} + +func (c *CommitStore) Close() error { + for _, tree := range c.multiTrees { + if err := tree.Close(); err != nil { + return err + } + } + return nil +} diff --git a/store/v2/commitment/store_test_suite.go b/store/v2/commitment/store_test_suite.go new file mode 100644 index 000000000000..955b743058a7 --- /dev/null +++ b/store/v2/commitment/store_test_suite.go @@ -0,0 +1,492 @@ +package commitment + +import ( + "fmt" + "io" + "strings" + + "github.com/stretchr/testify/suite" + + corelog "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + coretesting "cosmossdk.io/core/testing" + "cosmossdk.io/store/v2" + dbm "cosmossdk.io/store/v2/db" + "cosmossdk.io/store/v2/proof" + "cosmossdk.io/store/v2/snapshots" + snapshotstypes "cosmossdk.io/store/v2/snapshots/types" +) + +const ( + storeKey1 = "store1" + storeKey2 = "store2" + storeKey3 = "store3" +) + +// CommitStoreTestSuite is a test suite to be used for all tree backends. +type CommitStoreTestSuite struct { + suite.Suite + + NewStore func(db corestore.KVStoreWithBatch, dbDir string, storeKeys, oldStoreKeys []string, logger corelog.Logger) (*CommitStore, error) + TreeType string +} + +// TestStore_Snapshotter tests the snapshot functionality of the CommitStore. +// This test verifies that the store can correctly create snapshots and restore from them. +// The test follows these steps: +// +// 1. Setup & Data Population: +// - Creates a new CommitStore with two stores (store1 and store2) +// - Writes 10 versions of data (version 1-10) +// - For each version, writes 10 key-value pairs to each store +// - Total data: 2 stores * 10 versions * 10 pairs = 200 key-value pairs +// - Keys are formatted as "key-{version}-{index}" +// - Values are formatted as "value-{version}-{index}" +// - Each version is committed to get a CommitInfo +// +// 2. Snapshot Creation: +// - Creates a dummy extension item for metadata testing +// - Sets up a new target store for restoration +// - Creates a channel for snapshot chunks +// - Launches a goroutine to: +// - Create a snapshot writer +// - Take a snapshot at version 10 +// - Write extension metadata +// +// 3. Snapshot Restoration: +// - Creates a snapshot reader from the chunks +// - Sets up a channel for state changes during restoration +// - Launches a goroutine to collect restored key-value pairs +// - Restores the snapshot into the target store +// - Verifies the extension metadata was preserved +// +// 4. Verification: +// - Confirms all 200 key-value pairs were restored correctly +// - Verifies the format: "{storeKey}_key-{version}-{index}" -> "value-{version}-{index}" +// - Checks that the restored store's Merkle tree hashes match the original +// - Ensures store integrity by comparing CommitInfo hashes +func (s *CommitStoreTestSuite) TestStore_Snapshotter() { + storeKeys := []string{storeKey1, storeKey2} + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + // We'll create 10 versions of data + latestVersion := uint64(10) + kvCount := 10 + var cInfo *proof.CommitInfo + + // For each version 1-10 + for i := uint64(1); i <= latestVersion; i++ { + // Create KV pairs for each store + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range storeKeys { + kvPairs[storeKey] = corestore.KVPairs{} + // Create 10 KV pairs for this store + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + // Write and commit the changes for this version + s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + cInfo, err = commitStore.Commit(i) + s.Require().NoError(err) + } + + s.Require().Equal(len(storeKeys), len(cInfo.StoreInfos)) + + // create a snapshot + dummyExtensionItem := snapshotstypes.SnapshotItem{ + Item: &snapshotstypes.SnapshotItem_Extension{ + Extension: &snapshotstypes.SnapshotExtensionMeta{ + Name: "test", + Format: 1, + }, + }, + } + + targetStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + chunks := make(chan io.ReadCloser, kvCount*int(latestVersion)) + go func() { + streamWriter := snapshots.NewStreamWriter(chunks) + s.Require().NotNil(streamWriter) + defer streamWriter.Close() + err := commitStore.Snapshot(latestVersion, streamWriter) + s.Require().NoError(err) + // write an extension metadata + err = streamWriter.WriteMsg(&dummyExtensionItem) + s.Require().NoError(err) + }() + + streamReader, err := snapshots.NewStreamReader(chunks) + s.Require().NoError(err) + + nextItem, err := targetStore.Restore(latestVersion, snapshotstypes.CurrentFormat, streamReader) + s.Require().NoError(err) + s.Require().Equal(*dummyExtensionItem.GetExtension(), *nextItem.GetExtension()) + + // check the restored tree hash + targetCommitInfo, err := targetStore.GetCommitInfo(latestVersion) + s.Require().NoError(err) + for _, storeInfo := range targetCommitInfo.StoreInfos { + matched := false + for _, latestStoreInfo := range cInfo.StoreInfos { + if strings.EqualFold(storeInfo.Name, latestStoreInfo.Name) { + s.Require().Equal(latestStoreInfo.GetHash(), storeInfo.GetHash()) + matched = true + } + } + s.Require().True(matched) + } +} + +func (s *CommitStoreTestSuite) TestStore_LoadVersion() { + storeKeys := []string{storeKey1, storeKey2} + mdb := dbm.NewMemDB() + dbDir := s.T().TempDir() + commitStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + latestVersion := uint64(10) + kvCount := 10 + for i := uint64(1); i <= latestVersion; i++ { + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range storeKeys { + kvPairs[storeKey] = corestore.KVPairs{} + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + _, err = commitStore.Commit(i) + s.Require().NoError(err) + } + + // load the store with the latest version + targetStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + err = targetStore.LoadVersion(latestVersion) + s.Require().NoError(err) + // check the store + for i := uint64(1); i <= latestVersion; i++ { + commitInfo, _ := targetStore.GetCommitInfo(i) + s.Require().NotNil(commitInfo) + s.Require().Equal(i, uint64(commitInfo.Version)) + } + + // rollback to a previous version + rollbackVersion := uint64(5) + rollbackStore, err := s.NewStore(mdb, dbDir, storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + err = rollbackStore.LoadVersion(rollbackVersion) + s.Require().NoError(err) + // check the store + v, err := rollbackStore.GetLatestVersion() + s.Require().NoError(err) + s.Require().Equal(rollbackVersion, v) + for i := uint64(1); i <= latestVersion; i++ { + commitInfo, _ := rollbackStore.GetCommitInfo(i) + if i > rollbackVersion { + s.Require().Nil(commitInfo) + } else { + s.Require().NotNil(commitInfo) + } + } +} + +func (s *CommitStoreTestSuite) TestStore_Pruning() { + storeKeys := []string{storeKey1, storeKey2} + pruneOpts := store.NewPruningOptionWithCustom(10, 5) + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + latestVersion := uint64(100) + kvCount := 10 + for i := uint64(1); i <= latestVersion; i++ { + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range storeKeys { + kvPairs[storeKey] = corestore.KVPairs{} + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + + _, err = commitStore.Commit(i) + s.Require().NoError(err) + + if prune, pruneVersion := pruneOpts.ShouldPrune(i); prune { + s.Require().NoError(commitStore.Prune(pruneVersion)) + } + + } + + pruneVersion := latestVersion - pruneOpts.KeepRecent - 1 + // check the store + for i := uint64(1); i <= latestVersion; i++ { + commitInfo, _ := commitStore.GetCommitInfo(i) + if i <= pruneVersion { + s.Require().Nil(commitInfo) + } else { + s.Require().NotNil(commitInfo) + } + } +} + +func (s *CommitStoreTestSuite) TestStore_GetProof() { + storeKeys := []string{storeKey1, storeKey2} + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + toVersion := uint64(10) + keyCount := 5 + + // commit some changes + for version := uint64(1); version <= toVersion; version++ { + cs := corestore.NewChangeset(version) + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + cs.Add([]byte(storeKey), []byte(fmt.Sprintf("key-%d-%d", version, i)), []byte(fmt.Sprintf("value-%d-%d", version, i)), false) + } + } + err := commitStore.WriteChangeset(cs) + s.Require().NoError(err) + _, err = commitStore.Commit(version) + s.Require().NoError(err) + } + + // get proof + for version := uint64(1); version <= toVersion; version++ { + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + _, err := commitStore.GetProof([]byte(storeKey), version, []byte(fmt.Sprintf("key-%d-%d", version, i))) + s.Require().NoError(err) + } + } + } + + // prune version 1 + s.Require().NoError(commitStore.Prune(1)) + + // check if proof for version 1 is pruned + _, err = commitStore.GetProof([]byte(storeKeys[0]), 1, []byte(fmt.Sprintf("key-%d-%d", 1, 0))) + s.Require().Error(err) + // check the commit info + commit, _ := commitStore.GetCommitInfo(1) + s.Require().Nil(commit) +} + +func (s *CommitStoreTestSuite) TestStore_Get() { + storeKeys := []string{storeKey1, storeKey2} + commitStore, err := s.NewStore(dbm.NewMemDB(), s.T().TempDir(), storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + toVersion := uint64(10) + keyCount := 5 + + // commit some changes + for version := uint64(1); version <= toVersion; version++ { + cs := corestore.NewChangeset(version) + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + cs.Add([]byte(storeKey), []byte(fmt.Sprintf("key-%d-%d", version, i)), []byte(fmt.Sprintf("value-%d-%d", version, i)), false) + } + } + err := commitStore.WriteChangeset(cs) + s.Require().NoError(err) + _, err = commitStore.Commit(version) + s.Require().NoError(err) + } + + // get proof + for version := uint64(1); version <= toVersion; version++ { + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + val, err := commitStore.Get([]byte(storeKey), version, []byte(fmt.Sprintf("key-%d-%d", version, i))) + s.Require().NoError(err) + s.Require().Equal([]byte(fmt.Sprintf("value-%d-%d", version, i)), val) + } + } + } +} + +func (s *CommitStoreTestSuite) TestStore_Upgrades() { + storeKeys := []string{storeKey1, storeKey2, storeKey3} + commitDB := dbm.NewMemDB() + commitDir := s.T().TempDir() + commitStore, err := s.NewStore(commitDB, commitDir, storeKeys, nil, coretesting.NewNopLogger()) + s.Require().NoError(err) + + latestVersion := uint64(10) + kvCount := 10 + for i := uint64(1); i <= latestVersion; i++ { + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range storeKeys { + kvPairs[storeKey] = corestore.KVPairs{} + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + _, err = commitStore.Commit(i) + s.Require().NoError(err) + } + + // create a new commitment store with upgrades + upgrades := &corestore.StoreUpgrades{ + Added: []string{"newStore1", "newStore2"}, + Deleted: []string{storeKey3}, + } + newStoreKeys := []string{storeKey1, storeKey2, storeKey3, "newStore1", "newStore2"} + realStoreKeys := []string{storeKey1, storeKey2, "newStore1", "newStore2"} + oldStoreKeys := []string{storeKey3} + commitStore, err = s.NewStore(commitDB, commitDir, newStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) + s.Require().NoError(err) + err = commitStore.LoadVersionAndUpgrade(latestVersion, upgrades) + s.Require().NoError(err) + + // GetProof should work for the old stores + for _, storeKey := range []string{storeKey3} { + for i := uint64(1); i <= latestVersion; i++ { + for j := 0; j < kvCount; j++ { + proof, err := commitStore.GetProof([]byte(storeKey), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().NoError(err) + s.Require().NotNil(proof) + } + } + } + // GetProof should fail for the new stores against the old versions + for _, storeKey := range []string{"newStore1", "newStore2"} { + for i := uint64(1); i <= latestVersion; i++ { + for j := 0; j < kvCount; j++ { + _, err := commitStore.GetProof([]byte(storeKey), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().Error(err) + } + } + } + + // apply the changeset again + for i := latestVersion + 1; i < latestVersion*2; i++ { + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range realStoreKeys { + kvPairs[storeKey] = corestore.KVPairs{} + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + s.Require().NoError(commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs))) + commitInfo, err := commitStore.Commit(i) + s.Require().NoError(err) + s.Require().NotNil(commitInfo) + s.Require().Equal(len(realStoreKeys), len(commitInfo.StoreInfos)) + for _, storeKey := range realStoreKeys { + s.Require().NotNil(commitInfo.GetStoreCommitID([]byte(storeKey))) + } + } + + // verify new stores + for _, storeKey := range []string{"newStore1", "newStore2"} { + for i := latestVersion + 1; i < latestVersion*2; i++ { + for j := 0; j < kvCount; j++ { + proof, err := commitStore.GetProof([]byte(storeKey), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().NoError(err) + s.Require().NotNil(proof) + } + } + } + + // verify existing store + for i := uint64(1); i < latestVersion*2; i++ { + for j := 0; j < kvCount; j++ { + prf, err := commitStore.GetProof([]byte(storeKey2), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().NoError(err) + s.Require().NotNil(prf) + } + } + + // create a new commitment store with one more upgrades + upgrades = &corestore.StoreUpgrades{ + Deleted: []string{storeKey2}, + Added: []string{"newStore3"}, + } + newRealStoreKeys := []string{storeKey1, "newStore1", "newStore2", "newStore3"} + oldStoreKeys = []string{storeKey2, storeKey3} + commitStore, err = s.NewStore(commitDB, commitDir, newRealStoreKeys, oldStoreKeys, coretesting.NewNopLogger()) + s.Require().NoError(err) + err = commitStore.LoadVersionAndUpgrade(2*latestVersion-1, upgrades) + s.Require().NoError(err) + + // apply the changeset again + for i := latestVersion * 2; i < latestVersion*3; i++ { + kvPairs := make(map[string]corestore.KVPairs) + for _, storeKey := range newRealStoreKeys { + kvPairs[storeKey] = corestore.KVPairs{} + for j := 0; j < kvCount; j++ { + key := []byte(fmt.Sprintf("key-%d-%d", i, j)) + value := []byte(fmt.Sprintf("value-%d-%d", i, j)) + kvPairs[storeKey] = append(kvPairs[storeKey], corestore.KVPair{Key: key, Value: value}) + } + } + err = commitStore.WriteChangeset(corestore.NewChangesetWithPairs(i, kvPairs)) + s.Require().NoError(err) + commitInfo, err := commitStore.Commit(i) + s.Require().NoError(err) + s.Require().NotNil(commitInfo) + s.Require().Equal(len(newRealStoreKeys), len(commitInfo.StoreInfos)) + for _, storeKey := range newRealStoreKeys { + s.Require().NotNil(commitInfo.GetStoreCommitID([]byte(storeKey))) + } + } + + // prune the old stores + s.Require().NoError(commitStore.Prune(latestVersion)) + s.T().Logf("prune to version %d", latestVersion) + // GetProof should fail for the old stores + for _, storeKey := range []string{storeKey1, storeKey3} { + for i := uint64(1); i <= latestVersion; i++ { + for j := 0; j < kvCount; j++ { + _, err := commitStore.GetProof([]byte(storeKey), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().Error(err) + } + } + } + s.T().Log("GetProof should work for the new stores") + // GetProof should not fail for the newly removed store + for i := latestVersion + 1; i < latestVersion*2; i++ { + for j := 0; j < kvCount; j++ { + proof, err := commitStore.GetProof([]byte(storeKey2), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().NoError(err) + s.Require().NotNil(proof) + } + } + + s.T().Logf("Prune to version %d", latestVersion*2) + s.Require().NoError(commitStore.Prune(latestVersion * 2)) + // GetProof should fail for the newly deleted stores + for i := uint64(1); i < latestVersion*2; i++ { + for j := 0; j < kvCount; j++ { + _, err := commitStore.GetProof([]byte(storeKey2), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().Error(err) + } + } + s.T().Log("GetProof should work for the new added store") + // GetProof should work for the new added store + for i := latestVersion*2 + 1; i < latestVersion*3; i++ { + for j := 0; j < kvCount; j++ { + proof, err := commitStore.GetProof([]byte("newStore3"), i, []byte(fmt.Sprintf("key-%d-%d", i, j))) + s.Require().NoError(err) + s.Require().NotNil(proof) + } + } +} diff --git a/store/v2/go.mod b/store/v2/go.mod new file mode 100644 index 000000000000..dcb57635f47c --- /dev/null +++ b/store/v2/go.mod @@ -0,0 +1,76 @@ +module cosmossdk.io/store/v2 + +go 1.23 + +require ( + cosmossdk.io/core v1.0.0 + cosmossdk.io/core/testing v0.0.1 + cosmossdk.io/errors/v2 v2.0.0 + cosmossdk.io/log v1.5.0 + github.com/cockroachdb/pebble v1.1.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.5 + github.com/cosmos/gogoproto v1.7.0 + github.com/cosmos/iavl v1.3.4 + github.com/cosmos/iavl/v2 v2.0.0-alpha.4 + github.com/cosmos/ics23/go v0.11.0 + github.com/google/btree v1.1.3 + github.com/hashicorp/go-metrics v0.5.4 + github.com/spf13/cast v1.7.1 + github.com/stretchr/testify v1.10.0 + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d + go.uber.org/mock v0.5.0 + golang.org/x/sync v0.10.0 + google.golang.org/protobuf v1.36.2 +) + +require ( + cosmossdk.io/schema v1.0.0 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bvinc/go-sqlite-lite v0.6.1 // indirect + github.com/bytedance/sonic v1.12.6 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/emicklei/dot v1.6.2 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-uuid v1.0.1 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/kocubinski/costor-api v1.1.1 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.61.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect + github.com/tidwall/btree v1.7.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.12.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/store/v2/migration/manager.go b/store/v2/migration/manager.go new file mode 100644 index 000000000000..18bf6d4c9b7a --- /dev/null +++ b/store/v2/migration/manager.go @@ -0,0 +1,210 @@ +package migration + +import ( + "encoding/binary" + "errors" + "fmt" + "sync/atomic" + "time" + + "golang.org/x/sync/errgroup" + + "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2/commitment" + "cosmossdk.io/store/v2/internal/encoding" + "cosmossdk.io/store/v2/snapshots" +) + +const ( + // defaultChannelBufferSize is the default buffer size for the migration stream. + defaultChannelBufferSize = 1024 + + migrateChangesetKeyFmt = "m/cs_%x" // m/cs_ +) + +// VersionedChangeset is a pair of version and Changeset. +type VersionedChangeset struct { + Version uint64 + Changeset *corestore.Changeset +} + +// Manager manages the migration of the whole state from store/v1 to store/v2. +type Manager struct { + logger log.Logger + snapshotsManager *snapshots.Manager + + stateCommitment *commitment.CommitStore + + db corestore.KVStoreWithBatch + + migratedVersion atomic.Uint64 + + chChangeset <-chan *VersionedChangeset + chDone <-chan struct{} +} + +// NewManager returns a new Manager. +// +// NOTE: `sc` can be `nil` if don't want to migrate the commitment. +func NewManager(db corestore.KVStoreWithBatch, sm *snapshots.Manager, sc *commitment.CommitStore, logger log.Logger) *Manager { + return &Manager{ + logger: logger, + snapshotsManager: sm, + stateCommitment: sc, + db: db, + } +} + +// Start starts the whole migration process. +// It migrates the whole state at the given version to the new store/v2 (both SC and SS). +// It also catches up the Changesets which are committed while the migration is in progress. +// `chChangeset` is the channel to receive the committed Changesets from the RootStore. +// `chDone` is the channel to receive the done signal from the RootStore. +// NOTE: It should be called by the RootStore, running in the background. +func (m *Manager) Start(version uint64, chChangeset <-chan *VersionedChangeset, chDone <-chan struct{}) error { + m.chChangeset = chChangeset + m.chDone = chDone + + go func() { + if err := m.writeChangeset(); err != nil { + m.logger.Error("failed to write changeset", "err", err) + } + }() + + if err := m.Migrate(version); err != nil { + return fmt.Errorf("failed to migrate state: %w", err) + } + + return m.Sync() +} + +// GetStateCommitment returns the state commitment. +func (m *Manager) GetStateCommitment() *commitment.CommitStore { + return m.stateCommitment +} + +// Migrate migrates the whole state at the given height to the new store/v2. +func (m *Manager) Migrate(height uint64) error { + // create the migration stream and snapshot, + // which acts as protoio.Reader and snapshots.WriteCloser. + ms := NewMigrationStream(defaultChannelBufferSize) + if err := m.snapshotsManager.CreateMigration(height, ms); err != nil { + return err + } + + eg := new(errgroup.Group) + eg.Go(func() error { + if _, err := m.stateCommitment.Restore(height, 0, ms); err != nil { + return err + } + return nil + }) + + if err := eg.Wait(); err != nil { + return err + } + + m.migratedVersion.Store(height) + + return nil +} + +// writeChangeset writes the Changeset to the db. +func (m *Manager) writeChangeset() error { + for vc := range m.chChangeset { + cs := vc.Changeset + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, vc.Version) + csKey := []byte(fmt.Sprintf(migrateChangesetKeyFmt, buf)) + csBytes, err := encoding.MarshalChangeset(cs) + if err != nil { + return fmt.Errorf("failed to marshal changeset: %w", err) + } + + batch := m.db.NewBatch() + // Invoking this code in a closure so that defer is called immediately on return + // yet not in the for-loop which can leave resource lingering. + err = func() (err error) { + defer func() { + err = errors.Join(err, batch.Close()) + }() + + if err := batch.Set(csKey, csBytes); err != nil { + return fmt.Errorf("failed to write changeset to db.Batch: %w", err) + } + if err := batch.Write(); err != nil { + return fmt.Errorf("failed to write changeset to db: %w", err) + } + return nil + }() + if err != nil { + return err + } + } + + return nil +} + +// GetMigratedVersion returns the migrated version. +// It is used to check the migrated version in the RootStore. +func (m *Manager) GetMigratedVersion() uint64 { + return m.migratedVersion.Load() +} + +// Sync catches up the Changesets which are committed while the migration is in progress. +// It should be called after the migration is done. +func (m *Manager) Sync() error { + version := m.GetMigratedVersion() + if version == 0 { + return errors.New("migration is not done yet") + } + version += 1 + + for { + select { + case <-m.chDone: + return nil + default: + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, version) + csKey := []byte(fmt.Sprintf(migrateChangesetKeyFmt, buf)) + csBytes, err := m.db.Get(csKey) + if err != nil { + return fmt.Errorf("failed to get changeset from db: %w", err) + } + if csBytes == nil { + // wait for the next changeset + time.Sleep(100 * time.Millisecond) + continue + } + + cs := corestore.NewChangeset(version) + if err := encoding.UnmarshalChangeset(cs, csBytes); err != nil { + return fmt.Errorf("failed to unmarshal changeset: %w", err) + } + if m.stateCommitment != nil { + if err := m.stateCommitment.WriteChangeset(cs); err != nil { + return fmt.Errorf("failed to write changeset to commitment: %w", err) + } + if _, err := m.stateCommitment.Commit(version); err != nil { + return fmt.Errorf("failed to commit changeset to commitment: %w", err) + } + } + + m.migratedVersion.Store(version) + + version += 1 + } + } +} + +// Close closes the manager. It should be called after the migration is done. +// It will notify the snapshotsManager that the migration is done. +func (m *Manager) Close() error { + if m.stateCommitment != nil { + m.snapshotsManager.EndMigration(m.stateCommitment) + } + + return nil +} diff --git a/store/v2/migration/manager_test.go b/store/v2/migration/manager_test.go new file mode 100644 index 000000000000..f5382ac33011 --- /dev/null +++ b/store/v2/migration/manager_test.go @@ -0,0 +1,178 @@ +package migration + +import ( + "encoding/binary" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + corestore "cosmossdk.io/core/store" + coretesting "cosmossdk.io/core/testing" + "cosmossdk.io/store/v2/commitment" + "cosmossdk.io/store/v2/commitment/iavl" + dbm "cosmossdk.io/store/v2/db" + "cosmossdk.io/store/v2/snapshots" +) + +var storeKeys = []string{"store1", "store2"} + +func setupMigrationManager(t *testing.T) (*Manager, *commitment.CommitStore) { + t.Helper() + + db := dbm.NewMemDB() + multiTrees := make(map[string]commitment.Tree) + for _, storeKey := range storeKeys { + prefixDB := dbm.NewPrefixDB(db, []byte(storeKey)) + multiTrees[storeKey] = iavl.NewIavlTree(prefixDB, coretesting.NewNopLogger(), iavl.DefaultConfig()) + } + commitStore, err := commitment.NewCommitStore(multiTrees, nil, db, coretesting.NewNopLogger()) + require.NoError(t, err) + + snapshotsStore, err := snapshots.NewStore(t.TempDir()) + require.NoError(t, err) + + snapshotsManager := snapshots.NewManager(snapshotsStore, snapshots.NewSnapshotOptions(1500, 2), commitStore, nil, coretesting.NewNopLogger()) + + db1 := dbm.NewMemDB() + multiTrees1 := make(map[string]commitment.Tree) + for _, storeKey := range storeKeys { + prefixDB := dbm.NewPrefixDB(db1, []byte(storeKey)) + multiTrees1[storeKey] = iavl.NewIavlTree(prefixDB, coretesting.NewNopLogger(), iavl.DefaultConfig()) + } + + newCommitStore, err := commitment.NewCommitStore(multiTrees1, nil, db1, coretesting.NewNopLogger()) // for store/v2 + require.NoError(t, err) + + return NewManager(db, snapshotsManager, newCommitStore, coretesting.NewNopLogger()), commitStore +} + +func TestMigrateState(t *testing.T) { + m, orgCommitStore := setupMigrationManager(t) + // apply changeset + toVersion := uint64(100) + keyCount := 10 + for version := uint64(1); version <= toVersion; version++ { + cs := corestore.NewChangeset(version) + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + cs.Add([]byte(storeKey), []byte(fmt.Sprintf("key-%d-%d", version, i)), []byte(fmt.Sprintf("value-%d-%d", version, i)), false) + } + } + require.NoError(t, orgCommitStore.WriteChangeset(cs)) + _, err := orgCommitStore.Commit(version) + require.NoError(t, err) + } + + err := m.Migrate(toVersion - 1) + require.NoError(t, err) + + // expecting error for conflicting process, since Migrate trigger snapshotter create migration, + // which start a snapshot process already. + _, err = m.snapshotsManager.Create(toVersion - 1) + require.Error(t, err) + + // check the migrated state + for version := uint64(1); version < toVersion; version++ { + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + val, err := m.stateCommitment.Get([]byte(storeKey), toVersion-1, []byte(fmt.Sprintf("key-%d-%d", version, i))) + require.NoError(t, err) + require.Equal(t, []byte(fmt.Sprintf("value-%d-%d", version, i)), val) + } + } + + // check the latest state + val, err := m.stateCommitment.Get([]byte("store1"), toVersion-1, []byte("key-100-1")) + require.NoError(t, err) + require.Nil(t, val) + val, err = m.stateCommitment.Get([]byte("store2"), toVersion-1, []byte("key-100-0")) + require.NoError(t, err) + require.Nil(t, val) + } +} + +func TestStartMigrateState(t *testing.T) { + m, orgCommitStore := setupMigrationManager(t) + + chDone := make(chan struct{}) + chChangeset := make(chan *VersionedChangeset, 1) + + // apply changeset + toVersion := uint64(10) + keyCount := 5 + changesets := []corestore.Changeset{} + + for version := uint64(1); version <= toVersion; version++ { + cs := corestore.NewChangeset(version) + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + cs.Add([]byte(storeKey), []byte(fmt.Sprintf("key-%d-%d", version, i)), []byte(fmt.Sprintf("value-%d-%d", version, i)), false) + } + } + changesets = append(changesets, *cs) + require.NoError(t, orgCommitStore.WriteChangeset(cs)) + _, err := orgCommitStore.Commit(version) + require.NoError(t, err) + } + + // feed changesets to channel + go func() { + for version := uint64(1); version <= toVersion; version++ { + chChangeset <- &VersionedChangeset{ + Version: version, + Changeset: &changesets[version-1], + } + } + }() + + // check if migrate process complete + go func() { + for { + migrateVersion := m.GetMigratedVersion() + if migrateVersion == toVersion-1 { + break + } + } + + chDone <- struct{}{} + }() + + err := m.Start(toVersion-1, chChangeset, chDone) + require.NoError(t, err) + + // expecting error for conflicting process, since Migrate trigger snapshotter create migration, + // which start a snapshot process already. + _, err = m.snapshotsManager.Create(toVersion - 1) + require.Error(t, err) + + if m.stateCommitment != nil { + // check the migrated state + for version := uint64(1); version < toVersion; version++ { + for _, storeKey := range storeKeys { + for i := 0; i < keyCount; i++ { + val, err := m.stateCommitment.Get([]byte(storeKey), toVersion-1, []byte(fmt.Sprintf("key-%d-%d", version, i))) + require.NoError(t, err) + require.Equal(t, []byte(fmt.Sprintf("value-%d-%d", version, i)), val) + } + } + } + // check the latest state + val, err := m.stateCommitment.Get([]byte("store1"), toVersion-1, []byte("key-100-1")) + require.NoError(t, err) + require.Nil(t, val) + val, err = m.stateCommitment.Get([]byte("store2"), toVersion-1, []byte("key-100-0")) + require.NoError(t, err) + require.Nil(t, val) + } + + // check if migration db write change set to storage + for version := uint64(1); version < toVersion; version++ { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, version) + csKey := []byte(fmt.Sprintf(migrateChangesetKeyFmt, buf)) + csVal, err := m.db.Get(csKey) + require.NoError(t, err) + require.NotEmpty(t, csVal) + } +} diff --git a/store/v2/proof/commit_info.go b/store/v2/proof/commit_info.go new file mode 100644 index 000000000000..b42b401ae61d --- /dev/null +++ b/store/v2/proof/commit_info.go @@ -0,0 +1,86 @@ +package proof + +import ( + "fmt" + "sort" + "strings" +) + +func (si StoreInfo) GetHash() []byte { + return si.CommitId.Hash +} + +// Hash returns the root hash of all committed stores represented by CommitInfo, +// sorted by store name/key. +func (ci *CommitInfo) Hash() []byte { + if len(ci.StoreInfos) == 0 { + return nil + } + + if len(ci.CommitHash) != 0 { + return ci.CommitHash + } + + rootHash, _, _ := ci.GetStoreProof([]byte{}) + return rootHash +} + +// GetStoreCommitID returns the CommitID for the given store key. +func (ci *CommitInfo) GetStoreCommitID(storeKey []byte) *CommitID { + for _, si := range ci.StoreInfos { + if strings.EqualFold(si.Name, string(storeKey)) { + return si.CommitId + } + } + return &CommitID{} +} + +// GetStoreProof takes in a storeKey and returns a proof of the store key in addition +// to the root hash it should be proved against. If an empty string is provided, the first +// store based on lexographical ordering will be proved. +func (ci *CommitInfo) GetStoreProof(storeKey []byte) ([]byte, *CommitmentOp, error) { + sort.Slice(ci.StoreInfos, func(i, j int) bool { + return strings.Compare(ci.StoreInfos[i].Name, ci.StoreInfos[j].Name) < 0 + }) + + isEmpty := len(storeKey) == 0 + index := -1 + leaves := make([][]byte, len(ci.StoreInfos)) + for i, si := range ci.StoreInfos { + var err error + leaves[i], err = LeafHash([]byte(si.Name), si.GetHash()) + if err != nil { + return nil, nil, err + } + if !isEmpty && strings.EqualFold(si.Name, string(storeKey)) { + index = i + } + } + + if index == -1 { + if isEmpty { + index = 0 + } else { + return nil, nil, fmt.Errorf("store key %s not found", storeKey) + } + } + + rootHash, inners := ProofFromByteSlices(leaves, index) + commitmentOp := ConvertCommitmentOp(inners, storeKey, ci.StoreInfos[index].GetHash()) + return rootHash, &commitmentOp, nil +} + +func (ci *CommitInfo) CommitID() *CommitID { + return &CommitID{ + Version: ci.Version, + Hash: ci.Hash(), + } +} + +func (cid *CommitID) String() string { + return fmt.Sprintf("CommitID{%v:%X}", cid.Hash, cid.Version) +} + +func (cid *CommitID) IsZero() bool { + return cid.Version == 0 && len(cid.Hash) == 0 +} diff --git a/store/v2/proof/commit_info.pb.go b/store/v2/proof/commit_info.pb.go new file mode 100644 index 000000000000..26811186fd4c --- /dev/null +++ b/store/v2/proof/commit_info.pb.go @@ -0,0 +1,975 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/store/v2/commit_info.proto + +package proof + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// 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 + +// CommitInfo defines commit information used by the multi-store when committing +// a version/height. +type CommitInfo struct { + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + StoreInfos []*StoreInfo `protobuf:"bytes,2,rep,name=store_infos,json=storeInfos,proto3" json:"store_infos,omitempty"` + Timestamp time.Time `protobuf:"bytes,3,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + CommitHash []byte `protobuf:"bytes,4,opt,name=commit_hash,json=commitHash,proto3" json:"commit_hash,omitempty"` +} + +func (m *CommitInfo) Reset() { *m = CommitInfo{} } +func (m *CommitInfo) String() string { return proto.CompactTextString(m) } +func (*CommitInfo) ProtoMessage() {} +func (*CommitInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_fae1fdc51331137e, []int{0} +} +func (m *CommitInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommitInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommitInfo.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 *CommitInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommitInfo.Merge(m, src) +} +func (m *CommitInfo) XXX_Size() int { + return m.Size() +} +func (m *CommitInfo) XXX_DiscardUnknown() { + xxx_messageInfo_CommitInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_CommitInfo proto.InternalMessageInfo + +func (m *CommitInfo) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *CommitInfo) GetStoreInfos() []*StoreInfo { + if m != nil { + return m.StoreInfos + } + return nil +} + +func (m *CommitInfo) GetTimestamp() time.Time { + if m != nil { + return m.Timestamp + } + return time.Time{} +} + +func (m *CommitInfo) GetCommitHash() []byte { + if m != nil { + return m.CommitHash + } + return nil +} + +// StoreInfo defines store-specific commit information. It contains a reference +// between a store name and the commit ID. +type StoreInfo struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + CommitId *CommitID `protobuf:"bytes,2,opt,name=commit_id,json=commitId,proto3" json:"commit_id,omitempty"` + Structure string `protobuf:"bytes,3,opt,name=structure,proto3" json:"structure,omitempty"` +} + +func (m *StoreInfo) Reset() { *m = StoreInfo{} } +func (m *StoreInfo) String() string { return proto.CompactTextString(m) } +func (*StoreInfo) ProtoMessage() {} +func (*StoreInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_fae1fdc51331137e, []int{1} +} +func (m *StoreInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StoreInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StoreInfo.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 *StoreInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoreInfo.Merge(m, src) +} +func (m *StoreInfo) XXX_Size() int { + return m.Size() +} +func (m *StoreInfo) XXX_DiscardUnknown() { + xxx_messageInfo_StoreInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_StoreInfo proto.InternalMessageInfo + +func (m *StoreInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *StoreInfo) GetCommitId() *CommitID { + if m != nil { + return m.CommitId + } + return nil +} + +func (m *StoreInfo) GetStructure() string { + if m != nil { + return m.Structure + } + return "" +} + +// CommitID defines the commitment information when a specific store is +// committed. +type CommitID struct { + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *CommitID) Reset() { *m = CommitID{} } +func (*CommitID) ProtoMessage() {} +func (*CommitID) Descriptor() ([]byte, []int) { + return fileDescriptor_fae1fdc51331137e, []int{2} +} +func (m *CommitID) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommitID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommitID.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 *CommitID) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommitID.Merge(m, src) +} +func (m *CommitID) XXX_Size() int { + return m.Size() +} +func (m *CommitID) XXX_DiscardUnknown() { + xxx_messageInfo_CommitID.DiscardUnknown(m) +} + +var xxx_messageInfo_CommitID proto.InternalMessageInfo + +func (m *CommitID) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *CommitID) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + +func init() { + proto.RegisterType((*CommitInfo)(nil), "cosmos.store.v2.CommitInfo") + proto.RegisterType((*StoreInfo)(nil), "cosmos.store.v2.StoreInfo") + proto.RegisterType((*CommitID)(nil), "cosmos.store.v2.CommitID") +} + +func init() { proto.RegisterFile("cosmos/store/v2/commit_info.proto", fileDescriptor_fae1fdc51331137e) } + +var fileDescriptor_fae1fdc51331137e = []byte{ + // 355 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x31, 0x4f, 0xc2, 0x50, + 0x10, 0xc7, 0xfb, 0xa0, 0x51, 0x7a, 0x98, 0x98, 0xbc, 0x38, 0x54, 0x34, 0x6d, 0x65, 0x62, 0x7a, + 0x4d, 0x30, 0x3a, 0x68, 0xe2, 0x80, 0x0e, 0xb2, 0x56, 0x27, 0x17, 0x53, 0xa0, 0x2d, 0x8d, 0xb6, + 0x47, 0xfa, 0x5e, 0xf9, 0x1c, 0x8c, 0x8e, 0x7e, 0x1c, 0x46, 0x46, 0x27, 0x35, 0xf0, 0x45, 0x0c, + 0xf7, 0x28, 0x24, 0x9a, 0xb8, 0xfd, 0xdf, 0xf5, 0x7f, 0x77, 0xbf, 0xfb, 0xa7, 0x70, 0x36, 0x44, + 0x99, 0xa1, 0xf4, 0xa5, 0xc2, 0x22, 0xf2, 0xa7, 0x5d, 0x7f, 0x88, 0x59, 0x96, 0xaa, 0xe7, 0x34, + 0x8f, 0x51, 0x4c, 0x0a, 0x54, 0xc8, 0x0f, 0xb5, 0x45, 0x90, 0x45, 0x4c, 0xbb, 0xad, 0xa3, 0x04, + 0x13, 0xa4, 0x6f, 0xfe, 0x5a, 0x69, 0x5b, 0xcb, 0x4d, 0x10, 0x93, 0xd7, 0xc8, 0xa7, 0xd7, 0xa0, + 0x8c, 0x7d, 0x95, 0x66, 0x91, 0x54, 0x61, 0x36, 0xd1, 0x86, 0xf6, 0x9c, 0x01, 0xdc, 0xd2, 0xf4, + 0x7e, 0x1e, 0x23, 0xb7, 0x61, 0x7f, 0x1a, 0x15, 0x32, 0xc5, 0xdc, 0x66, 0x1e, 0xeb, 0xd4, 0x83, + 0xea, 0xc9, 0xaf, 0xa1, 0x49, 0xbb, 0x08, 0x42, 0xda, 0x35, 0xaf, 0xde, 0x69, 0x76, 0x5b, 0xe2, + 0x17, 0x86, 0x78, 0x58, 0x8b, 0xf5, 0xa8, 0x00, 0x64, 0x25, 0x25, 0xef, 0x81, 0xb5, 0x5d, 0x6c, + 0xd7, 0x3d, 0x46, 0xad, 0x1a, 0x4d, 0x54, 0x68, 0xe2, 0xb1, 0x72, 0xf4, 0x1a, 0xf3, 0x4f, 0xd7, + 0x98, 0x7d, 0xb9, 0x2c, 0xd8, 0xb5, 0x71, 0x17, 0x9a, 0x9b, 0x18, 0xc6, 0xa1, 0x1c, 0xdb, 0xa6, + 0xc7, 0x3a, 0x07, 0x01, 0xe8, 0xd2, 0x7d, 0x28, 0xc7, 0xed, 0x12, 0xac, 0xed, 0x76, 0xce, 0xc1, + 0xcc, 0xc3, 0x2c, 0xa2, 0x2b, 0xac, 0x80, 0x34, 0xbf, 0x04, 0xab, 0x0a, 0x72, 0x64, 0xd7, 0x88, + 0xe2, 0xf8, 0xcf, 0x01, 0x9b, 0x30, 0xee, 0x82, 0x86, 0xf6, 0xf6, 0x47, 0xfc, 0x14, 0x2c, 0xa9, + 0x8a, 0x72, 0xa8, 0xca, 0x22, 0x22, 0x7a, 0x2b, 0xd8, 0x15, 0xda, 0x37, 0xd0, 0xa8, 0x7a, 0xfe, + 0x89, 0x8f, 0x83, 0x49, 0xd8, 0x35, 0xc2, 0x26, 0x7d, 0x65, 0xbe, 0xbd, 0xbb, 0x46, 0xef, 0x62, + 0xbe, 0x74, 0xd8, 0x62, 0xe9, 0xb0, 0xef, 0xa5, 0xc3, 0x66, 0x2b, 0xc7, 0x58, 0xac, 0x1c, 0xe3, + 0x63, 0xe5, 0x18, 0x4f, 0x27, 0x9a, 0x4d, 0x8e, 0x5e, 0x44, 0x8a, 0xbb, 0x9f, 0x61, 0x52, 0x20, + 0xc6, 0x83, 0x3d, 0xca, 0xed, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x18, 0xd0, 0x41, 0xbe, 0x2c, + 0x02, 0x00, 0x00, +} + +func (m *CommitInfo) 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 *CommitInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CommitHash) > 0 { + i -= len(m.CommitHash) + copy(dAtA[i:], m.CommitHash) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.CommitHash))) + i-- + dAtA[i] = 0x22 + } + n1, err1 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintCommitInfo(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x1a + if len(m.StoreInfos) > 0 { + for iNdEx := len(m.StoreInfos) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StoreInfos[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommitInfo(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Version != 0 { + i = encodeVarintCommitInfo(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *StoreInfo) 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 *StoreInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StoreInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Structure) > 0 { + i -= len(m.Structure) + copy(dAtA[i:], m.Structure) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.Structure))) + i-- + dAtA[i] = 0x1a + } + if m.CommitId != nil { + { + size, err := m.CommitId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommitInfo(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CommitID) 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 *CommitID) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommitID) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x12 + } + if m.Version != 0 { + i = encodeVarintCommitInfo(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintCommitInfo(dAtA []byte, offset int, v uint64) int { + offset -= sovCommitInfo(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *CommitInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovCommitInfo(uint64(m.Version)) + } + if len(m.StoreInfos) > 0 { + for _, e := range m.StoreInfos { + l = e.Size() + n += 1 + l + sovCommitInfo(uint64(l)) + } + } + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovCommitInfo(uint64(l)) + l = len(m.CommitHash) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + return n +} + +func (m *StoreInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + if m.CommitId != nil { + l = m.CommitId.Size() + n += 1 + l + sovCommitInfo(uint64(l)) + } + l = len(m.Structure) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + return n +} + +func (m *CommitID) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovCommitInfo(uint64(m.Version)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + return n +} + +func sovCommitInfo(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCommitInfo(x uint64) (n int) { + return sovCommitInfo(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *CommitInfo) 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 ErrIntOverflowCommitInfo + } + 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: CommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StoreInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StoreInfos = append(m.StoreInfos, &StoreInfo{}) + if err := m.StoreInfos[len(m.StoreInfos)-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 Timestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommitHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CommitHash = append(m.CommitHash[:0], dAtA[iNdEx:postIndex]...) + if m.CommitHash == nil { + m.CommitHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreInfo) 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 ErrIntOverflowCommitInfo + } + 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: StoreInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommitId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CommitId == nil { + m.CommitId = &CommitID{} + } + if err := m.CommitId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Structure", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Structure = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CommitID) 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 ErrIntOverflowCommitInfo + } + 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: CommitID: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommitID: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCommitInfo(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, ErrIntOverflowCommitInfo + } + 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, ErrIntOverflowCommitInfo + } + 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, ErrIntOverflowCommitInfo + } + 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, ErrInvalidLengthCommitInfo + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCommitInfo + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCommitInfo + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCommitInfo = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCommitInfo = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCommitInfo = fmt.Errorf("proto: unexpected end of group") +) diff --git a/store/v2/proof/commit_info_test.go b/store/v2/proof/commit_info_test.go new file mode 100644 index 000000000000..61f4f48412ab --- /dev/null +++ b/store/v2/proof/commit_info_test.go @@ -0,0 +1,71 @@ +package proof + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestGetStoreProof(t *testing.T) { + tests := []struct { + storeInfos []*StoreInfo + }{ + {[]*StoreInfo{ + {("key1"), &CommitID{1, []byte("value1")}, "iavl"}, + }}, + {[]*StoreInfo{ + {("key2"), &CommitID{1, []byte("value2")}, "iavl"}, + {("key1"), &CommitID{1, []byte("value1")}, "iavl"}, + }}, + {[]*StoreInfo{ + {("key3"), &CommitID{1, []byte("value3")}, "iavl"}, + {("key2"), &CommitID{1, []byte("value2")}, "iavl"}, + {("key1"), &CommitID{1, []byte("value1")}, "iavl"}, + }}, + {[]*StoreInfo{ + {("key2"), &CommitID{1, []byte("value2")}, "iavl"}, + {("key1"), &CommitID{1, []byte("value1")}, "iavl"}, + {("key3"), &CommitID{1, []byte("value3")}, "iavl"}, + }}, + {[]*StoreInfo{ + {("key4"), &CommitID{1, []byte("value4")}, "iavl"}, + {("key1"), &CommitID{1, []byte("value1")}, "iavl"}, + {("key3"), &CommitID{1, []byte("value3")}, "iavl"}, + {("key2"), &CommitID{1, []byte("value2")}, "iavl"}, + }}, + } + + for i, tc := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + // create a commit info + ci := &CommitInfo{ + Version: 1, + Timestamp: time.Now(), + StoreInfos: tc.storeInfos, + } + commitHash := ci.Hash() + // make sure the store infos are sorted + require.Equal(t, ci.StoreInfos[0].Name, "key1") + for _, si := range tc.storeInfos { + // get the proof + _, proof, err := ci.GetStoreProof([]byte(si.Name)) + require.NoError(t, err, "test case %d", i) + // verify the proof + expRoots, err := proof.Run([][]byte{si.CommitId.Hash}) + require.NoError(t, err, "test case %d", i) + require.Equal(t, commitHash, expRoots[0], "test case %d", i) + + bz, err := ci.Marshal() + require.NoError(t, err) + ci2 := &CommitInfo{} + err = ci2.Unmarshal(bz) + require.NoError(t, err) + require.True(t, ci.Timestamp.Equal(ci2.Timestamp)) + ci2.Timestamp = ci.Timestamp + require.Equal(t, ci, ci2) + } + }) + } +} diff --git a/store/v2/proof/v1/types/commit_info.pb.go b/store/v2/proof/v1/types/commit_info.pb.go new file mode 100644 index 000000000000..aa3c6788690f --- /dev/null +++ b/store/v2/proof/v1/types/commit_info.pb.go @@ -0,0 +1,859 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/store/v1beta1/commit_info.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// 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 + +// CommitInfo defines commit information used by the multi-store when committing +// a version/height. +type CommitInfo struct { + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + StoreInfos []StoreInfo `protobuf:"bytes,2,rep,name=store_infos,json=storeInfos,proto3" json:"store_infos"` + Timestamp time.Time `protobuf:"bytes,3,opt,name=timestamp,proto3,stdtime" json:"timestamp"` +} + +func (m *CommitInfo) Reset() { *m = CommitInfo{} } +func (m *CommitInfo) String() string { return proto.CompactTextString(m) } +func (*CommitInfo) ProtoMessage() {} +func (*CommitInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_5f8c656cdef8c524, []int{0} +} +func (m *CommitInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommitInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommitInfo.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 *CommitInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommitInfo.Merge(m, src) +} +func (m *CommitInfo) XXX_Size() int { + return m.Size() +} +func (m *CommitInfo) XXX_DiscardUnknown() { + xxx_messageInfo_CommitInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_CommitInfo proto.InternalMessageInfo + +func (m *CommitInfo) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *CommitInfo) GetStoreInfos() []StoreInfo { + if m != nil { + return m.StoreInfos + } + return nil +} + +func (m *CommitInfo) GetTimestamp() time.Time { + if m != nil { + return m.Timestamp + } + return time.Time{} +} + +// StoreInfo defines store-specific commit information. It contains a reference +// between a store name and the commit ID. +type StoreInfo struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + CommitId CommitID `protobuf:"bytes,2,opt,name=commit_id,json=commitId,proto3" json:"commit_id"` +} + +func (m *StoreInfo) Reset() { *m = StoreInfo{} } +func (m *StoreInfo) String() string { return proto.CompactTextString(m) } +func (*StoreInfo) ProtoMessage() {} +func (*StoreInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_5f8c656cdef8c524, []int{1} +} +func (m *StoreInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StoreInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StoreInfo.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 *StoreInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoreInfo.Merge(m, src) +} +func (m *StoreInfo) XXX_Size() int { + return m.Size() +} +func (m *StoreInfo) XXX_DiscardUnknown() { + xxx_messageInfo_StoreInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_StoreInfo proto.InternalMessageInfo + +func (m *StoreInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *StoreInfo) GetCommitId() CommitID { + if m != nil { + return m.CommitId + } + return CommitID{} +} + +// CommitID defines the commitment information when a specific store is +// committed. +type CommitID struct { + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *CommitID) Reset() { *m = CommitID{} } +func (*CommitID) ProtoMessage() {} +func (m *CommitID) String() string { + return fmt.Sprintf("CommitID{%v:%X}", m.Hash, m.Version) +} +func (*CommitID) Descriptor() ([]byte, []int) { + return fileDescriptor_5f8c656cdef8c524, []int{2} +} +func (m *CommitID) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommitID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommitID.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 *CommitID) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommitID.Merge(m, src) +} +func (m *CommitID) XXX_Size() int { + return m.Size() +} +func (m *CommitID) XXX_DiscardUnknown() { + xxx_messageInfo_CommitID.DiscardUnknown(m) +} + +var xxx_messageInfo_CommitID proto.InternalMessageInfo + +func (m *CommitID) GetVersion() int64 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *CommitID) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + + + +var fileDescriptor_5f8c656cdef8c524 = []byte{ + // 336 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0x4e, 0xf2, 0x50, + 0x14, 0xc7, 0x7b, 0xa1, 0xf9, 0x3e, 0x7a, 0x70, 0xba, 0x61, 0x68, 0x18, 0x6e, 0x09, 0x83, 0x61, + 0xba, 0x0d, 0xb8, 0x39, 0x98, 0x58, 0x8d, 0x09, 0x6b, 0x75, 0x72, 0x31, 0x2d, 0x5c, 0x4a, 0xa3, + 0xed, 0x21, 0xdc, 0x2b, 0x89, 0x6f, 0xc1, 0xe8, 0xe8, 0x33, 0xf8, 0x14, 0x8c, 0x8c, 0x4e, 0x6a, + 0xe0, 0x45, 0x4c, 0x4f, 0x5b, 0x5c, 0x88, 0xdb, 0x39, 0xed, 0xef, 0x9c, 0xff, 0xaf, 0xa7, 0x70, + 0x3a, 0x41, 0x9d, 0xa1, 0xf6, 0xb5, 0xc1, 0xa5, 0xf2, 0x57, 0xc3, 0x58, 0x99, 0x68, 0xe8, 0x4f, + 0x30, 0xcb, 0x52, 0xf3, 0x90, 0xe6, 0x33, 0x94, 0x8b, 0x25, 0x1a, 0xe4, 0x9d, 0x92, 0x93, 0xc4, + 0xc9, 0x8a, 0xeb, 0x76, 0x12, 0x4c, 0x90, 0x00, 0xbf, 0xa8, 0x4a, 0xb6, 0xeb, 0x25, 0x88, 0xc9, + 0x93, 0xf2, 0xa9, 0x8b, 0x9f, 0x67, 0xbe, 0x49, 0x33, 0xa5, 0x4d, 0x94, 0x2d, 0x4a, 0xa0, 0xff, + 0xce, 0x00, 0xae, 0x28, 0x62, 0x9c, 0xcf, 0x90, 0xbb, 0xf0, 0x7f, 0xa5, 0x96, 0x3a, 0xc5, 0xdc, + 0x65, 0x3d, 0x36, 0x68, 0x86, 0x75, 0xcb, 0x6f, 0xa0, 0x4d, 0x81, 0x64, 0xa2, 0xdd, 0x46, 0xaf, + 0x39, 0x68, 0x8f, 0x3c, 0x79, 0xcc, 0x45, 0xde, 0x16, 0x5d, 0xb1, 0x2f, 0xb0, 0x37, 0x9f, 0x9e, + 0x15, 0x82, 0xae, 0x1f, 0x68, 0x1e, 0x80, 0x73, 0x70, 0x70, 0x9b, 0x3d, 0x36, 0x68, 0x8f, 0xba, + 0xb2, 0xb4, 0x94, 0xb5, 0xa5, 0xbc, 0xab, 0x89, 0xa0, 0x55, 0x2c, 0x58, 0x7f, 0x79, 0x2c, 0xfc, + 0x1d, 0xeb, 0xc7, 0xe0, 0x1c, 0x22, 0x38, 0x07, 0x3b, 0x8f, 0x32, 0x45, 0xbe, 0x4e, 0x48, 0x35, + 0xbf, 0x04, 0xa7, 0xbe, 0xdb, 0xd4, 0x6d, 0x50, 0x88, 0x38, 0xae, 0x5a, 0x7d, 0xfb, 0x75, 0x65, + 0xda, 0x2a, 0xc7, 0xc6, 0xd3, 0xfe, 0x05, 0xb4, 0xea, 0x77, 0x7f, 0x5c, 0x85, 0x83, 0x3d, 0x8f, + 0xf4, 0x9c, 0x32, 0x4e, 0x42, 0xaa, 0xcf, 0xed, 0xd7, 0x37, 0xcf, 0x0a, 0x46, 0x9b, 0x9d, 0x60, + 0xdb, 0x9d, 0x60, 0xdf, 0x3b, 0xc1, 0xd6, 0x7b, 0x61, 0x6d, 0xf7, 0xc2, 0xfa, 0xd8, 0x0b, 0xeb, + 0xde, 0x2d, 0x45, 0xf4, 0xf4, 0x51, 0xa6, 0x58, 0xfd, 0x6d, 0xf3, 0xb2, 0x50, 0x3a, 0xfe, 0x47, + 0x07, 0x38, 0xfb, 0x09, 0x00, 0x00, 0xff, 0xff, 0x67, 0xb7, 0x0d, 0x59, 0x0a, 0x02, 0x00, 0x00, +} + +func (m *CommitInfo) 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 *CommitInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintCommitInfo(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x1a + if len(m.StoreInfos) > 0 { + for iNdEx := len(m.StoreInfos) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StoreInfos[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommitInfo(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Version != 0 { + i = encodeVarintCommitInfo(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *StoreInfo) 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 *StoreInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StoreInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.CommitId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommitInfo(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CommitID) 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 *CommitID) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommitID) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintCommitInfo(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x12 + } + if m.Version != 0 { + i = encodeVarintCommitInfo(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintCommitInfo(dAtA []byte, offset int, v uint64) int { + offset -= sovCommitInfo(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *CommitInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovCommitInfo(uint64(m.Version)) + } + if len(m.StoreInfos) > 0 { + for _, e := range m.StoreInfos { + l = e.Size() + n += 1 + l + sovCommitInfo(uint64(l)) + } + } + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovCommitInfo(uint64(l)) + return n +} + +func (m *StoreInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + l = m.CommitId.Size() + n += 1 + l + sovCommitInfo(uint64(l)) + return n +} + +func (m *CommitID) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovCommitInfo(uint64(m.Version)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovCommitInfo(uint64(l)) + } + return n +} + +func sovCommitInfo(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCommitInfo(x uint64) (n int) { + return sovCommitInfo(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *CommitInfo) 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 ErrIntOverflowCommitInfo + } + 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: CommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StoreInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StoreInfos = append(m.StoreInfos, StoreInfo{}) + if err := m.StoreInfos[len(m.StoreInfos)-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 Timestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreInfo) 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 ErrIntOverflowCommitInfo + } + 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: StoreInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CommitId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CommitId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CommitID) 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 ErrIntOverflowCommitInfo + } + 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: CommitID: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommitID: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommitInfo + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCommitInfo + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCommitInfo + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommitInfo(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommitInfo + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCommitInfo(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, ErrIntOverflowCommitInfo + } + 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, ErrIntOverflowCommitInfo + } + 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, ErrIntOverflowCommitInfo + } + 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, ErrInvalidLengthCommitInfo + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCommitInfo + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCommitInfo + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCommitInfo = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCommitInfo = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCommitInfo = fmt.Errorf("proto: unexpected end of group") +) diff --git a/store/v2/root/factory.go b/store/v2/root/factory.go new file mode 100644 index 000000000000..fb90c575e783 --- /dev/null +++ b/store/v2/root/factory.go @@ -0,0 +1,186 @@ +package root + +import ( + "errors" + "fmt" + + iavl_v2 "github.com/cosmos/iavl/v2" + + "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/commitment" + "cosmossdk.io/store/v2/commitment/iavl" + "cosmossdk.io/store/v2/commitment/iavlv2" + "cosmossdk.io/store/v2/commitment/mem" + "cosmossdk.io/store/v2/db" + "cosmossdk.io/store/v2/internal" + "cosmossdk.io/store/v2/metrics" + "cosmossdk.io/store/v2/migration" + "cosmossdk.io/store/v2/pruning" + "cosmossdk.io/store/v2/snapshots" +) + +type ( + SCType string +) + +const ( + SCTypeIavl SCType = "iavl" + SCTypeIavlV2 SCType = "iavl-v2" +) + +const storePrefixTpl = "s/k:%s/" // s/k: + +// Options are the options for creating a root store. +type Options struct { + SCType SCType `mapstructure:"sc-type" toml:"sc-type" comment:"State commitment database type. Currently we support: \"iavl\" and \"iavl-v2\""` + SCPruningOption *store.PruningOption `mapstructure:"sc-pruning-option" toml:"sc-pruning-option" comment:"Pruning options for state commitment"` + IavlConfig *iavl.Config `mapstructure:"iavl-config" toml:"iavl-config"` + IavlV2Config iavl_v2.TreeOptions +} + +// FactoryOptions are the options for creating a root store. +type FactoryOptions struct { + Logger log.Logger + RootDir string + Options Options + StoreKeys []string + SCRawDB corestore.KVStoreWithBatch +} + +// DefaultStoreOptions returns the default options for creating a root store. +func DefaultStoreOptions() Options { + return Options{ + SCType: SCTypeIavl, + SCPruningOption: &store.PruningOption{ + KeepRecent: 2, + Interval: 100, + }, + IavlConfig: &iavl.Config{ + CacheSize: 500_000, + SkipFastStorageUpgrade: true, + }, + } +} + +// CreateRootStore is a convenience function to create a root store based on the +// provided FactoryOptions. Strictly speaking app developers can create the root +// store directly by calling root.New, so this function is not +// necessary, but demonstrates the required steps and configuration to create a root store. +func CreateRootStore(opts *FactoryOptions) (store.RootStore, error) { + var ( + sc *commitment.CommitStore + err error + ) + + storeOpts := opts.Options + + metadata := commitment.NewMetadataStore(opts.SCRawDB) + latestVersion, err := metadata.GetLatestVersion() + if err != nil { + return nil, err + } + if len(opts.StoreKeys) == 0 { + lastCommitInfo, err := metadata.GetCommitInfo(latestVersion) + if err != nil { + return nil, err + } + if lastCommitInfo == nil { + return nil, fmt.Errorf("tried to construct a root store with no store keys specified but no commit info found for version %d", latestVersion) + } + for _, si := range lastCommitInfo.StoreInfos { + opts.StoreKeys = append(opts.StoreKeys, si.Name) + } + } + removedStoreKeys, err := metadata.GetRemovedStoreKeys(latestVersion) + if err != nil { + return nil, err + } + + newTreeFn := func(key string, scType SCType) (commitment.Tree, error) { + if internal.IsMemoryStoreKey(key) { + return mem.New(), nil + } else { + switch scType { + case SCTypeIavl: + return iavl.NewIavlTree(db.NewPrefixDB(opts.SCRawDB, []byte(fmt.Sprintf(storePrefixTpl, key))), opts.Logger, storeOpts.IavlConfig), nil + case SCTypeIavlV2: + dir := fmt.Sprintf("%s/data/iavl-v2/%s", opts.RootDir, key) + return iavlv2.NewTree(opts.Options.IavlV2Config, iavl_v2.SqliteDbOptions{Path: dir}, opts.Logger) + default: + return nil, errors.New("unsupported commitment store type") + } + } + } + + // check if we need to migrate the store + isMigrating := false + scType := storeOpts.SCType + + if scType != SCTypeIavl { + isMigrating = true // need to migrate + scType = SCTypeIavl // only support iavl v1 for migration + } + + trees := make(map[string]commitment.Tree, len(opts.StoreKeys)) + for _, key := range opts.StoreKeys { + tree, err := newTreeFn(key, scType) + if err != nil { + return nil, err + } + if isMigrating { + v, err := tree.GetLatestVersion() + if err != nil { + return nil, err + } + if v == 0 && latestVersion > 0 { + if err := tree.SetInitialVersion(latestVersion + 1); err != nil { + return nil, err + } + } + } + trees[key] = tree + } + oldTrees := make(map[string]commitment.Tree, len(opts.StoreKeys)) + for _, key := range removedStoreKeys { + tree, err := newTreeFn(string(key), scType) + if err != nil { + return nil, err + } + oldTrees[string(key)] = tree + } + + sc, err = commitment.NewCommitStore(trees, oldTrees, opts.SCRawDB, opts.Logger) + if err != nil { + return nil, err + } + + var mm *migration.Manager + if isMigrating { + snapshotDB, err := snapshots.NewStore(fmt.Sprintf("%s/data/snapshots/store.db", opts.RootDir)) + if err != nil { + return nil, err + } + snapshotMgr := snapshots.NewManager(snapshotDB, snapshots.SnapshotOptions{}, sc, nil, opts.Logger) + var newSC *commitment.CommitStore + if scType != storeOpts.SCType { + newTrees := make(map[string]commitment.Tree, len(opts.StoreKeys)) + for _, key := range opts.StoreKeys { + tree, err := newTreeFn(key, storeOpts.SCType) + if err != nil { + return nil, err + } + newTrees[key] = tree + } + newSC, err = commitment.NewCommitStore(newTrees, nil, opts.SCRawDB, opts.Logger) + if err != nil { + return nil, err + } + } + mm = migration.NewManager(opts.SCRawDB, snapshotMgr, newSC, opts.Logger) + } + + pm := pruning.NewManager(sc, storeOpts.SCPruningOption) + return New(opts.SCRawDB, opts.Logger, sc, pm, mm, metrics.NoOpMetrics{}) +} diff --git a/store/v2/root/factory_test.go b/store/v2/root/factory_test.go new file mode 100644 index 000000000000..031ccd0adfa1 --- /dev/null +++ b/store/v2/root/factory_test.go @@ -0,0 +1,46 @@ +package root + +import ( + "testing" + + gogotypes "github.com/cosmos/gogoproto/types" + "github.com/stretchr/testify/require" + + corestore "cosmossdk.io/core/store" + coretesting "cosmossdk.io/core/testing" + "cosmossdk.io/store/v2/db" +) + +func TestFactory(t *testing.T) { + fop := FactoryOptions{ + Logger: coretesting.NewNopLogger(), + RootDir: t.TempDir(), + Options: DefaultStoreOptions(), + StoreKeys: storeKeys, + SCRawDB: db.NewMemDB(), + } + + f, err := CreateRootStore(&fop) + require.NoError(t, err) + require.NotNil(t, f) + + fop.Options.SCType = SCTypeIavlV2 + f, err = CreateRootStore(&fop) + require.NoError(t, err) + require.NotNil(t, f) + + require.NoError(t, setLatestVersion(fop.SCRawDB, 1)) + fop.Options.SCType = SCTypeIavl + f, err = CreateRootStore(&fop) + require.NoError(t, err) + require.NotNil(t, f) + require.False(t, f.(*Store).isMigrating) +} + +func setLatestVersion(db corestore.KVStoreWithBatch, version int64) error { + bz, err := gogotypes.StdInt64Marshal(version) + if err != nil { + panic(err) + } + return db.Set([]byte("s/latest"), bz) +} diff --git a/store/v2/root/store.go b/store/v2/root/store.go new file mode 100644 index 000000000000..c0d06420a7c6 --- /dev/null +++ b/store/v2/root/store.go @@ -0,0 +1,387 @@ +package root + +import ( + "crypto/sha256" + "errors" + "fmt" + "io" + "sync" + "time" + + corelog "cosmossdk.io/core/log" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/metrics" + "cosmossdk.io/store/v2/migration" + "cosmossdk.io/store/v2/proof" + "cosmossdk.io/store/v2/pruning" +) + +var ( + _ store.RootStore = (*Store)(nil) + _ store.UpgradeableStore = (*Store)(nil) +) + +// Store defines the SDK's default RootStore implementation. It contains a single +// State Storage (SS) backend and a single State Commitment (SC) backend. The SC +// backend may or may not support multiple store keys and is implementation +// dependent. +type Store struct { + logger corelog.Logger + + // holds the db instance for closing it + dbCloser io.Closer + + // stateCommitment reflects the state commitment (SC) backend + stateCommitment store.Committer + + // lastCommitInfo reflects the last version/hash that has been committed + lastCommitInfo *proof.CommitInfo + + // telemetry reflects a telemetry agent responsible for emitting metrics (if any) + telemetry metrics.StoreMetrics + + // pruningManager reflects the pruning manager used to prune state of the SS and SC backends + pruningManager *pruning.Manager + + // Migration related fields + // migrationManager reflects the migration manager used to migrate state from v1 to v2 + migrationManager *migration.Manager + // chChangeset reflects the channel used to send the changeset to the migration manager + chChangeset chan *migration.VersionedChangeset + // chDone reflects the channel used to signal the migration manager that the migration + // is done + chDone chan struct{} + // isMigrating reflects whether the store is currently migrating + isMigrating bool +} + +// New creates a new root Store instance. +// +// NOTE: The migration manager is optional and can be nil if no migration is required. +func New( + dbCloser io.Closer, + logger corelog.Logger, + sc store.Committer, + pm *pruning.Manager, + mm *migration.Manager, + m metrics.StoreMetrics, +) (store.RootStore, error) { + return &Store{ + dbCloser: dbCloser, + logger: logger, + stateCommitment: sc, + pruningManager: pm, + migrationManager: mm, + telemetry: m, + isMigrating: mm != nil, + }, nil +} + +// Close closes the store and resets all internal fields. Note, Close() is NOT +// idempotent and should only be called once. +func (s *Store) Close() (err error) { + err = errors.Join(err, s.stateCommitment.Close()) + err = errors.Join(err, s.dbCloser.Close()) + + s.stateCommitment = nil + s.lastCommitInfo = nil + + return err +} + +func (s *Store) SetMetrics(m metrics.Metrics) { + s.telemetry = m +} + +func (s *Store) SetInitialVersion(v uint64) error { + return s.stateCommitment.SetInitialVersion(v) +} + +// getVersionedReader returns a VersionedReader based on the given version. If the +// version exists in the state storage, it returns the state storage. +// If not, it checks if the state commitment implements the VersionedReader interface +// and the version exists in the state commitment, since the state storage will be +// synced during migration. +func (s *Store) getVersionedReader(version uint64) (store.VersionedReader, error) { + isExist, err := s.stateCommitment.VersionExists(version) + if err != nil { + return nil, err + } + if isExist { + return s.stateCommitment, nil + } + return nil, fmt.Errorf("version %d does not exist", version) +} + +// StateAt returns a read-only view of the state at a given version. +func (s *Store) StateAt(v uint64) (corestore.ReaderMap, error) { + vReader, err := s.getVersionedReader(v) + return NewReaderMap(v, vReader), err +} + +func (s *Store) StateLatest() (uint64, corestore.ReaderMap, error) { + v, err := s.GetLatestVersion() + if err != nil { + return 0, nil, err + } + vReader, err := s.getVersionedReader(v) + if err != nil { + return 0, nil, err + } + + return v, NewReaderMap(v, vReader), nil +} + +func (s *Store) GetStateCommitment() store.Committer { + return s.stateCommitment +} + +// LastCommitID returns a CommitID based off of the latest internal CommitInfo. +// If an internal CommitInfo is not set, a new one will be returned with only the +// latest version set, which is based off of the SC view. +func (s *Store) LastCommitID() (proof.CommitID, error) { + if s.lastCommitInfo != nil { + return *s.lastCommitInfo.CommitID(), nil + } + + latestVersion, err := s.stateCommitment.GetLatestVersion() + if err != nil { + return proof.CommitID{}, err + } + // if the latest version is 0, we return a CommitID with version 0 and a hash of an empty byte slice + bz := sha256.Sum256([]byte{}) + + return proof.CommitID{Version: int64(latestVersion), Hash: bz[:]}, nil +} + +// GetLatestVersion returns the latest version based on the latest internal +// CommitInfo. An error is returned if the latest CommitInfo or version cannot +// be retrieved. +func (s *Store) GetLatestVersion() (uint64, error) { + lastCommitID, err := s.LastCommitID() + if err != nil { + return 0, err + } + + return uint64(lastCommitID.Version), nil +} + +func (s *Store) Query(storeKey []byte, version uint64, key []byte, prove bool) (store.QueryResult, error) { + if s.telemetry != nil { + defer s.telemetry.MeasureSince(time.Now(), "root_store", "query") + } + + val, err := s.stateCommitment.Get(storeKey, version, key) + if err != nil { + return store.QueryResult{}, fmt.Errorf("failed to query SC store: %w", err) + } + + result := store.QueryResult{ + Key: key, + Value: val, + Version: version, + } + + if prove { + result.ProofOps, err = s.stateCommitment.GetProof(storeKey, version, key) + if err != nil { + return store.QueryResult{}, fmt.Errorf("failed to get SC store proof: %w", err) + } + } + + return result, nil +} + +func (s *Store) LoadLatestVersion() error { + if s.telemetry != nil { + defer s.telemetry.MeasureSince(time.Now(), "root_store", "load_latest_version") + } + + lv, err := s.GetLatestVersion() + if err != nil { + return err + } + + return s.loadVersion(lv, nil, false) +} + +func (s *Store) LoadVersion(version uint64) error { + if s.telemetry != nil { + defer s.telemetry.MeasureSince(time.Now(), "root_store", "load_version") + } + + return s.loadVersion(version, nil, false) +} + +func (s *Store) LoadVersionForOverwriting(version uint64) error { + if s.telemetry != nil { + defer s.telemetry.MeasureSince(time.Now(), "root_store", "load_version_for_overwriting") + } + + return s.loadVersion(version, nil, true) +} + +// LoadVersionAndUpgrade implements the UpgradeableStore interface. +// +// NOTE: It cannot be called while the store is migrating. +func (s *Store) LoadVersionAndUpgrade(version uint64, upgrades *corestore.StoreUpgrades) error { + if upgrades == nil { + return errors.New("upgrades cannot be nil") + } + if s.telemetry != nil { + defer s.telemetry.MeasureSince(time.Now(), "root_store", "load_version_and_upgrade") + } + + if s.isMigrating { + return errors.New("cannot upgrade while migrating") + } + + if err := s.loadVersion(version, upgrades, true); err != nil { + return err + } + + return nil +} + +func (s *Store) loadVersion(v uint64, upgrades *corestore.StoreUpgrades, overrideAfter bool) error { + s.logger.Debug("loading version", "version", v) + + if upgrades == nil { + if !overrideAfter { + if err := s.stateCommitment.LoadVersion(v); err != nil { + return fmt.Errorf("failed to load SC version %d: %w", v, err) + } + } else { + if err := s.stateCommitment.LoadVersionForOverwriting(v); err != nil { + return fmt.Errorf("failed to load SC version %d: %w", v, err) + } + } + } else { + // if upgrades are provided, we need to load the version and apply the upgrades + if err := s.stateCommitment.LoadVersionAndUpgrade(v, upgrades); err != nil { + return fmt.Errorf("failed to load SS version with upgrades %d: %w", v, err) + } + } + + // set lastCommitInfo explicitly s.t. Commit commits the correct version, i.e. v+1 + var err error + s.lastCommitInfo, err = s.stateCommitment.GetCommitInfo(v) + if err != nil { + return fmt.Errorf("failed to get commit info for version %d: %w", v, err) + } + + // if we're migrating, we need to start the migration process + if s.isMigrating { + s.startMigration() + } + + return nil +} + +// Commit commits all state changes to the underlying SS and SC backends. It +// writes a batch of the changeset to the SC tree, and retrieves the CommitInfo +// from the SC tree. Finally, it commits the SC tree and returns the hash of +// the CommitInfo. +func (s *Store) Commit(cs *corestore.Changeset) ([]byte, error) { + if s.telemetry != nil { + now := time.Now() + defer func() { + s.telemetry.MeasureSince(now, "root_store", "commit") + }() + } + + if err := s.handleMigration(cs); err != nil { + return nil, err + } + + // signal to the pruning manager that a new version is about to be committed + // this may be required if the SS and SC backends implementation have the + // background pruning process (iavl v1 for example) which must be paused during the commit + s.pruningManager.PausePruning() + + st := time.Now() + if err := s.stateCommitment.WriteChangeset(cs); err != nil { + return nil, fmt.Errorf("failed to write batch to SC store: %w", err) + } + writeDur := time.Since(st) + st = time.Now() + cInfo, err := s.stateCommitment.Commit(cs.Version) + if err != nil { + return nil, fmt.Errorf("failed to commit SC store: %w", err) + } + s.logger.Warn(fmt.Sprintf("commit version %d write=%s commit=%s", cs.Version, writeDur, time.Since(st))) + + if cInfo.Version != int64(cs.Version) { + return nil, fmt.Errorf("commit version mismatch: got %d, expected %d", cInfo.Version, cs.Version) + } + s.lastCommitInfo = cInfo + + // signal to the pruning manager that the commit is done + if err := s.pruningManager.ResumePruning(uint64(s.lastCommitInfo.Version)); err != nil { + s.logger.Error("failed to signal commit done to pruning manager", "err", err) + } + + return s.lastCommitInfo.Hash(), nil +} + +// startMigration starts a migration process to migrate the RootStore/v1 to the +// SS and SC backends of store/v2 and initializes the channels. +// It runs in a separate goroutine and replaces the current RootStore with the +// migrated new backends once the migration is complete. +// +// NOTE: This method should only be called once after loadVersion. +func (s *Store) startMigration() { + // buffer at most 1 changeset, if the receiver is behind attempting to buffer + // more than 1 will block. + s.chChangeset = make(chan *migration.VersionedChangeset, 1) + // it is used to signal the migration manager that the migration is done + s.chDone = make(chan struct{}) + + mtx := sync.Mutex{} + mtx.Lock() + go func() { + version := s.lastCommitInfo.Version + s.logger.Info("starting migration", "version", version) + mtx.Unlock() + if err := s.migrationManager.Start(uint64(version), s.chChangeset, s.chDone); err != nil { + s.logger.Error("failed to start migration", "err", err) + } + }() + + // wait for the migration manager to start + mtx.Lock() + defer mtx.Unlock() +} + +func (s *Store) handleMigration(cs *corestore.Changeset) error { + if s.isMigrating { + // if the migration manager has already migrated to the version, close the + // channels and replace the state commitment + if s.migrationManager.GetMigratedVersion() == uint64(s.lastCommitInfo.Version) { + close(s.chDone) + close(s.chChangeset) + s.isMigrating = false + newStateCommitment := s.migrationManager.GetStateCommitment() + if newStateCommitment != nil { + // close the old state commitment and replace it with the new one + if err := s.stateCommitment.Close(); err != nil { + return fmt.Errorf("failed to close the old SC store: %w", err) + } + s.stateCommitment = newStateCommitment + } + if err := s.migrationManager.Close(); err != nil { + return fmt.Errorf("failed to close migration manager: %w", err) + } + s.logger.Info("migration completed", "version", s.lastCommitInfo.Version) + } else { + // queue the next changeset to the migration manager + s.chChangeset <- &migration.VersionedChangeset{Version: uint64(s.lastCommitInfo.Version + 1), Changeset: cs} + } + } + return nil +} + +func (s *Store) Prune(version uint64) error { + return s.pruningManager.Prune(version) +} diff --git a/tests/systemtests/bankv2_test.go b/tests/systemtests/bankv2_test.go new file mode 100644 index 000000000000..9d4d60914a5b --- /dev/null +++ b/tests/systemtests/bankv2_test.go @@ -0,0 +1,58 @@ +//go:build system_test + +package systemtests + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + systest "cosmossdk.io/systemtests" +) + +func TestBankV2SendTxCmd(t *testing.T) { + // bankv2 was removed from simapp + t.Skip() + // scenario: test bank send command + // given a running chain + + systest.Sut.ResetChain(t) + cli := systest.NewCLIWrapper(t, systest.Sut, systest.Verbose) + + // get validator address + valAddr := gjson.Get(cli.Keys("keys", "list"), "1.address").String() + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + denom := "stake" + systest.Sut.StartChain(t) + + // query validator balance and make sure it has enough balance + var transferAmount int64 = 1000 + raw := cli.CustomQuery("q", "bankv2", "balance", valAddr, denom) + valBalance := gjson.Get(raw, "balance.amount").Int() + + require.Greater(t, valBalance, transferAmount, "not enough balance found with validator") + + bankSendCmdArgs := []string{"tx", "bankv2", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom)} + + // test valid transaction + rsp := cli.Run(append(bankSendCmdArgs, "--fees=1stake")...) + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + systest.RequireTxSuccess(t, txResult) + + // Check balance after send + valRaw := cli.CustomQuery("q", "bankv2", "balance", valAddr, denom) + valBalanceAfer := gjson.Get(valRaw, "balance.amount").Int() + + // TODO: Make DeductFee ante handler work with bank/v2 + require.Equal(t, valBalanceAfer, valBalance-transferAmount) + + receiverRaw := cli.CustomQuery("q", "bankv2", "balance", receiverAddr, denom) + receiverBalance := gjson.Get(receiverRaw, "balance.amount").Int() + require.Equal(t, receiverBalance, transferAmount) +}