From d6da7037b63ab17caa63b93716cafd943f180878 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 21 Nov 2022 23:46:48 +0100 Subject: [PATCH] fix(group): migrate group policy account to base accounts with credentials (#13742) --- CHANGELOG.md | 2 + api/cosmos/auth/v1beta1/auth.pulsar.go | 702 ++++++++++++++++-- .../adr-028-public-key-addresses.md | 4 +- proto/cosmos/auth/v1beta1/auth.proto | 11 + server/mock/tx.go | 20 +- x/auth/types/auth.pb.go | 320 ++++++-- x/auth/types/codec.go | 8 + x/auth/types/credentials.go | 91 +++ x/auth/types/credentials_test.go | 39 + x/crisis/migrations/v2/migrate_test.go | 6 +- x/distribution/migrations/v3/migrate_test.go | 4 +- x/group/expected_keepers.go | 2 + x/group/keeper/keeper_test.go | 42 +- x/group/keeper/migrations.go | 27 + x/group/keeper/msg_server.go | 24 +- x/group/migrations/v2/migrate.go | 78 ++ x/group/migrations/v2/migrate_test.go | 92 +++ x/group/module/module.go | 10 +- x/group/testutil/expected_keepers_mocks.go | 12 + x/group/types_test.go | 4 +- x/slashing/migrations/v3/migrator_test.go | 4 +- x/staking/migrations/v4/migrations_test.go | 3 +- 22 files changed, 1354 insertions(+), 151 deletions(-) create mode 100644 x/auth/types/credentials.go create mode 100644 x/auth/types/credentials_test.go create mode 100644 x/group/keeper/migrations.go create mode 100644 x/group/migrations/v2/migrate.go create mode 100644 x/group/migrations/v2/migrate_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 345573dea3..08663e4a36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking +* (x/group) [#13742](https://github.com/cosmos/cosmos-sdk/pull/13742) Migrate group policy account from module accounts to base account. * (codec) [#13307](https://github.com/cosmos/cosmos-sdk/pull/13307) Register all modules' `Msg`s with group's ModuleCdc so that Amino sign bytes are correctly generated. * (codec) [#13196](https://github.com/cosmos/cosmos-sdk/pull/13196) Register all modules' `Msg`s with gov's ModuleCdc so that Amino sign bytes are correctly generated. * (group) [#13592](https://github.com/cosmos/cosmos-sdk/pull/13592) Fix group types registration with Amino. @@ -180,6 +181,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf ### Bug Fixes +* (x/group) [#13742](https://github.com/cosmos/cosmos-sdk/pull/13742) Fix `validate-genesis` when group policy accounts exist. * (x/auth) [#13838](https://github.com/cosmos/cosmos-sdk/pull/13838) Fix calling `String()` and `MarshalYAML` panics when pubkey is set on a `BaseAccount`. * (rosetta) [#13583](https://github.com/cosmos/cosmos-sdk/pull/13583) Misc fixes for cosmos-rosetta. * (x/evidence) [#13740](https://github.com/cosmos/cosmos-sdk/pull/13740) Fix evidence query API to decode the hash properly. diff --git a/api/cosmos/auth/v1beta1/auth.pulsar.go b/api/cosmos/auth/v1beta1/auth.pulsar.go index 350e83eb53..b60a1a64b9 100644 --- a/api/cosmos/auth/v1beta1/auth.pulsar.go +++ b/api/cosmos/auth/v1beta1/auth.pulsar.go @@ -1234,6 +1234,550 @@ func (x *fastReflection_ModuleAccount) ProtoMethods() *protoiface.Methods { } } +var _ protoreflect.List = (*_ModuleCredential_2_list)(nil) + +type _ModuleCredential_2_list struct { + list *[][]byte +} + +func (x *_ModuleCredential_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_ModuleCredential_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfBytes((*x.list)[i]) +} + +func (x *_ModuleCredential_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Bytes() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue +} + +func (x *_ModuleCredential_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Bytes() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) +} + +func (x *_ModuleCredential_2_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message ModuleCredential at list field DerivationKeys as it is not of Message kind")) +} + +func (x *_ModuleCredential_2_list) Truncate(n int) { + *x.list = (*x.list)[:n] +} + +func (x *_ModuleCredential_2_list) NewElement() protoreflect.Value { + var v []byte + return protoreflect.ValueOfBytes(v) +} + +func (x *_ModuleCredential_2_list) IsValid() bool { + return x.list != nil +} + +var ( + md_ModuleCredential protoreflect.MessageDescriptor + fd_ModuleCredential_module_name protoreflect.FieldDescriptor + fd_ModuleCredential_derivation_keys protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_auth_v1beta1_auth_proto_init() + md_ModuleCredential = File_cosmos_auth_v1beta1_auth_proto.Messages().ByName("ModuleCredential") + fd_ModuleCredential_module_name = md_ModuleCredential.Fields().ByName("module_name") + fd_ModuleCredential_derivation_keys = md_ModuleCredential.Fields().ByName("derivation_keys") +} + +var _ protoreflect.Message = (*fastReflection_ModuleCredential)(nil) + +type fastReflection_ModuleCredential ModuleCredential + +func (x *ModuleCredential) ProtoReflect() protoreflect.Message { + return (*fastReflection_ModuleCredential)(x) +} + +func (x *ModuleCredential) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_auth_v1beta1_auth_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_ModuleCredential_messageType fastReflection_ModuleCredential_messageType +var _ protoreflect.MessageType = fastReflection_ModuleCredential_messageType{} + +type fastReflection_ModuleCredential_messageType struct{} + +func (x fastReflection_ModuleCredential_messageType) Zero() protoreflect.Message { + return (*fastReflection_ModuleCredential)(nil) +} +func (x fastReflection_ModuleCredential_messageType) New() protoreflect.Message { + return new(fastReflection_ModuleCredential) +} +func (x fastReflection_ModuleCredential_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_ModuleCredential +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_ModuleCredential) Descriptor() protoreflect.MessageDescriptor { + return md_ModuleCredential +} + +// 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_ModuleCredential) Type() protoreflect.MessageType { + return _fastReflection_ModuleCredential_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_ModuleCredential) New() protoreflect.Message { + return new(fastReflection_ModuleCredential) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_ModuleCredential) Interface() protoreflect.ProtoMessage { + return (*ModuleCredential)(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_ModuleCredential) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ModuleName != "" { + value := protoreflect.ValueOfString(x.ModuleName) + if !f(fd_ModuleCredential_module_name, value) { + return + } + } + if len(x.DerivationKeys) != 0 { + value := protoreflect.ValueOfList(&_ModuleCredential_2_list{list: &x.DerivationKeys}) + if !f(fd_ModuleCredential_derivation_keys, 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_ModuleCredential) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + return x.ModuleName != "" + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + return len(x.DerivationKeys) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + x.ModuleName = "" + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + x.DerivationKeys = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + value := x.ModuleName + return protoreflect.ValueOfString(value) + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + if len(x.DerivationKeys) == 0 { + return protoreflect.ValueOfList(&_ModuleCredential_2_list{}) + } + listValue := &_ModuleCredential_2_list{list: &x.DerivationKeys} + return protoreflect.ValueOfList(listValue) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + x.ModuleName = value.Interface().(string) + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + lv := value.List() + clv := lv.(*_ModuleCredential_2_list) + x.DerivationKeys = *clv.list + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + if x.DerivationKeys == nil { + x.DerivationKeys = [][]byte{} + } + value := &_ModuleCredential_2_list{list: &x.DerivationKeys} + return protoreflect.ValueOfList(value) + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + panic(fmt.Errorf("field module_name of message cosmos.auth.v1beta1.ModuleCredential is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.auth.v1beta1.ModuleCredential.module_name": + return protoreflect.ValueOfString("") + case "cosmos.auth.v1beta1.ModuleCredential.derivation_keys": + list := [][]byte{} + return protoreflect.ValueOfList(&_ModuleCredential_2_list{list: &list}) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.auth.v1beta1.ModuleCredential")) + } + panic(fmt.Errorf("message cosmos.auth.v1beta1.ModuleCredential 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_ModuleCredential) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.auth.v1beta1.ModuleCredential", 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_ModuleCredential) 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_ModuleCredential) 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_ModuleCredential) 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_ModuleCredential) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*ModuleCredential) + 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.ModuleName) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if len(x.DerivationKeys) > 0 { + for _, b := range x.DerivationKeys { + l = len(b) + 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().(*ModuleCredential) + 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.DerivationKeys) > 0 { + for iNdEx := len(x.DerivationKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.DerivationKeys[iNdEx]) + copy(dAtA[i:], x.DerivationKeys[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.DerivationKeys[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(x.ModuleName) > 0 { + i -= len(x.ModuleName) + copy(dAtA[i:], x.ModuleName) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ModuleName))) + 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().(*ModuleCredential) + 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: ModuleCredential: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: ModuleCredential: 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 ModuleName", 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.ModuleName = 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 DerivationKeys", 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.DerivationKeys = append(x.DerivationKeys, make([]byte, postIndex-iNdEx)) + copy(x.DerivationKeys[len(x.DerivationKeys)-1], 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_Params protoreflect.MessageDescriptor fd_Params_max_memo_characters protoreflect.FieldDescriptor @@ -1262,7 +1806,7 @@ func (x *Params) ProtoReflect() protoreflect.Message { } func (x *Params) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_auth_v1beta1_auth_proto_msgTypes[2] + mi := &file_cosmos_auth_v1beta1_auth_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1957,6 +2501,55 @@ func (x *ModuleAccount) GetPermissions() []string { return nil } +// ModuleCredential represents a unclaimable pubkey for base accounts controlled by modules. +// +// Since: cosmos-sdk 0.47 +type ModuleCredential struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // module_name is the name of the module used for address derivation (passed into address.Module). + ModuleName string `protobuf:"bytes,1,opt,name=module_name,json=moduleName,proto3" json:"module_name,omitempty"` + // derivation_keys is for deriving a module account address (passed into address.Module) + // adding more keys creates sub-account addresses (passed into address.Derive) + DerivationKeys [][]byte `protobuf:"bytes,2,rep,name=derivation_keys,json=derivationKeys,proto3" json:"derivation_keys,omitempty"` +} + +func (x *ModuleCredential) Reset() { + *x = ModuleCredential{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_auth_v1beta1_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ModuleCredential) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModuleCredential) ProtoMessage() {} + +// Deprecated: Use ModuleCredential.ProtoReflect.Descriptor instead. +func (*ModuleCredential) Descriptor() ([]byte, []int) { + return file_cosmos_auth_v1beta1_auth_proto_rawDescGZIP(), []int{2} +} + +func (x *ModuleCredential) GetModuleName() string { + if x != nil { + return x.ModuleName + } + return "" +} + +func (x *ModuleCredential) GetDerivationKeys() [][]byte { + if x != nil { + return x.DerivationKeys + } + return nil +} + // Params defines the parameters for the auth module. type Params struct { state protoimpl.MessageState @@ -1973,7 +2566,7 @@ type Params struct { func (x *Params) Reset() { *x = Params{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_auth_v1beta1_auth_proto_msgTypes[2] + mi := &file_cosmos_auth_v1beta1_auth_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1987,7 +2580,7 @@ func (*Params) ProtoMessage() {} // Deprecated: Use Params.ProtoReflect.Descriptor instead. func (*Params) Descriptor() ([]byte, []int) { - return file_cosmos_auth_v1beta1_auth_proto_rawDescGZIP(), []int{2} + return file_cosmos_auth_v1beta1_auth_proto_rawDescGZIP(), []int{3} } func (x *Params) GetMaxMemoCharacters() uint64 { @@ -2067,41 +2660,47 @@ var file_cosmos_auth_v1beta1_auth_proto_rawDesc = []byte{ 0x00, 0xca, 0xb4, 0x2d, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0xdb, 0x02, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6d, - 0x61, 0x78, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x6d, - 0x6f, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x74, - 0x78, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0a, 0x74, 0x78, 0x53, 0x69, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x30, 0x0a, - 0x15, 0x74, 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x70, 0x65, - 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x74, 0x78, - 0x53, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, - 0x4f, 0x0a, 0x17, 0x73, 0x69, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x63, 0x6f, - 0x73, 0x74, 0x5f, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x42, 0x18, 0xe2, 0xde, 0x1f, 0x14, 0x53, 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, - 0x6f, 0x73, 0x74, 0x45, 0x44, 0x32, 0x35, 0x35, 0x31, 0x39, 0x52, 0x14, 0x73, 0x69, 0x67, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, - 0x12, 0x55, 0x0a, 0x19, 0x73, 0x69, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x63, - 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x04, 0x42, 0x1a, 0xe2, 0xde, 0x1f, 0x16, 0x53, 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x52, - 0x16, 0x73, 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x53, 0x65, - 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x3a, 0x25, 0x98, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, - 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, - 0x2f, 0x78, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xc4, - 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x09, 0x41, 0x75, 0x74, 0x68, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, - 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x61, 0x75, - 0x74, 0x68, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x58, 0xaa, - 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x56, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, - 0x75, 0x74, 0x68, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, - 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x75, 0x74, 0x68, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x5c, 0x0a, 0x10, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, + 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x22, 0xdb, + 0x02, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x61, 0x78, + 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x6d, 0x61, 0x78, 0x4d, 0x65, 0x6d, 0x6f, 0x43, + 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x78, 0x5f, + 0x73, 0x69, 0x67, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0a, 0x74, 0x78, 0x53, 0x69, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x30, 0x0a, 0x15, 0x74, + 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x74, 0x78, 0x53, 0x69, + 0x7a, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x4f, 0x0a, + 0x17, 0x73, 0x69, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, + 0x5f, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x18, + 0xe2, 0xde, 0x1f, 0x14, 0x53, 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x73, + 0x74, 0x45, 0x44, 0x32, 0x35, 0x35, 0x31, 0x39, 0x52, 0x14, 0x73, 0x69, 0x67, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x12, 0x55, + 0x0a, 0x19, 0x73, 0x69, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x63, 0x6f, 0x73, + 0x74, 0x5f, 0x73, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x04, 0x42, 0x1a, 0xe2, 0xde, 0x1f, 0x16, 0x53, 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x52, 0x16, 0x73, + 0x69, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x63, 0x70, + 0x32, 0x35, 0x36, 0x6b, 0x31, 0x3a, 0x25, 0x98, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, + 0xe7, 0xb0, 0x2a, 0x18, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x78, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xc4, 0x01, 0x0a, + 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x09, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, + 0x75, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x61, 0x75, 0x74, 0x68, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x58, 0xaa, 0x02, 0x13, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x56, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, + 0x68, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x43, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x75, 0x74, 0x68, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2116,15 +2715,16 @@ func file_cosmos_auth_v1beta1_auth_proto_rawDescGZIP() []byte { return file_cosmos_auth_v1beta1_auth_proto_rawDescData } -var file_cosmos_auth_v1beta1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_cosmos_auth_v1beta1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_cosmos_auth_v1beta1_auth_proto_goTypes = []interface{}{ - (*BaseAccount)(nil), // 0: cosmos.auth.v1beta1.BaseAccount - (*ModuleAccount)(nil), // 1: cosmos.auth.v1beta1.ModuleAccount - (*Params)(nil), // 2: cosmos.auth.v1beta1.Params - (*anypb.Any)(nil), // 3: google.protobuf.Any + (*BaseAccount)(nil), // 0: cosmos.auth.v1beta1.BaseAccount + (*ModuleAccount)(nil), // 1: cosmos.auth.v1beta1.ModuleAccount + (*ModuleCredential)(nil), // 2: cosmos.auth.v1beta1.ModuleCredential + (*Params)(nil), // 3: cosmos.auth.v1beta1.Params + (*anypb.Any)(nil), // 4: google.protobuf.Any } var file_cosmos_auth_v1beta1_auth_proto_depIdxs = []int32{ - 3, // 0: cosmos.auth.v1beta1.BaseAccount.pub_key:type_name -> google.protobuf.Any + 4, // 0: cosmos.auth.v1beta1.BaseAccount.pub_key:type_name -> google.protobuf.Any 0, // 1: cosmos.auth.v1beta1.ModuleAccount.base_account:type_name -> cosmos.auth.v1beta1.BaseAccount 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type @@ -2164,6 +2764,18 @@ func file_cosmos_auth_v1beta1_auth_proto_init() { } } file_cosmos_auth_v1beta1_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ModuleCredential); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_auth_v1beta1_auth_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Params); i { case 0: return &v.state @@ -2182,7 +2794,7 @@ func file_cosmos_auth_v1beta1_auth_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cosmos_auth_v1beta1_auth_proto_rawDesc, NumEnums: 0, - NumMessages: 3, + NumMessages: 4, NumExtensions: 0, NumServices: 0, }, diff --git a/docs/architecture/adr-028-public-key-addresses.md b/docs/architecture/adr-028-public-key-addresses.md index cf75e660b9..a42a3a7f64 100644 --- a/docs/architecture/adr-028-public-key-addresses.md +++ b/docs/architecture/adr-028-public-key-addresses.md @@ -197,13 +197,13 @@ func Module(moduleName string, key []byte) []byte{ **Example** A lending BTC pool address would be: ```go -btcPool := address.Module("lending", btc.Addrress()}) +btcPool := address.Module("lending", btc.Address()}) ``` If we want to create an address for a module account depending on more than one key, we can concatenate them: ```go -btcAtomAMM := address.Module("amm", btc.Addrress() + atom.Address()}) +btcAtomAMM := address.Module("amm", btc.Address() + atom.Address()}) ``` #### Derived Addresses diff --git a/proto/cosmos/auth/v1beta1/auth.proto b/proto/cosmos/auth/v1beta1/auth.proto index efaf2db620..32734fa321 100644 --- a/proto/cosmos/auth/v1beta1/auth.proto +++ b/proto/cosmos/auth/v1beta1/auth.proto @@ -36,6 +36,17 @@ message ModuleAccount { repeated string permissions = 3; } +// ModuleCredential represents a unclaimable pubkey for base accounts controlled by modules. +// +// Since: cosmos-sdk 0.47 +message ModuleCredential { + // module_name is the name of the module used for address derivation (passed into address.Module). + string module_name = 1; + // derivation_keys is for deriving a module account address (passed into address.Module) + // adding more keys creates sub-account addresses (passed into address.Derive) + repeated bytes derivation_keys = 2; +} + // Params defines the parameters for the auth module. message Params { option (amino.name) = "cosmos-sdk/x/auth/Params"; diff --git a/server/mock/tx.go b/server/mock/tx.go index 6b4c499c83..c4c8a778d6 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -7,10 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/signing" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - txsigning "github.com/cosmos/cosmos-sdk/types/tx/signing" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + txsigning "github.com/cosmos/cosmos-sdk/types/tx/signing" ) // An sdk.Tx which is its own sdk.Msg. @@ -20,25 +19,27 @@ type kvstoreTx struct { bytes []byte address sdk.AccAddress } + +// testPubKey is a dummy implementation of PubKey used for testing. type testPubKey struct { address sdk.AccAddress } -func (t testPubKey) Reset() { panic("implement me") } +func (t testPubKey) Reset() { panic("not implemented") } -func (t testPubKey) String() string { panic("implement me") } +func (t testPubKey) String() string { panic("not implemented") } -func (t testPubKey) ProtoMessage() { panic("implement me") } +func (t testPubKey) ProtoMessage() { panic("not implemented") } func (t testPubKey) Address() cryptotypes.Address { return t.address.Bytes() } -func (t testPubKey) Bytes() []byte { panic("implement me") } +func (t testPubKey) Bytes() []byte { panic("not implemented") } -func (t testPubKey) VerifySignature(msg []byte, sig []byte) bool { panic("implement me") } +func (t testPubKey) VerifySignature(msg []byte, sig []byte) bool { panic("not implemented") } -func (t testPubKey) Equals(key cryptotypes.PubKey) bool { panic("implement me") } +func (t testPubKey) Equals(key cryptotypes.PubKey) bool { panic("not implemented") } -func (t testPubKey) Type() string { panic("implement me") } +func (t testPubKey) Type() string { panic("not implemented") } func (msg *kvstoreTx) GetSignaturesV2() (res []txsigning.SignatureV2, err error) { res = append(res, txsigning.SignatureV2{ @@ -76,6 +77,7 @@ var ( _ sdk.Msg = &kvstoreTx{} _ signing.SigVerifiableTx = &kvstoreTx{} _ cryptotypes.PubKey = &kvstoreTx{} + _ cryptotypes.PubKey = &testPubKey{} ) func NewTx(key, value string, accAddress sdk.AccAddress) *kvstoreTx { diff --git a/x/auth/types/auth.pb.go b/x/auth/types/auth.pb.go index d1a340eae5..b94813acc7 100644 --- a/x/auth/types/auth.pb.go +++ b/x/auth/types/auth.pb.go @@ -108,6 +108,64 @@ func (m *ModuleAccount) XXX_DiscardUnknown() { var xxx_messageInfo_ModuleAccount proto.InternalMessageInfo +// ModuleCredential represents a unclaimable pubkey for base accounts controlled by modules. +// +// Since: cosmos-sdk 0.47 +type ModuleCredential struct { + // module_name is the name of the module used for address derivation (passed into address.Module). + ModuleName string `protobuf:"bytes,1,opt,name=module_name,json=moduleName,proto3" json:"module_name,omitempty"` + // derivation_keys is for deriving a module account address (passed into address.Module) + // adding more keys creates sub-account addresses (passed into address.Derive) + DerivationKeys [][]byte `protobuf:"bytes,2,rep,name=derivation_keys,json=derivationKeys,proto3" json:"derivation_keys,omitempty"` +} + +func (m *ModuleCredential) Reset() { *m = ModuleCredential{} } +func (m *ModuleCredential) String() string { return proto.CompactTextString(m) } +func (*ModuleCredential) ProtoMessage() {} +func (*ModuleCredential) Descriptor() ([]byte, []int) { + return fileDescriptor_7e1f7e915d020d2d, []int{2} +} +func (m *ModuleCredential) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ModuleCredential) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ModuleCredential.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 *ModuleCredential) XXX_Merge(src proto.Message) { + xxx_messageInfo_ModuleCredential.Merge(m, src) +} +func (m *ModuleCredential) XXX_Size() int { + return m.Size() +} +func (m *ModuleCredential) XXX_DiscardUnknown() { + xxx_messageInfo_ModuleCredential.DiscardUnknown(m) +} + +var xxx_messageInfo_ModuleCredential proto.InternalMessageInfo + +func (m *ModuleCredential) GetModuleName() string { + if m != nil { + return m.ModuleName + } + return "" +} + +func (m *ModuleCredential) GetDerivationKeys() [][]byte { + if m != nil { + return m.DerivationKeys + } + return nil +} + // Params defines the parameters for the auth module. type Params struct { MaxMemoCharacters uint64 `protobuf:"varint,1,opt,name=max_memo_characters,json=maxMemoCharacters,proto3" json:"max_memo_characters,omitempty"` @@ -120,7 +178,7 @@ type Params struct { func (m *Params) Reset() { *m = Params{} } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_7e1f7e915d020d2d, []int{2} + return fileDescriptor_7e1f7e915d020d2d, []int{3} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -187,54 +245,58 @@ func (m *Params) GetSigVerifyCostSecp256k1() uint64 { func init() { proto.RegisterType((*BaseAccount)(nil), "cosmos.auth.v1beta1.BaseAccount") proto.RegisterType((*ModuleAccount)(nil), "cosmos.auth.v1beta1.ModuleAccount") + proto.RegisterType((*ModuleCredential)(nil), "cosmos.auth.v1beta1.ModuleCredential") proto.RegisterType((*Params)(nil), "cosmos.auth.v1beta1.Params") } func init() { proto.RegisterFile("cosmos/auth/v1beta1/auth.proto", fileDescriptor_7e1f7e915d020d2d) } var fileDescriptor_7e1f7e915d020d2d = []byte{ - // 649 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0xcf, 0x4e, 0xdb, 0x4e, - 0x10, 0x8e, 0x21, 0x3f, 0xfe, 0x6c, 0x00, 0x09, 0x93, 0x1f, 0x35, 0x39, 0x24, 0x16, 0x12, 0x6a, - 0x8a, 0x8a, 0xdd, 0xa4, 0xa2, 0x55, 0xb9, 0x61, 0xda, 0x03, 0x6a, 0x69, 0x91, 0xa3, 0x72, 0xe8, - 0xc5, 0x5a, 0x3b, 0x83, 0xb1, 0xc8, 0x7a, 0x5d, 0xef, 0x1a, 0xc5, 0x3c, 0x41, 0x55, 0xa9, 0x52, - 0x8f, 0x1c, 0x51, 0x9f, 0x80, 0x03, 0x0f, 0xd1, 0xf6, 0x84, 0x7a, 0xaa, 0x54, 0x29, 0xaa, 0xc2, - 0x81, 0xaa, 0x4f, 0x51, 0x79, 0xd7, 0xa1, 0x09, 0xe5, 0x62, 0xed, 0x7c, 0xdf, 0x37, 0x33, 0xfb, - 0xcd, 0x78, 0x51, 0xd5, 0xa3, 0x8c, 0x50, 0x66, 0xe2, 0x84, 0x1f, 0x98, 0x47, 0x0d, 0x17, 0x38, - 0x6e, 0x88, 0xc0, 0x88, 0x62, 0xca, 0xa9, 0xba, 0x20, 0x79, 0x43, 0x40, 0x39, 0x5f, 0x99, 0xc7, - 0x24, 0x08, 0xa9, 0x29, 0xbe, 0x52, 0x57, 0x59, 0x92, 0x3a, 0x47, 0x44, 0x66, 0x9e, 0x24, 0xa9, - 0xb2, 0x4f, 0x7d, 0x2a, 0xf1, 0xec, 0x34, 0x48, 0xf0, 0x29, 0xf5, 0x3b, 0x60, 0x8a, 0xc8, 0x4d, - 0xf6, 0x4d, 0x1c, 0xa6, 0x92, 0x5a, 0xfe, 0x30, 0x86, 0x4a, 0x16, 0x66, 0xb0, 0xe9, 0x79, 0x34, - 0x09, 0xb9, 0xda, 0x44, 0x93, 0xb8, 0xdd, 0x8e, 0x81, 0x31, 0x4d, 0xd1, 0x95, 0xfa, 0xb4, 0xa5, - 0x7d, 0x3b, 0x5f, 0x2b, 0xe7, 0x3d, 0x36, 0x25, 0xd3, 0xe2, 0x71, 0x10, 0xfa, 0xf6, 0x40, 0xa8, - 0xee, 0xa1, 0xc9, 0x28, 0x71, 0x9d, 0x43, 0x48, 0xb5, 0x31, 0x5d, 0xa9, 0x97, 0x9a, 0x65, 0x43, - 0x36, 0x34, 0x06, 0x0d, 0x8d, 0xcd, 0x30, 0xb5, 0xee, 0xfe, 0xee, 0xd5, 0xca, 0x51, 0xe2, 0x76, - 0x02, 0x2f, 0xd3, 0xde, 0xa7, 0x24, 0xe0, 0x40, 0x22, 0x9e, 0x7e, 0xba, 0x3a, 0x5b, 0x45, 0x7f, - 0x09, 0x7b, 0x22, 0x4a, 0xdc, 0xe7, 0x90, 0xaa, 0x2b, 0x68, 0x0e, 0xcb, 0x6b, 0x39, 0x61, 0x42, - 0x5c, 0x88, 0xb5, 0x71, 0x5d, 0xa9, 0x17, 0xed, 0xd9, 0x1c, 0x7d, 0x29, 0x40, 0xb5, 0x82, 0xa6, - 0x18, 0xbc, 0x4d, 0x20, 0xf4, 0x40, 0x2b, 0x0a, 0xc1, 0x75, 0xbc, 0x61, 0xbe, 0x3b, 0xad, 0x15, - 0x7e, 0x9d, 0xd6, 0x0a, 0x5f, 0xcf, 0xd7, 0xa6, 0x72, 0x8f, 0xdb, 0xef, 0xaf, 0xce, 0x56, 0x17, - 0xa5, 0xa5, 0x35, 0xd6, 0x3e, 0x34, 0x87, 0xfc, 0x2f, 0x7f, 0x51, 0xd0, 0xec, 0x0e, 0x6d, 0x27, - 0x9d, 0xeb, 0x89, 0x6c, 0xa3, 0x19, 0x17, 0x33, 0x70, 0xf2, 0xa6, 0x62, 0x2c, 0xa5, 0xa6, 0x6e, - 0xdc, 0xb2, 0x2c, 0x63, 0xa8, 0x92, 0x55, 0xbc, 0xe8, 0xd5, 0x14, 0xbb, 0xe4, 0x0e, 0x0d, 0x57, - 0x45, 0xc5, 0x10, 0x13, 0x10, 0x53, 0x9a, 0xb6, 0xc5, 0x59, 0xd5, 0x51, 0x29, 0x82, 0x98, 0x04, - 0x8c, 0x05, 0x34, 0x64, 0xda, 0xb8, 0x3e, 0x5e, 0x9f, 0xb6, 0x87, 0xa1, 0x8d, 0xc7, 0x99, 0x87, - 0x13, 0xe9, 0x61, 0x6e, 0xe4, 0x6e, 0xc2, 0x89, 0x36, 0xe4, 0x64, 0x84, 0x5d, 0xfe, 0x31, 0x86, - 0x26, 0x76, 0x71, 0x8c, 0x09, 0x53, 0x0d, 0xb4, 0x40, 0x70, 0xd7, 0x21, 0x40, 0xa8, 0xe3, 0x1d, - 0xe0, 0x18, 0x7b, 0x1c, 0x62, 0xb9, 0xe2, 0xa2, 0x3d, 0x4f, 0x70, 0x77, 0x07, 0x08, 0xdd, 0xba, - 0x26, 0x54, 0x1d, 0xcd, 0xf0, 0xae, 0xc3, 0x02, 0xdf, 0xe9, 0x04, 0x24, 0xe0, 0xe2, 0xc6, 0x45, - 0x1b, 0xf1, 0x6e, 0x2b, 0xf0, 0x5f, 0x64, 0x88, 0xfa, 0x00, 0xfd, 0x2f, 0x14, 0xc7, 0xe0, 0x78, - 0x94, 0x71, 0x27, 0x82, 0xd8, 0x71, 0x53, 0x0e, 0xf9, 0x8e, 0xe6, 0x33, 0xe9, 0x31, 0x6c, 0x51, - 0xc6, 0x77, 0x21, 0xb6, 0x52, 0x0e, 0xea, 0x2b, 0x74, 0x27, 0x2b, 0x78, 0x04, 0x71, 0xb0, 0x9f, - 0xca, 0x24, 0x68, 0x37, 0xd7, 0xd7, 0x1b, 0x4f, 0xe4, 0xda, 0x2c, 0xad, 0xdf, 0xab, 0x95, 0x5b, - 0x81, 0xbf, 0x27, 0x14, 0x59, 0xea, 0xb3, 0xa7, 0x82, 0xb7, 0xcb, 0x6c, 0x04, 0x95, 0x59, 0xea, - 0x6b, 0xb4, 0x74, 0xb3, 0x20, 0x03, 0x2f, 0x6a, 0xae, 0x3f, 0x3a, 0x6c, 0x68, 0xff, 0x89, 0x92, - 0x95, 0x7e, 0xaf, 0xb6, 0x38, 0x52, 0xb2, 0x35, 0x50, 0xd8, 0x8b, 0xec, 0x56, 0x7c, 0x63, 0xe5, - 0x44, 0xfe, 0x33, 0xca, 0xcd, 0xe9, 0x76, 0xe5, 0xcb, 0x95, 0x23, 0xb5, 0xb6, 0x3e, 0xf7, 0xab, - 0xca, 0x45, 0xbf, 0xaa, 0xfc, 0xec, 0x57, 0x95, 0x8f, 0x97, 0xd5, 0xc2, 0xc5, 0x65, 0xb5, 0xf0, - 0xfd, 0xb2, 0x5a, 0x78, 0x73, 0xcf, 0x0f, 0xf8, 0x41, 0xe2, 0x1a, 0x1e, 0x25, 0xf9, 0xeb, 0x34, - 0xff, 0xad, 0xc2, 0xd3, 0x08, 0x98, 0x3b, 0x21, 0x5e, 0xc8, 0xc3, 0x3f, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x56, 0x7e, 0xb1, 0xc7, 0x1b, 0x04, 0x00, 0x00, + // 704 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x54, 0x4d, 0x4f, 0xdb, 0x48, + 0x18, 0x8e, 0x93, 0x2c, 0x1f, 0x13, 0x60, 0x17, 0x93, 0x65, 0x4d, 0x0e, 0x89, 0x15, 0x09, 0x91, + 0x45, 0x8b, 0xbd, 0x49, 0x45, 0xab, 0x72, 0x23, 0x69, 0x0f, 0x88, 0x42, 0x91, 0xa3, 0x72, 0xa8, + 0x2a, 0x59, 0x63, 0x67, 0x30, 0x23, 0x32, 0x1e, 0xd7, 0x33, 0x46, 0x31, 0xbf, 0xa0, 0xaa, 0x54, + 0xa9, 0x47, 0x8e, 0xa8, 0xbf, 0x80, 0x03, 0x3f, 0xa2, 0xed, 0x09, 0xf5, 0x54, 0xa9, 0x52, 0x54, + 0x85, 0x03, 0x55, 0x7f, 0x45, 0xe5, 0x19, 0x07, 0x12, 0xca, 0x25, 0xf2, 0xfb, 0x3c, 0xcf, 0xfb, + 0xfd, 0x4e, 0x40, 0xd9, 0xa5, 0x8c, 0x50, 0x66, 0xc2, 0x88, 0x1f, 0x9a, 0xc7, 0x75, 0x07, 0x71, + 0x58, 0x17, 0x86, 0x11, 0x84, 0x94, 0x53, 0x75, 0x41, 0xf2, 0x86, 0x80, 0x52, 0xbe, 0x34, 0x0f, + 0x09, 0xf6, 0xa9, 0x29, 0x7e, 0xa5, 0xae, 0xb4, 0x24, 0x75, 0xb6, 0xb0, 0xcc, 0xd4, 0x49, 0x52, + 0x45, 0x8f, 0x7a, 0x54, 0xe2, 0xc9, 0xd7, 0xd0, 0xc1, 0xa3, 0xd4, 0xeb, 0x22, 0x53, 0x58, 0x4e, + 0x74, 0x60, 0x42, 0x3f, 0x96, 0x54, 0xf5, 0x5d, 0x16, 0x14, 0x9a, 0x90, 0xa1, 0x4d, 0xd7, 0xa5, + 0x91, 0xcf, 0xd5, 0x06, 0x98, 0x84, 0x9d, 0x4e, 0x88, 0x18, 0xd3, 0x14, 0x5d, 0xa9, 0x4d, 0x37, + 0xb5, 0x2f, 0x17, 0x6b, 0xc5, 0x34, 0xc7, 0xa6, 0x64, 0xda, 0x3c, 0xc4, 0xbe, 0x67, 0x0d, 0x85, + 0xea, 0x3e, 0x98, 0x0c, 0x22, 0xc7, 0x3e, 0x42, 0xb1, 0x96, 0xd5, 0x95, 0x5a, 0xa1, 0x51, 0x34, + 0x64, 0x42, 0x63, 0x98, 0xd0, 0xd8, 0xf4, 0xe3, 0xe6, 0xca, 0xcf, 0x7e, 0xa5, 0x18, 0x44, 0x4e, + 0x17, 0xbb, 0x89, 0xf6, 0x3f, 0x4a, 0x30, 0x47, 0x24, 0xe0, 0xf1, 0x87, 0xeb, 0xf3, 0x55, 0x70, + 0x4b, 0x58, 0x13, 0x41, 0xe4, 0x6c, 0xa3, 0x58, 0x5d, 0x06, 0x73, 0x50, 0x96, 0x65, 0xfb, 0x11, + 0x71, 0x50, 0xa8, 0xe5, 0x74, 0xa5, 0x96, 0xb7, 0x66, 0x53, 0x74, 0x57, 0x80, 0x6a, 0x09, 0x4c, + 0x31, 0xf4, 0x3a, 0x42, 0xbe, 0x8b, 0xb4, 0xbc, 0x10, 0xdc, 0xd8, 0x1b, 0xe6, 0x9b, 0xb3, 0x4a, + 0xe6, 0xc7, 0x59, 0x25, 0xf3, 0xf9, 0x62, 0x6d, 0x2a, 0xed, 0x71, 0xeb, 0xed, 0xf5, 0xf9, 0xea, + 0xa2, 0x6c, 0x69, 0x8d, 0x75, 0x8e, 0xcc, 0x91, 0xfe, 0xab, 0x9f, 0x14, 0x30, 0xbb, 0x43, 0x3b, + 0x51, 0xf7, 0x66, 0x22, 0x5b, 0x60, 0xc6, 0x81, 0x0c, 0xd9, 0x69, 0x52, 0x31, 0x96, 0x42, 0x43, + 0x37, 0xee, 0x59, 0x96, 0x31, 0x12, 0xa9, 0x99, 0xbf, 0xec, 0x57, 0x14, 0xab, 0xe0, 0x8c, 0x0c, + 0x57, 0x05, 0x79, 0x1f, 0x12, 0x24, 0xa6, 0x34, 0x6d, 0x89, 0x6f, 0x55, 0x07, 0x85, 0x00, 0x85, + 0x04, 0x33, 0x86, 0xa9, 0xcf, 0xb4, 0x9c, 0x9e, 0xab, 0x4d, 0x5b, 0xa3, 0xd0, 0xc6, 0xa3, 0xa4, + 0x87, 0x53, 0xd9, 0xc3, 0xdc, 0x58, 0x6d, 0xa2, 0x13, 0x6d, 0xa4, 0x93, 0x31, 0xb6, 0xfa, 0x0a, + 0xfc, 0x25, 0x81, 0x56, 0x88, 0x3a, 0xc8, 0xe7, 0x18, 0x76, 0xd5, 0x0a, 0x28, 0x10, 0x81, 0xd9, + 0xa2, 0x12, 0xb1, 0x63, 0x0b, 0x48, 0x68, 0x37, 0xa9, 0x67, 0x05, 0xfc, 0xd9, 0x41, 0x21, 0x3e, + 0x86, 0x1c, 0x53, 0x3f, 0x59, 0x07, 0xd3, 0xb2, 0x7a, 0xae, 0x36, 0x63, 0xcd, 0xdd, 0xc2, 0xdb, + 0x28, 0x66, 0xd5, 0x6f, 0x59, 0x30, 0xb1, 0x07, 0x43, 0x48, 0x98, 0x6a, 0x80, 0x05, 0x02, 0x7b, + 0x36, 0x41, 0x84, 0xda, 0xee, 0x21, 0x0c, 0xa1, 0xcb, 0x51, 0x28, 0x0f, 0x28, 0x6f, 0xcd, 0x13, + 0xd8, 0xdb, 0x41, 0x84, 0xb6, 0x6e, 0x08, 0x55, 0x07, 0x33, 0xbc, 0x67, 0x33, 0xec, 0xd9, 0x5d, + 0x4c, 0x30, 0x17, 0xf3, 0xc8, 0x5b, 0x80, 0xf7, 0xda, 0xd8, 0x7b, 0x96, 0x20, 0xea, 0xff, 0xe0, + 0x6f, 0xa1, 0x38, 0x41, 0xb6, 0x4b, 0x19, 0xb7, 0x03, 0x14, 0xda, 0x4e, 0xcc, 0x51, 0x7a, 0x01, + 0xf3, 0x89, 0xf4, 0x04, 0xb5, 0x28, 0xe3, 0x7b, 0x28, 0x6c, 0xc6, 0x1c, 0xa9, 0xcf, 0xc1, 0x3f, + 0x49, 0xc0, 0x63, 0x14, 0xe2, 0x83, 0x58, 0x3a, 0xa1, 0x4e, 0x63, 0x7d, 0xbd, 0xfe, 0x58, 0x1e, + 0x45, 0x53, 0x1b, 0xf4, 0x2b, 0xc5, 0x36, 0xf6, 0xf6, 0x85, 0x22, 0x71, 0x7d, 0xfa, 0x44, 0xf0, + 0x56, 0x91, 0x8d, 0xa1, 0xd2, 0x4b, 0x7d, 0x01, 0x96, 0xee, 0x06, 0x64, 0xc8, 0x0d, 0x1a, 0xeb, + 0x0f, 0x8f, 0xea, 0xda, 0x1f, 0x22, 0x64, 0x69, 0xd0, 0xaf, 0x2c, 0x8e, 0x85, 0x6c, 0x0f, 0x15, + 0xd6, 0x22, 0xbb, 0x17, 0xdf, 0x58, 0x3e, 0x95, 0x17, 0xa9, 0xdc, 0xdd, 0x5d, 0x4f, 0xfe, 0x2f, + 0xc8, 0x91, 0x36, 0x5b, 0x1f, 0x07, 0x65, 0xe5, 0x72, 0x50, 0x56, 0xbe, 0x0f, 0xca, 0xca, 0xfb, + 0xab, 0x72, 0xe6, 0xf2, 0xaa, 0x9c, 0xf9, 0x7a, 0x55, 0xce, 0xbc, 0xfc, 0xd7, 0xc3, 0xfc, 0x30, + 0x72, 0x0c, 0x97, 0x92, 0xf4, 0xed, 0x9b, 0xbf, 0x47, 0xe1, 0x71, 0x80, 0x98, 0x33, 0x21, 0xde, + 0xdf, 0x83, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x70, 0x41, 0x50, 0x4a, 0x79, 0x04, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -376,6 +438,45 @@ func (m *ModuleAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ModuleCredential) 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 *ModuleCredential) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ModuleCredential) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DerivationKeys) > 0 { + for iNdEx := len(m.DerivationKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.DerivationKeys[iNdEx]) + copy(dAtA[i:], m.DerivationKeys[iNdEx]) + i = encodeVarintAuth(dAtA, i, uint64(len(m.DerivationKeys[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.ModuleName) > 0 { + i -= len(m.ModuleName) + copy(dAtA[i:], m.ModuleName) + i = encodeVarintAuth(dAtA, i, uint64(len(m.ModuleName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Params) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -481,6 +582,25 @@ func (m *ModuleAccount) Size() (n int) { return n } +func (m *ModuleCredential) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ModuleName) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) + } + if len(m.DerivationKeys) > 0 { + for _, b := range m.DerivationKeys { + l = len(b) + n += 1 + l + sovAuth(uint64(l)) + } + } + return n +} + func (m *Params) Size() (n int) { if m == nil { return 0 @@ -817,6 +937,120 @@ func (m *ModuleAccount) Unmarshal(dAtA []byte) error { } return nil } +func (m *ModuleCredential) 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 ErrIntOverflowAuth + } + 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: ModuleCredential: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ModuleCredential: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ModuleName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + 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 ErrInvalidLengthAuth + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuth + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ModuleName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DerivationKeys", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAuth + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DerivationKeys = append(m.DerivationKeys, make([]byte, postIndex-iNdEx)) + copy(m.DerivationKeys[len(m.DerivationKeys)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuth(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuth + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Params) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/auth/types/codec.go b/x/auth/types/codec.go index 76680d824d..9182f0ef97 100644 --- a/x/auth/types/codec.go +++ b/x/auth/types/codec.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" @@ -21,6 +22,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) cdc.RegisterConcrete(&ModuleAccount{}, "cosmos-sdk/ModuleAccount", nil) cdc.RegisterConcrete(Params{}, "cosmos-sdk/x/auth/Params", nil) + cdc.RegisterConcrete(&ModuleCredential{}, "cosmos-sdk/GroupAccountCredential", nil) legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "cosmos-sdk/x/auth/MsgUpdateParams") @@ -44,6 +46,12 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &ModuleAccount{}, ) + registry.RegisterInterface( + "cosmos.auth.v1.ModuleCredential", + (*cryptotypes.PubKey)(nil), + &ModuleCredential{}, + ) + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgUpdateParams{}, ) diff --git a/x/auth/types/credentials.go b/x/auth/types/credentials.go new file mode 100644 index 0000000000..7632689621 --- /dev/null +++ b/x/auth/types/credentials.go @@ -0,0 +1,91 @@ +package types + +import ( + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" +) + +// NewBaseAccountWithPubKey creates an account with an a pubkey. +func NewBaseAccountWithPubKey(pubkey cryptotypes.PubKey) (*BaseAccount, error) { + if pubkey == nil { + return nil, fmt.Errorf("pubkey cannot be nil") + } + + baseAccount := NewBaseAccountWithAddress(sdk.AccAddress(pubkey.Address())) + if err := baseAccount.SetPubKey(pubkey); err != nil { + return nil, fmt.Errorf("failed to create a valid account with credentials: %w", err) + } + + if err := baseAccount.Validate(); err != nil { + return nil, fmt.Errorf("failed to create a valid account with credentials: %w", err) + } + + return baseAccount, nil +} + +//nolint:gosec // this isn't an hardcoded credential +const ModuleCredentialType = "ModuleCredential" + +var _ cryptotypes.PubKey = &ModuleCredential{} + +func NewModuleCredential(moduleName string, derivationKeys [][]byte) *ModuleCredential { + return &ModuleCredential{ + ModuleName: moduleName, + DerivationKeys: derivationKeys, + } +} + +func (m *ModuleCredential) Address() cryptotypes.Address { + var addr []byte + for i, dk := range m.DerivationKeys { + if i == 0 { + addr = address.Module(m.ModuleName, dk) + continue + } + + addr = address.Derive(addr, dk) + } + + return addr +} + +func (m *ModuleCredential) Bytes() []byte { + return nil +} + +// VerifySignature returns always false, making the account unclaimable +func (m *ModuleCredential) VerifySignature(_ []byte, _ []byte) bool { + return false +} + +func (m *ModuleCredential) Equals(other cryptotypes.PubKey) bool { + om, ok := other.(*ModuleCredential) + if !ok { + return false + } + + if m.ModuleName != om.ModuleName { + return false + } + + if len(m.DerivationKeys) != len(om.DerivationKeys) { + return false + } + + for i := range m.DerivationKeys { + for j := range m.DerivationKeys[i] { + if m.DerivationKeys[i][j] != om.DerivationKeys[i][j] { + return false + } + } + } + + return true +} + +func (m *ModuleCredential) Type() string { + return ModuleCredentialType +} diff --git a/x/auth/types/credentials_test.go b/x/auth/types/credentials_test.go new file mode 100644 index 0000000000..39cc07f223 --- /dev/null +++ b/x/auth/types/credentials_test.go @@ -0,0 +1,39 @@ +package types_test + +import ( + "testing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/require" +) + +func TestNewModuleCrendentials(t *testing.T) { + expected := sdk.MustAccAddressFromBech32("cosmos1fpn0w0yf4x300llf5r66jnfhgj4ul6cfahrvqsskwkhsw6sv84wsmz359y") + + credential := authtypes.NewModuleCredential("group", [][]byte{{0x20}, {0x0}}) + require.NoError(t, sdk.VerifyAddressFormat(credential.Address().Bytes())) + addr, err := sdk.AccAddressFromHexUnsafe(credential.Address().String()) + require.NoError(t, err) + require.Equal(t, expected.String(), addr.String()) + + require.True(t, credential.Equals(authtypes.NewModuleCredential("group", [][]byte{{0x20}, {0x0}}))) + require.False(t, credential.Equals(authtypes.NewModuleCredential("group", [][]byte{{0x20}, {0x1}}))) + require.False(t, credential.Equals(authtypes.NewModuleCredential("group", [][]byte{{0x20}}))) +} + +func TestNewBaseAccountWithPubKey(t *testing.T) { + expected := sdk.MustAccAddressFromBech32("cosmos1fpn0w0yf4x300llf5r66jnfhgj4ul6cfahrvqsskwkhsw6sv84wsmz359y") + + credential := authtypes.NewModuleCredential("group", [][]byte{{0x20}, {0x0}}) + account, err := authtypes.NewBaseAccountWithPubKey(credential) + require.NoError(t, err) + require.Equal(t, expected, account.GetAddress()) + require.Equal(t, credential, account.GetPubKey()) +} + +func TestNewBaseAccountWithPubKey_WrongCredentials(t *testing.T) { + _, err := authtypes.NewBaseAccountWithPubKey(cryptotypes.PubKey(nil)) + require.Error(t, err) +} diff --git a/x/crisis/migrations/v2/migrate_test.go b/x/crisis/migrations/v2/migrate_test.go index 4239b675d0..40bf888559 100644 --- a/x/crisis/migrations/v2/migrate_test.go +++ b/x/crisis/migrations/v2/migrate_test.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/crisis" v2 "github.com/cosmos/cosmos-sdk/x/crisis/migrations/v2" "github.com/cosmos/cosmos-sdk/x/crisis/types" - "github.com/cosmos/cosmos-sdk/x/distribution" ) type mockSubspace struct { @@ -26,9 +26,7 @@ func (ms mockSubspace) Get(ctx sdk.Context, key []byte, ptr interface{}) { } func TestMigrate(t *testing.T) { - encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) - cdc := encCfg.Codec - + cdc := moduletestutil.MakeTestEncodingConfig(crisis.AppModuleBasic{}).Codec storeKey := sdk.NewKVStoreKey(v2.ModuleName) tKey := sdk.NewTransientStoreKey("transient_test") ctx := testutil.DefaultContext(storeKey, tKey) diff --git a/x/distribution/migrations/v3/migrate_test.go b/x/distribution/migrations/v3/migrate_test.go index b0de4b4605..3a485ebf2d 100644 --- a/x/distribution/migrations/v3/migrate_test.go +++ b/x/distribution/migrations/v3/migrate_test.go @@ -27,9 +27,7 @@ func (ms mockSubspace) GetParamSet(ctx sdk.Context, ps exported.ParamSet) { } func TestMigrate(t *testing.T) { - encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) - cdc := encCfg.Codec - + cdc := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}).Codec storeKey := sdk.NewKVStoreKey(v3.ModuleName) tKey := sdk.NewTransientStoreKey("transient_test") ctx := testutil.DefaultContext(storeKey, tKey) diff --git a/x/group/expected_keepers.go b/x/group/expected_keepers.go index f5baa0d486..389665843d 100644 --- a/x/group/expected_keepers.go +++ b/x/group/expected_keepers.go @@ -14,6 +14,8 @@ type AccountKeeper interface { // Set an account in the store. SetAccount(sdk.Context, authtypes.AccountI) + // Remove an account in the store. + RemoveAccount(ctx sdk.Context, acc authtypes.AccountI) } // BankKeeper defines the expected interface needed to retrieve account balances. diff --git a/x/group/keeper/keeper_test.go b/x/group/keeper/keeper_test.go index 33a0b969db..0e9197cb27 100644 --- a/x/group/keeper/keeper_test.go +++ b/x/group/keeper/keeper_test.go @@ -20,7 +20,6 @@ import ( simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/bank" @@ -61,12 +60,9 @@ func (s *TestSuite) SetupTest() { // setup gomock and initialize some globally expected executions ctrl := gomock.NewController(s.T()) s.accountKeeper = grouptestutil.NewMockAccountKeeper(ctrl) - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[0]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[0])).AnyTimes() - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[1]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[1])).AnyTimes() - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[2]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[2])).AnyTimes() - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[3]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[3])).AnyTimes() - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[4]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[4])).AnyTimes() - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[5]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[5])).AnyTimes() + for i := range s.addrs { + s.accountKeeper.EXPECT().GetAccount(gomock.Any(), s.addrs[i]).Return(authtypes.NewBaseAccountWithAddress(s.addrs[i])).AnyTimes() + } s.bankKeeper = grouptestutil.NewMockBankKeeper(ctrl) bApp := baseapp.NewBaseApp( @@ -125,25 +121,21 @@ func (s *TestSuite) SetupTest() { func (s TestSuite) setNextAccount() { nextAccVal := s.groupKeeper.GetGroupPolicySeq(s.sdkCtx) + 1 - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, nextAccVal) + derivationKey := make([]byte, 8) + binary.BigEndian.PutUint64(derivationKey, nextAccVal) - var accountAddr sdk.AccAddress - parentAcc := address.Module(group.ModuleName, []byte{keeper.GroupPolicyTablePrefix}) - accountAddr = address.Derive(parentAcc, buf) - s.accountKeeper.EXPECT().GetAccount(gomock.Any(), accountAddr).Return(nil).AnyTimes() - s.accountKeeper.EXPECT().NewAccount(gomock.Any(), &authtypes.ModuleAccount{ - BaseAccount: &authtypes.BaseAccount{ - Address: accountAddr.String(), - }, - Name: accountAddr.String(), - }).Return(authtypes.NewModuleAccount(authtypes.NewBaseAccountWithAddress(accountAddr), accountAddr.String())).AnyTimes() - s.accountKeeper.EXPECT().SetAccount(gomock.Any(), &authtypes.ModuleAccount{ - BaseAccount: &authtypes.BaseAccount{ - Address: accountAddr.String(), - }, - Name: accountAddr.String(), - }).Return().AnyTimes() + accountCredentials := authtypes.NewModuleCredential(group.ModuleName, [][]byte{{keeper.GroupPolicyTablePrefix}, derivationKey}) + + groupPolicyAcc, err := authtypes.NewBaseAccountWithPubKey(accountCredentials) + s.Require().NoError(err) + + groupPolicyAccBumpAccountNumber, err := authtypes.NewBaseAccountWithPubKey(accountCredentials) + s.Require().NoError(err) + groupPolicyAccBumpAccountNumber.SetAccountNumber(nextAccVal) + + s.accountKeeper.EXPECT().GetAccount(gomock.Any(), sdk.AccAddress(accountCredentials.Address())).Return(nil).AnyTimes() + s.accountKeeper.EXPECT().NewAccount(gomock.Any(), groupPolicyAcc).Return(groupPolicyAccBumpAccountNumber).AnyTimes() + s.accountKeeper.EXPECT().SetAccount(gomock.Any(), authtypes.AccountI(groupPolicyAccBumpAccountNumber)).Return().AnyTimes() } func TestKeeperTestSuite(t *testing.T) { diff --git a/x/group/keeper/migrations.go b/x/group/keeper/migrations.go new file mode 100644 index 0000000000..402479b976 --- /dev/null +++ b/x/group/keeper/migrations.go @@ -0,0 +1,27 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + v2 "github.com/cosmos/cosmos-sdk/x/group/migrations/v2" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.Migrate( + ctx, + m.keeper.key, + m.keeper.accKeeper, + m.keeper.groupPolicySeq, + m.keeper.groupPolicyTable, + ) +} diff --git a/x/group/keeper/msg_server.go b/x/group/keeper/msg_server.go index 0023c57a90..70486a0962 100644 --- a/x/group/keeper/msg_server.go +++ b/x/group/keeper/msg_server.go @@ -6,7 +6,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/group" @@ -334,23 +333,24 @@ func (k Keeper) CreateGroupPolicy(goCtx context.Context, req *group.MsgCreateGro // collision with an existing address. for { nextAccVal := k.groupPolicySeq.NextVal(ctx.KVStore(k.key)) - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, nextAccVal) - - parentAcc := address.Module(group.ModuleName, []byte{GroupPolicyTablePrefix}) - accountAddr = address.Derive(parentAcc, buf) + derivationKey := make([]byte, 8) + binary.BigEndian.PutUint64(derivationKey, nextAccVal) + accountCredentials := authtypes.NewModuleCredential(group.ModuleName, [][]byte{{GroupPolicyTablePrefix}, derivationKey}) + accountAddr = sdk.AccAddress(accountCredentials.Address()) if k.accKeeper.GetAccount(ctx, accountAddr) != nil { // handle a rare collision, in which case we just go on to the // next sequence value and derive a new address. continue } - acc := k.accKeeper.NewAccount(ctx, &authtypes.ModuleAccount{ - BaseAccount: &authtypes.BaseAccount{ - Address: accountAddr.String(), - }, - Name: accountAddr.String(), - }) + + // group policy accounts are unclaimable base accounts + account, err := authtypes.NewBaseAccountWithPubKey(accountCredentials) + if err != nil { + return nil, sdkerrors.Wrap(err, "could not create group policy account") + } + + acc := k.accKeeper.NewAccount(ctx, account) k.accKeeper.SetAccount(ctx, acc) break diff --git a/x/group/migrations/v2/migrate.go b/x/group/migrations/v2/migrate.go new file mode 100644 index 0000000000..bb574c0b2d --- /dev/null +++ b/x/group/migrations/v2/migrate.go @@ -0,0 +1,78 @@ +package v2 + +import ( + "encoding/binary" + "fmt" + + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/group" + "github.com/cosmos/cosmos-sdk/x/group/internal/orm" +) + +const ( + ModuleName = "group" + + // Group Policy Table + GroupPolicyTablePrefix byte = 0x20 + GroupPolicyTableSeqPrefix byte = 0x21 +) + +// Migrate migrates the x/group module state from the consensus version 1 to version 2. +// Specifically, it changes the group policy account to from module account to base account. +func Migrate( + ctx sdk.Context, + storeKey storetypes.StoreKey, + accountKeeper group.AccountKeeper, + groupPolicySeq orm.Sequence, + groupPolicyTable orm.PrimaryKeyTable, +) error { + store := ctx.KVStore(storeKey) + curAccVal := groupPolicySeq.CurVal(store) + groupPolicyAccountDerivationKey := make(map[string][]byte, 0) + for i := uint64(0); i <= curAccVal; i++ { + derivationKey := make([]byte, 8) + binary.BigEndian.PutUint64(derivationKey, i) + parentAcc := address.Module(group.ModuleName, []byte{GroupPolicyTablePrefix}) + groupPolicyAcc := sdk.AccAddress(address.Derive(parentAcc, derivationKey)) + groupPolicyAccountDerivationKey[groupPolicyAcc.String()] = derivationKey + } + + // get all group policies + var groupPolicies []*group.GroupPolicyInfo + if _, err := groupPolicyTable.Export(store, &groupPolicies); err != nil { + return fmt.Errorf("failed to get group policies: %w", err) + } + + for _, policy := range groupPolicies { + // get the account address by acc id + oldAcc := accountKeeper.GetAccount(ctx, sdk.MustAccAddressFromBech32(policy.Address)) + // remove the old account + accountKeeper.RemoveAccount(ctx, oldAcc) + + // create the group policy account + derivationKey, ok := groupPolicyAccountDerivationKey[policy.Address] + if !ok { + // should never happen + panic(fmt.Errorf("group policy account %s derivation key not found", policy.Address)) + } + + accountCredentials := authtypes.NewModuleCredential(group.ModuleName, [][]byte{{GroupPolicyTablePrefix}, derivationKey}) + baseAccount, err := authtypes.NewBaseAccountWithPubKey(accountCredentials) + if err != nil { + return fmt.Errorf("failed to create new group policy account: %w", err) + } + + // NOTE: we do not call NewAccount because we do not want to bump the account number + + // set new account + // because we have only changed the account type, so we can use: + // - the same account number + // - the same address + accountKeeper.SetAccount(ctx, baseAccount) + } + + return nil +} diff --git a/x/group/migrations/v2/migrate_test.go b/x/group/migrations/v2/migrate_test.go new file mode 100644 index 0000000000..9773021679 --- /dev/null +++ b/x/group/migrations/v2/migrate_test.go @@ -0,0 +1,92 @@ +package v2_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/group" + "github.com/cosmos/cosmos-sdk/x/group/internal/orm" + groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" + v2 "github.com/cosmos/cosmos-sdk/x/group/migrations/v2" + groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" +) + +var ( + policies = []sdk.AccAddress{policyAddr1, policyAddr2, policyAddr3} + policyAddr1 = sdk.MustAccAddressFromBech32("cosmos1q32tjg5qm3n9fj8wjgpd7gl98prefntrckjkyvh8tntp7q33zj0s5tkjrk") + policyAddr2 = sdk.MustAccAddressFromBech32("cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd") + policyAddr3 = sdk.MustAccAddressFromBech32("cosmos1dlszg2sst9r69my4f84l3mj66zxcf3umcgujys30t84srg95dgvsmn3jeu") + accountAddr = sdk.AccAddress("addr2_______________") +) + +func TestMigrate(t *testing.T) { + cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, groupmodule.AppModuleBasic{}).Codec + storeKey := sdk.NewKVStoreKey(v2.ModuleName) + tKey := sdk.NewTransientStoreKey("transient_test") + ctx := testutil.DefaultContext(storeKey, tKey) + + accountKeeper := createOldPolicyAccount(ctx, storeKey, cdc) + groupPolicyTable, groupPolicySeq, err := createGroupPolicies(ctx, storeKey, cdc) + require.NoError(t, err) + + oldAcc := accountKeeper.GetAccount(ctx, policyAddr1) + + require.NoError(t, v2.Migrate(ctx, storeKey, accountKeeper, groupPolicySeq, groupPolicyTable)) + newAcc := accountKeeper.GetAccount(ctx, policyAddr1) + + require.NotEqual(t, oldAcc, newAcc) + require.True(t, func() bool { _, ok := oldAcc.(*authtypes.ModuleAccount); return ok }()) + require.True(t, func() bool { _, ok := newAcc.(*authtypes.BaseAccount); return ok }()) + require.Equal(t, oldAcc.GetAddress(), newAcc.GetAddress()) + require.Equal(t, oldAcc.GetAccountNumber(), newAcc.GetAccountNumber()) + require.Equal(t, newAcc.GetPubKey().Address().Bytes(), newAcc.GetAddress().Bytes()) +} + +func createGroupPolicies(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec) (orm.PrimaryKeyTable, orm.Sequence, error) { + groupPolicyTable, err := orm.NewPrimaryKeyTable([2]byte{groupkeeper.GroupPolicyTablePrefix}, &group.GroupPolicyInfo{}, cdc) + if err != nil { + panic(err.Error()) + } + + groupPolicySeq := orm.NewSequence(v2.GroupPolicyTableSeqPrefix) + + for _, policyAddr := range policies { + groupPolicyInfo, err := group.NewGroupPolicyInfo(policyAddr, 1, accountAddr, "", 1, group.NewPercentageDecisionPolicy("1", 1, 1), ctx.BlockTime()) + if err != nil { + return orm.PrimaryKeyTable{}, orm.Sequence{}, err + } + + if err := groupPolicyTable.Create(ctx.KVStore(storeKey), &groupPolicyInfo); err != nil { + return orm.PrimaryKeyTable{}, orm.Sequence{}, err + } + + groupPolicySeq.NextVal(ctx.KVStore(storeKey)) + } + + return *groupPolicyTable, groupPolicySeq, nil +} + +// createOldPolicyAccount re-creates the group policy account using a module account +func createOldPolicyAccount(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec) group.AccountKeeper { + accountKeeper := authkeeper.NewAccountKeeper(cdc, storeKey, authtypes.ProtoBaseAccount, nil, sdk.Bech32MainPrefix, accountAddr.String()) + for _, policyAddr := range policies { + acc := accountKeeper.NewAccount(ctx, &authtypes.ModuleAccount{ + BaseAccount: &authtypes.BaseAccount{ + Address: policyAddr.String(), + }, + Name: policyAddr.String(), + }) + accountKeeper.SetAccount(ctx, acc) + } + + return accountKeeper +} diff --git a/x/group/module/module.go b/x/group/module/module.go index 75b1a6be65..373361325f 100644 --- a/x/group/module/module.go +++ b/x/group/module/module.go @@ -28,6 +28,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/group/simulation" ) +// ConsensusVersion defines the current x/group module consensus version. +const ConsensusVersion = 2 + var ( _ module.EndBlockAppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} @@ -145,10 +148,15 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (am AppModule) RegisterServices(cfg module.Configurator) { group.RegisterMsgServer(cfg.MsgServer(), am.keeper) group.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + m := keeper.NewMigrator(am.keeper) + if err := cfg.RegisterMigration(group.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", group.ModuleName, err)) + } } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 1 } +func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion } // EndBlock implements the group module's EndBlock. func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { diff --git a/x/group/testutil/expected_keepers_mocks.go b/x/group/testutil/expected_keepers_mocks.go index ea9ae48066..2e51cfad54 100644 --- a/x/group/testutil/expected_keepers_mocks.go +++ b/x/group/testutil/expected_keepers_mocks.go @@ -65,6 +65,18 @@ func (mr *MockAccountKeeperMockRecorder) NewAccount(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccount", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccount), arg0, arg1) } +// RemoveAccount mocks base method. +func (m *MockAccountKeeper) RemoveAccount(ctx types.Context, acc types0.AccountI) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RemoveAccount", ctx, acc) +} + +// RemoveAccount indicates an expected call of RemoveAccount. +func (mr *MockAccountKeeperMockRecorder) RemoveAccount(ctx, acc interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveAccount", reflect.TypeOf((*MockAccountKeeper)(nil).RemoveAccount), ctx, acc) +} + // SetAccount mocks base method. func (m *MockAccountKeeper) SetAccount(arg0 types.Context, arg1 types0.AccountI) { m.ctrl.T.Helper() diff --git a/x/group/types_test.go b/x/group/types_test.go index 0bf8f2e70f..ff117940dc 100644 --- a/x/group/types_test.go +++ b/x/group/types_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/x/group" - "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/x/group" ) func TestThresholdDecisionPolicyValidate(t *testing.T) { diff --git a/x/slashing/migrations/v3/migrator_test.go b/x/slashing/migrations/v3/migrator_test.go index 4030a2360d..b570007666 100644 --- a/x/slashing/migrations/v3/migrator_test.go +++ b/x/slashing/migrations/v3/migrator_test.go @@ -27,9 +27,7 @@ func (ms mockSubspace) GetParamSet(ctx sdk.Context, ps exported.ParamSet) { } func TestMigrate(t *testing.T) { - encCfg := moduletestutil.MakeTestEncodingConfig(slashing.AppModuleBasic{}) - cdc := encCfg.Codec - + cdc := moduletestutil.MakeTestEncodingConfig(slashing.AppModuleBasic{}).Codec storeKey := sdk.NewKVStoreKey(v3.ModuleName) tKey := sdk.NewTransientStoreKey("transient_test") ctx := testutil.DefaultContext(storeKey, tKey) diff --git a/x/staking/migrations/v4/migrations_test.go b/x/staking/migrations/v4/migrations_test.go index eee7550785..1efbd4dbf7 100644 --- a/x/staking/migrations/v4/migrations_test.go +++ b/x/staking/migrations/v4/migrations_test.go @@ -30,8 +30,7 @@ func (ms mockSubspace) GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) { } func TestMigrate(t *testing.T) { - encCfg := moduletestutil.MakeTestEncodingConfig(staking.AppModuleBasic{}) - cdc := encCfg.Codec + cdc := moduletestutil.MakeTestEncodingConfig(staking.AppModuleBasic{}).Codec storeKey := sdk.NewKVStoreKey(v4.ModuleName) tKey := sdk.NewTransientStoreKey("transient_test")