diff --git a/CHANGELOG.md b/CHANGELOG.md index 660866500e77..4ecea9b99820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (runtime) [#15547](https://github.com/cosmos/cosmos-sdk/pull/15547) Allow runtime to pass event core api service to modules * (telemetry) [#15657](https://github.com/cosmos/cosmos-sdk/pull/15657) Emit more data (go version, sdk version, upgrade height) in prom metrics * (modulemanager) [#15829](https://github.com/cosmos/cosmos-sdk/pull/15829) add new endblocker interface to handle valset updates +* (core) [#14860](https://github.com/cosmos/cosmos-sdk/pull/14860) Add `Precommit` and `PrepareCheckState` AppModule callbacks. ### Improvements diff --git a/api/cosmos/app/runtime/v1alpha1/module.pulsar.go b/api/cosmos/app/runtime/v1alpha1/module.pulsar.go index e8fe74d59cd5..d29da340c176 100644 --- a/api/cosmos/app/runtime/v1alpha1/module.pulsar.go +++ b/api/cosmos/app/runtime/v1alpha1/module.pulsar.go @@ -294,15 +294,109 @@ func (x *_Module_7_list) IsValid() bool { return x.list != nil } +var _ protoreflect.List = (*_Module_8_list)(nil) + +type _Module_8_list struct { + list *[]string +} + +func (x *_Module_8_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_Module_8_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfString((*x.list)[i]) +} + +func (x *_Module_8_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue +} + +func (x *_Module_8_list) Append(value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) +} + +func (x *_Module_8_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message Module at list field Precommiters as it is not of Message kind")) +} + +func (x *_Module_8_list) Truncate(n int) { + *x.list = (*x.list)[:n] +} + +func (x *_Module_8_list) NewElement() protoreflect.Value { + v := "" + return protoreflect.ValueOfString(v) +} + +func (x *_Module_8_list) IsValid() bool { + return x.list != nil +} + +var _ protoreflect.List = (*_Module_9_list)(nil) + +type _Module_9_list struct { + list *[]string +} + +func (x *_Module_9_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_Module_9_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfString((*x.list)[i]) +} + +func (x *_Module_9_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue +} + +func (x *_Module_9_list) Append(value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) +} + +func (x *_Module_9_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message Module at list field PrepareCheckStaters as it is not of Message kind")) +} + +func (x *_Module_9_list) Truncate(n int) { + *x.list = (*x.list)[:n] +} + +func (x *_Module_9_list) NewElement() protoreflect.Value { + v := "" + return protoreflect.ValueOfString(v) +} + +func (x *_Module_9_list) IsValid() bool { + return x.list != nil +} + var ( - md_Module protoreflect.MessageDescriptor - fd_Module_app_name protoreflect.FieldDescriptor - fd_Module_begin_blockers protoreflect.FieldDescriptor - fd_Module_end_blockers protoreflect.FieldDescriptor - fd_Module_init_genesis protoreflect.FieldDescriptor - fd_Module_export_genesis protoreflect.FieldDescriptor - fd_Module_override_store_keys protoreflect.FieldDescriptor - fd_Module_order_migrations protoreflect.FieldDescriptor + md_Module protoreflect.MessageDescriptor + fd_Module_app_name protoreflect.FieldDescriptor + fd_Module_begin_blockers protoreflect.FieldDescriptor + fd_Module_end_blockers protoreflect.FieldDescriptor + fd_Module_init_genesis protoreflect.FieldDescriptor + fd_Module_export_genesis protoreflect.FieldDescriptor + fd_Module_override_store_keys protoreflect.FieldDescriptor + fd_Module_order_migrations protoreflect.FieldDescriptor + fd_Module_precommiters protoreflect.FieldDescriptor + fd_Module_prepare_check_staters protoreflect.FieldDescriptor ) func init() { @@ -315,6 +409,8 @@ func init() { fd_Module_export_genesis = md_Module.Fields().ByName("export_genesis") fd_Module_override_store_keys = md_Module.Fields().ByName("override_store_keys") fd_Module_order_migrations = md_Module.Fields().ByName("order_migrations") + fd_Module_precommiters = md_Module.Fields().ByName("precommiters") + fd_Module_prepare_check_staters = md_Module.Fields().ByName("prepare_check_staters") } var _ protoreflect.Message = (*fastReflection_Module)(nil) @@ -424,6 +520,18 @@ func (x *fastReflection_Module) Range(f func(protoreflect.FieldDescriptor, proto return } } + if len(x.Precommiters) != 0 { + value := protoreflect.ValueOfList(&_Module_8_list{list: &x.Precommiters}) + if !f(fd_Module_precommiters, value) { + return + } + } + if len(x.PrepareCheckStaters) != 0 { + value := protoreflect.ValueOfList(&_Module_9_list{list: &x.PrepareCheckStaters}) + if !f(fd_Module_prepare_check_staters, value) { + return + } + } } // Has reports whether a field is populated. @@ -453,6 +561,10 @@ func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool { return len(x.OverrideStoreKeys) != 0 case "cosmos.app.runtime.v1alpha1.Module.order_migrations": return len(x.OrderMigrations) != 0 + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + return len(x.Precommiters) != 0 + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + return len(x.PrepareCheckStaters) != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.app.runtime.v1alpha1.Module")) @@ -483,6 +595,10 @@ func (x *fastReflection_Module) Clear(fd protoreflect.FieldDescriptor) { x.OverrideStoreKeys = nil case "cosmos.app.runtime.v1alpha1.Module.order_migrations": x.OrderMigrations = nil + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + x.Precommiters = nil + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + x.PrepareCheckStaters = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.app.runtime.v1alpha1.Module")) @@ -538,6 +654,18 @@ func (x *fastReflection_Module) Get(descriptor protoreflect.FieldDescriptor) pro } listValue := &_Module_7_list{list: &x.OrderMigrations} return protoreflect.ValueOfList(listValue) + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + if len(x.Precommiters) == 0 { + return protoreflect.ValueOfList(&_Module_8_list{}) + } + listValue := &_Module_8_list{list: &x.Precommiters} + return protoreflect.ValueOfList(listValue) + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + if len(x.PrepareCheckStaters) == 0 { + return protoreflect.ValueOfList(&_Module_9_list{}) + } + listValue := &_Module_9_list{list: &x.PrepareCheckStaters} + return protoreflect.ValueOfList(listValue) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.app.runtime.v1alpha1.Module")) @@ -584,6 +712,14 @@ func (x *fastReflection_Module) Set(fd protoreflect.FieldDescriptor, value proto lv := value.List() clv := lv.(*_Module_7_list) x.OrderMigrations = *clv.list + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + lv := value.List() + clv := lv.(*_Module_8_list) + x.Precommiters = *clv.list + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + lv := value.List() + clv := lv.(*_Module_9_list) + x.PrepareCheckStaters = *clv.list default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.app.runtime.v1alpha1.Module")) @@ -640,6 +776,18 @@ func (x *fastReflection_Module) Mutable(fd protoreflect.FieldDescriptor) protore } value := &_Module_7_list{list: &x.OrderMigrations} return protoreflect.ValueOfList(value) + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + if x.Precommiters == nil { + x.Precommiters = []string{} + } + value := &_Module_8_list{list: &x.Precommiters} + return protoreflect.ValueOfList(value) + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + if x.PrepareCheckStaters == nil { + x.PrepareCheckStaters = []string{} + } + value := &_Module_9_list{list: &x.PrepareCheckStaters} + return protoreflect.ValueOfList(value) case "cosmos.app.runtime.v1alpha1.Module.app_name": panic(fmt.Errorf("field app_name of message cosmos.app.runtime.v1alpha1.Module is not mutable")) default: @@ -675,6 +823,12 @@ func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protor case "cosmos.app.runtime.v1alpha1.Module.order_migrations": list := []string{} return protoreflect.ValueOfList(&_Module_7_list{list: &list}) + case "cosmos.app.runtime.v1alpha1.Module.precommiters": + list := []string{} + return protoreflect.ValueOfList(&_Module_8_list{list: &list}) + case "cosmos.app.runtime.v1alpha1.Module.prepare_check_staters": + list := []string{} + return protoreflect.ValueOfList(&_Module_9_list{list: &list}) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.app.runtime.v1alpha1.Module")) @@ -784,6 +938,18 @@ func (x *fastReflection_Module) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } + if len(x.Precommiters) > 0 { + for _, s := range x.Precommiters { + l = len(s) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if len(x.PrepareCheckStaters) > 0 { + for _, s := range x.PrepareCheckStaters { + l = len(s) + n += 1 + l + runtime.Sov(uint64(l)) + } + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -813,6 +979,24 @@ func (x *fastReflection_Module) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.PrepareCheckStaters) > 0 { + for iNdEx := len(x.PrepareCheckStaters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.PrepareCheckStaters[iNdEx]) + copy(dAtA[i:], x.PrepareCheckStaters[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.PrepareCheckStaters[iNdEx]))) + i-- + dAtA[i] = 0x4a + } + } + if len(x.Precommiters) > 0 { + for iNdEx := len(x.Precommiters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.Precommiters[iNdEx]) + copy(dAtA[i:], x.Precommiters[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Precommiters[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } if len(x.OrderMigrations) > 0 { for iNdEx := len(x.OrderMigrations) - 1; iNdEx >= 0; iNdEx-- { i -= len(x.OrderMigrations[iNdEx]) @@ -1156,6 +1340,70 @@ func (x *fastReflection_Module) ProtoMethods() *protoiface.Methods { } x.OrderMigrations = append(x.OrderMigrations, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 8: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Precommiters", 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.Precommiters = append(x.Precommiters, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 9: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field PrepareCheckStaters", 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.PrepareCheckStaters = append(x.PrepareCheckStaters, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -1719,6 +1967,14 @@ type Module struct { // If this is left empty, it uses the default migration order. // https://pkg.go.dev/github.com/cosmos/cosmos-sdk@v0.47.0-alpha2/types/module#DefaultMigrationsOrder OrderMigrations []string `protobuf:"bytes,7,rep,name=order_migrations,json=orderMigrations,proto3" json:"order_migrations,omitempty"` + // precommiters specifies the module names of the precommiters + // to call in the order in which they should be called. If this is left empty + // no precommit function will be registered. + Precommiters []string `protobuf:"bytes,8,rep,name=precommiters,proto3" json:"precommiters,omitempty"` + // prepare_check_staters specifies the module names of the prepare_check_staters + // to call in the order in which they should be called. If this is left empty + // no preparecheckstate function will be registered. + PrepareCheckStaters []string `protobuf:"bytes,9,rep,name=prepare_check_staters,json=prepareCheckStaters,proto3" json:"prepare_check_staters,omitempty"` } func (x *Module) Reset() { @@ -1790,6 +2046,20 @@ func (x *Module) GetOrderMigrations() []string { return nil } +func (x *Module) GetPrecommiters() []string { + if x != nil { + return x.Precommiters + } + return nil +} + +func (x *Module) GetPrepareCheckStaters() []string { + if x != nil { + return x.PrepareCheckStaters + } + return nil +} + // StoreKeyConfig may be supplied to override the default module store key, which // is the module name. type StoreKeyConfig struct { @@ -1846,7 +2116,7 @@ var file_cosmos_app_runtime_v1alpha1_module_proto_rawDesc = []byte{ 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x84, 0x03, 0x0a, 0x06, 0x4d, 0x6f, + 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdc, 0x03, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x72, @@ -1866,33 +2136,39 @@ var file_cosmos_app_runtime_v1alpha1_module_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x43, 0xba, 0xc0, 0x96, - 0xda, 0x01, 0x3d, 0x0a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, - 0x6b, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x13, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x22, 0x53, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 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, 0x20, 0x0a, 0x0c, 0x6b, 0x76, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6b, 0x76, 0x53, 0x74, 0x6f, - 0x72, 0x65, 0x4b, 0x65, 0x79, 0x42, 0xfb, 0x01, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 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, 0x70, 0x70, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x52, 0xaa, 0x02, 0x1b, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1b, 0x43, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x70, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, - 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x27, 0x43, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x5c, 0x41, 0x70, 0x70, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x1e, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x70, - 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, + 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x32, 0x0a, 0x15, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, + 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x72, 0x73, 0x3a, 0x43, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x3d, 0x0a, 0x24, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x15, 0x0a, 0x13, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x22, 0x53, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, + 0x65, 0x4b, 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x20, 0x0a, 0x0c, 0x6b, + 0x76, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x6b, 0x76, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x42, 0xfb, 0x01, + 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x70, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, + 0x31, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x3c, 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, 0x70, 0x70, 0x2f, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xa2, 0x02, + 0x03, 0x43, 0x41, 0x52, 0xaa, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, + 0x70, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0xca, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x70, 0x5c, + 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, + 0xe2, 0x02, 0x27, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x70, 0x5c, 0x52, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1e, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x70, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/baseapp/abci.go b/baseapp/abci.go index 8dd1aaec0ba8..db82d3f97ddf 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -457,6 +457,10 @@ func (app *BaseApp) Commit() abci.ResponseCommit { header := app.deliverState.ctx.BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) + if app.precommiter != nil { + app.precommiter(app.deliverState.ctx) + } + rms, ok := app.cms.(*rootmulti.Store) if ok { rms.SetCommitHeader(header) @@ -464,7 +468,7 @@ func (app *BaseApp) Commit() abci.ResponseCommit { // Write the DeliverTx state into branched storage and commit the MultiStore. // The write to the DeliverTx state writes all state transitions to the root - // MultiStore (app.cms) so when Commit() is called is persists those values. + // MultiStore (app.cms) so when Commit() is called it persists those values. app.deliverState.ms.Write() commitID := app.cms.Commit() @@ -497,6 +501,10 @@ func (app *BaseApp) Commit() abci.ResponseCommit { // empty/reset the deliver state app.deliverState = nil + if app.prepareCheckStater != nil { + app.prepareCheckStater(app.checkState.ctx) + } + var halt bool switch { diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index cc762dad42c0..9e2f734dae59 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -598,6 +598,60 @@ func TestABCI_EndBlock(t *testing.T) { require.Equal(t, cp.Block.MaxGas, res.ConsensusParamUpdates.Block.MaxGas) } +func TestBaseApp_PrepareCheckState(t *testing.T) { + db := dbm.NewMemDB() + name := t.Name() + logger := log.NewTestLogger(t) + + cp := &cmtproto.ConsensusParams{ + Block: &cmtproto.BlockParams{ + MaxGas: 5000000, + }, + } + + app := baseapp.NewBaseApp(name, logger, db, nil) + app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) + app.InitChain(abci.RequestInitChain{ + ConsensusParams: cp, + }) + + wasPrepareCheckStateCalled := false + app.SetPrepareCheckStater(func(ctx sdk.Context) { + wasPrepareCheckStateCalled = true + }) + app.Seal() + + app.Commit() + require.Equal(t, true, wasPrepareCheckStateCalled) +} + +func TestBaseApp_Precommit(t *testing.T) { + db := dbm.NewMemDB() + name := t.Name() + logger := log.NewTestLogger(t) + + cp := &cmtproto.ConsensusParams{ + Block: &cmtproto.BlockParams{ + MaxGas: 5000000, + }, + } + + app := baseapp.NewBaseApp(name, logger, db, nil) + app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) + app.InitChain(abci.RequestInitChain{ + ConsensusParams: cp, + }) + + wasPrecommiterCalled := false + app.SetPrecommiter(func(ctx sdk.Context) { + wasPrecommiterCalled = true + }) + app.Seal() + + app.Commit() + require.Equal(t, true, wasPrecommiterCalled) +} + func TestABCI_CheckTx(t *testing.T) { // This ante handler reads the key and checks that the value matches the // current counter. This ensures changes to the KVStore persist across @@ -1322,6 +1376,49 @@ func TestABCI_GetBlockRetentionHeight(t *testing.T) { } } +// Verifies that PrepareCheckState is called with the checkState. +func TestPrepareCheckStateCalledWithCheckState(t *testing.T) { + t.Parallel() + + logger := log.NewTestLogger(t) + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil) + + wasPrepareCheckStateCalled := false + app.SetPrepareCheckStater(func(ctx sdk.Context) { + require.Equal(t, true, ctx.IsCheckTx()) + wasPrepareCheckStateCalled = true + }) + + app.BeginBlock(abci.RequestBeginBlock{Header: cmtproto.Header{Height: 1}}) + app.Commit() + + require.Equal(t, true, wasPrepareCheckStateCalled) +} + +// Verifies that the Precommiter is called with the deliverState. +func TestPrecommiterCalledWithDeliverState(t *testing.T) { + t.Parallel() + + logger := log.NewTestLogger(t) + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil) + + wasPrecommiterCalled := false + app.SetPrecommiter(func(ctx sdk.Context) { + require.Equal(t, false, ctx.IsCheckTx()) + require.Equal(t, false, ctx.IsReCheckTx()) + wasPrecommiterCalled = true + }) + + app.BeginBlock(abci.RequestBeginBlock{Header: cmtproto.Header{Height: 1}}) + app.Commit() + + require.Equal(t, true, wasPrecommiterCalled) +} + func TestABCI_Proposal_HappyPath(t *testing.T) { anteKey := []byte("ante-key") pool := mempool.NewSenderNonceMempool() diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index bf29ecc83f48..931fc0a32a00 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -62,17 +62,19 @@ type BaseApp struct { txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx txEncoder sdk.TxEncoder // marshal sdk.Tx into []byte - mempool mempool.Mempool // application side mempool - anteHandler sdk.AnteHandler // ante handler for fee and auth - postHandler sdk.PostHandler // post handler, optional, e.g. for tips - initChainer sdk.InitChainer // initialize state with validators and state blob - beginBlocker sdk.BeginBlocker // logic to run before any txs - processProposal sdk.ProcessProposalHandler // the handler which runs on ABCI ProcessProposal - prepareProposal sdk.PrepareProposalHandler // the handler which runs on ABCI PrepareProposal - endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes - addrPeerFilter sdk.PeerFilter // filter peers by address and port - idPeerFilter sdk.PeerFilter // filter peers by node ID - fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. + mempool mempool.Mempool // application side mempool + anteHandler sdk.AnteHandler // ante handler for fee and auth + postHandler sdk.PostHandler // post handler, optional, e.g. for tips + initChainer sdk.InitChainer // initialize state with validators and state blob + beginBlocker sdk.BeginBlocker // logic to run before any txs + processProposal sdk.ProcessProposalHandler // the handler which runs on ABCI ProcessProposal + prepareProposal sdk.PrepareProposalHandler // the handler which runs on ABCI PrepareProposal + endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes + prepareCheckStater sdk.PrepareCheckStater // logic to run during commit using the checkState + precommiter sdk.Precommiter // logic to run during commit using the deliverState + addrPeerFilter sdk.PeerFilter // filter peers by address and port + idPeerFilter sdk.PeerFilter // filter peers by node ID + fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. // manages snapshots, i.e. dumps of app state at certain intervals snapshotManager *snapshots.Manager diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 5b367c729bda..f5fe99d10881 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -388,6 +388,12 @@ func TestBaseAppOptionSeal(t *testing.T) { require.Panics(t, func() { suite.baseApp.SetEndBlocker(nil) }) + require.Panics(t, func() { + suite.baseApp.SetPrepareCheckStater(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetPrecommiter(nil) + }) require.Panics(t, func() { suite.baseApp.SetAnteHandler(nil) }) diff --git a/baseapp/options.go b/baseapp/options.go index 2900cd798b5d..c30488df4ee7 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -167,6 +167,22 @@ func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) { app.endBlocker = endBlocker } +func (app *BaseApp) SetPrepareCheckStater(prepareCheckStater sdk.PrepareCheckStater) { + if app.sealed { + panic("SetPrepareCheckStater() on sealed BaseApp") + } + + app.prepareCheckStater = prepareCheckStater +} + +func (app *BaseApp) SetPrecommiter(precommiter sdk.Precommiter) { + if app.sealed { + panic("SetPrecommiter() on sealed BaseApp") + } + + app.precommiter = precommiter +} + func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) { if app.sealed { panic("SetAnteHandler() on sealed BaseApp") diff --git a/docs/docs/building-modules/01-module-manager.md b/docs/docs/building-modules/01-module-manager.md index bd226c730c8f..a420a6f09831 100644 --- a/docs/docs/building-modules/01-module-manager.md +++ b/docs/docs/building-modules/01-module-manager.md @@ -36,6 +36,8 @@ The above interfaces are mostly embedding smaller interfaces (extension interfac * [`HasConsensusVersion`](#hasconsensusversion): The extension interface for declaring a module consensus version. * [`BeginBlockAppModule`](#beginblockappmodule): The extension interface that contains information about the `AppModule` and `BeginBlock`. * [`EndBlockAppModule`](#endblockappmodule): The extension interface that contains information about the `AppModule` and `EndBlock`. +* [`PrecommitAppModule`](#precommitappmodule): The extension interface that contains information about the `AppModule` and `Precommit`. +* [`PrepareCheckStateAppModule`](#preparecheckstateappmodule): The extension interface that contains information about the `AppModule` and `PrepareCheckState`. The `AppModuleBasic` interface exists to define independent methods of the module, i.e. those that do not depend on other modules in the application. This allows for the construction of the basic application structure early in the application definition, generally in the `init()` function of the [main application file](../basics/00-app-anatomy.md#core-application-file). @@ -167,6 +169,18 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/types/module/module.go#L20 * `EndBlock(sdk.Context, abci.RequestEndBlock)`: This method gives module developers the option to implement logic that is automatically triggered at the end of each block. This is also where the module can inform the underlying consensus engine of validator set changes (e.g. the `staking` module). Implement empty if no logic needs to be triggered at the end of each block for this module. +### `PrecommitAppModule` + +The `PrecommitAppModule` is an extension interface from `AppModule`. All modules that have a `Precommit` method implement this interface. + +* `Precommit(sdk.Context)`: This method gives module developers the option to implement logic that is automatically triggered during [`Commit'](../core/00-baseapp.md#commit) of each block using the [`deliverState`](../core/00-baseapp.md#state-updates) of the block to be committed. Implement empty if no logic needs to be triggered during `Commit` of each block for this module. + +### `PrepareCheckStateAppModule` + +The `PrepareCheckStateAppModule` is an extension interface from `AppModule`. All modules that have a `PrepareCheckState` method implement this interface. + +* `PrepareCheckState(sdk.Context)`: This method gives module developers the option to implement logic that is automatically triggered during [`Commit'](../core/00-baseapp.md#commit) of each block using the [`checkState`](../core/00-baseapp.md#state-updates) of the next block. Implement empty if no logic needs to be triggered during `Commit` of each block for this module. + ### Implementing the Application Module Interfaces Typically, the various application module interfaces are implemented in a file called `module.go`, located in the module's folder (e.g. `./x/module/module.go`). @@ -228,6 +242,8 @@ The module manager is used throughout the application whenever an action on a co * `SetOrderExportGenesis(moduleNames ...string)`: Sets the order in which the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module will be called in case of an export. This function is generally called from the application's main [constructor function](../basics/00-app-anatomy.md#constructor-function). * `SetOrderBeginBlockers(moduleNames ...string)`: Sets the order in which the `BeginBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../basics/00-app-anatomy.md#constructor-function). * `SetOrderEndBlockers(moduleNames ...string)`: Sets the order in which the `EndBlock()` function of each module will be called at the end of each block. This function is generally called from the application's main [constructor function](../basics/00-app-anatomy.md#constructor-function). +* `SetOrderPrecommiters(moduleNames ...string)`: Sets the order in which the `Precommit()` function of each module will be called during commit of each block. This function is generally called from the application's main [constructor function](../basics/00-app-anatomy.md#constructor-function). +* `SetOrderPrepareCheckStaters(moduleNames ...string)`: Sets the order in which the `PrepareCheckState()` function of each module will be called during commit of each block. This function is generally called from the application's main [constructor function](../basics/00-app-anatomy.md#constructor-function). * `SetOrderMigrations(moduleNames ...string)`: Sets the order of migrations to be run. If not set then migrations will be run with an order defined in `DefaultMigrationsOrder`. * `RegisterInvariants(ir sdk.InvariantRegistry)`: Registers the [invariants](./07-invariants.md) of module implementing the `HasInvariants` interface. * `RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter, legacyQuerierCdc *codec.LegacyAmino)`: Registers legacy [`Msg`](./02-messages-and-queries.md#messages) and [`querier`](./04-query-services.md#legacy-queriers) routes. @@ -237,6 +253,8 @@ The module manager is used throughout the application whenever an action on a co * `ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string)`: Behaves the same as `ExportGenesis`, except takes a list of modules to export. * `BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock)`: At the beginning of each block, this function is called from [`BaseApp`](../core/00-baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./05-beginblock-endblock.md) function of each modules implementing the `BeginBlockAppModule` interface, in the order defined in `OrderBeginBlockers`. It creates a child [context](../core/02-context.md) with an event manager to aggregate [events](../core/08-events.md) emitted from all modules. The function returns an `abci.ResponseBeginBlock` which contains the aforementioned events. * `EndBlock(ctx sdk.Context, req abci.RequestEndBlock)`: At the end of each block, this function is called from [`BaseApp`](../core/00-baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./05-beginblock-endblock.md) function of each modules implementing the `EndBlockAppModule` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../core/02-context.md) with an event manager to aggregate [events](../core/08-events.md) emitted from all modules. The function returns an `abci.ResponseEndBlock` which contains the aforementioned events, as well as validator set updates (if any). +* `Precommit(ctx sdk.Context)`: During [`Commit`](../core/00-baseapp.md#commit), this function is called from `BaseApp` immediately before the [`deliverState`](../core/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../core/04-store.md#commitmultistore) and, in turn calls the `Precommit` function of each modules implementing the `PrecommitAppModule` interface, in the order defined in `OrderPrecommiters`. It creates a child [context](../core/02-context.md) where the underlying `CacheMultiStore` is that of the newly committed block's [`deliverState`](../core/00-baseapp.md#state-updates). +* `PrepareCheckState(ctx sdk.Context)`: During [`Commit`](../core/00-baseapp.md#commit), this function is called from `BaseApp` immediately after the [`deliverState`](../core/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../core/04-store.md#commitmultistore) and, in turn calls the `PrepareCheckState` function of each module implementing the `PrepareCheckStateAppModule` interface, in the order defined in `OrderPrepareCheckStaters`. It creates a child [context](../core/02-context.md) where the underlying `CacheMultiStore` is that of the next block's [`checkState`](../core/00-baseapp.md#state-updates). Writes to this state will be present in the [`checkState`](../core/00-baseapp.md#state-updates) of the next block, and therefore this method can be used to prepare the `checkState` for the next block. Here's an example of a concrete integration within an `simapp`: diff --git a/go.mod b/go.mod index 6c0a46fbe6a9..6c5dedff0abf 100644 --- a/go.mod +++ b/go.mod @@ -162,6 +162,7 @@ require ( // Below are the long-lived replace of the Cosmos SDK replace ( + cosmossdk.io/api => ./api // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 // dgrijalva/jwt-go is deprecated and doesn't receive security updates. diff --git a/go.sum b/go.sum index 07d272880725..e07fcf01543b 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cosmossdk.io/api v0.4.0 h1:x90DmdidP6EhzktAa/6/IofSHidDnPjahdlrUvyQZQw= -cosmossdk.io/api v0.4.0/go.mod h1:TWDzBhUBhI1LhSf2XSYpfIBf6D4mbLu/fvzvDfhcaYM= cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8= cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo= cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= diff --git a/proto/cosmos/app/runtime/v1alpha1/module.proto b/proto/cosmos/app/runtime/v1alpha1/module.proto index e92ce482f3f9..c02612170271 100644 --- a/proto/cosmos/app/runtime/v1alpha1/module.proto +++ b/proto/cosmos/app/runtime/v1alpha1/module.proto @@ -42,6 +42,16 @@ message Module { // If this is left empty, it uses the default migration order. // https://pkg.go.dev/github.com/cosmos/cosmos-sdk@v0.47.0-alpha2/types/module#DefaultMigrationsOrder repeated string order_migrations = 7; + + // precommiters specifies the module names of the precommiters + // to call in the order in which they should be called. If this is left empty + // no precommit function will be registered. + repeated string precommiters = 8; + + // prepare_check_staters specifies the module names of the prepare_check_staters + // to call in the order in which they should be called. If this is left empty + // no preparecheckstate function will be registered. + repeated string prepare_check_staters = 9; } // StoreKeyConfig may be supplied to override the default module store key, which diff --git a/runtime/app.go b/runtime/app.go index 4bfd07798f20..86634a6b4863 100644 --- a/runtime/app.go +++ b/runtime/app.go @@ -100,6 +100,16 @@ func (a *App) Load(loadLatest bool) error { a.SetEndBlocker(a.EndBlocker) } + if len(a.config.Precommiters) != 0 { + a.ModuleManager.SetOrderPrecommiters(a.config.Precommiters...) + a.SetPrecommiter(a.Precommiter) + } + + if len(a.config.PrepareCheckStaters) != 0 { + a.ModuleManager.SetOrderPrepareCheckStaters(a.config.PrepareCheckStaters...) + a.SetPrepareCheckStater(a.PrepareCheckStater) + } + if len(a.config.OrderMigrations) != 0 { a.ModuleManager.SetOrderMigrations(a.config.OrderMigrations...) } @@ -123,6 +133,16 @@ func (a *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) (abci.Respon return a.ModuleManager.EndBlock(ctx, req) } +// Precommiter application updates every commit +func (a *App) Precommiter(ctx sdk.Context) { + a.ModuleManager.Precommit(ctx) +} + +// PrepareCheckStater application updates every commit +func (a *App) PrepareCheckStater(ctx sdk.Context) { + a.ModuleManager.PrepareCheckState(ctx) +} + // InitChainer initializes the chain. func (a *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) (abci.ResponseInitChain, error) { var genesisState map[string]json.RawMessage diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index e6542df86e19..c669c816a964 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -8,9 +8,11 @@ import ( // Common metric key constants const ( - MetricKeyBeginBlocker = "begin_blocker" - MetricKeyEndBlocker = "end_blocker" - MetricLabelNameModule = "module" + MetricKeyBeginBlocker = "begin_blocker" + MetricKeyEndBlocker = "end_blocker" + MetricKeyPrepareCheckStater = "prepare_check_stater" + MetricKeyPrecommiter = "precommiter" + MetricLabelNameModule = "module" ) // NewLabel creates a new instance of Label with name and value diff --git a/tests/go.mod b/tests/go.mod index 8419aa4f8993..3dc2a46a41cd 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -193,6 +193,7 @@ require ( replace ( cosmossdk.io/api => ../api // TODO tag all extracted modules after SDK refactor + cosmossdk.io/api => ../api cosmossdk.io/store => ../store cosmossdk.io/x/evidence => ../x/evidence cosmossdk.io/x/feegrant => ../x/feegrant diff --git a/testutil/mock/types_module_module.go b/testutil/mock/types_module_module.go index c406366748c0..e6e96e9c870b 100644 --- a/testutil/mock/types_module_module.go +++ b/testutil/mock/types_module_module.go @@ -881,6 +881,232 @@ func (mr *MockEndBlockAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 inter return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockEndBlockAppModule)(nil).RegisterLegacyAminoCodec), arg0) } +// MockPrepareCheckStateAppModule is a mock of PrepareCheckStateAppModule interface. +type MockPrepareCheckStateAppModule struct { + ctrl *gomock.Controller + recorder *MockPrepareCheckStateAppModuleMockRecorder +} + +// MockPrepareCheckStateAppModuleMockRecorder is the mock recorder for MockPrepareCheckStateAppModule. +type MockPrepareCheckStateAppModuleMockRecorder struct { + mock *MockPrepareCheckStateAppModule +} + +// NewMockPrepareCheckStateAppModule creates a new mock instance. +func NewMockPrepareCheckStateAppModule(ctrl *gomock.Controller) *MockPrepareCheckStateAppModule { + mock := &MockPrepareCheckStateAppModule{ctrl: ctrl} + mock.recorder = &MockPrepareCheckStateAppModuleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPrepareCheckStateAppModule) EXPECT() *MockPrepareCheckStateAppModuleMockRecorder { + return m.recorder +} + +// GetQueryCmd mocks base method. +func (m *MockPrepareCheckStateAppModule) GetQueryCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) GetQueryCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).GetQueryCmd)) +} + +// GetTxCmd mocks base method. +func (m *MockPrepareCheckStateAppModule) GetTxCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) GetTxCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).GetTxCmd)) +} + +// Name mocks base method. +func (m *MockPrepareCheckStateAppModule) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).Name)) +} + +// PrepareCheckState mocks base method. +func (m *MockPrepareCheckStateAppModule) PrepareCheckState(arg0 types1.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "PrepareCheckState", arg0) +} + +// PrepareCheckState indicates an expected call of PrepareCheckState. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) PrepareCheckState(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareCheckState", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).PrepareCheckState), arg0) +} + +// RegisterGRPCGatewayRoutes mocks base method. +func (m *MockPrepareCheckStateAppModule) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) +} + +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) +} + +// RegisterInterfaces mocks base method. +func (m *MockPrepareCheckStateAppModule) RegisterInterfaces(arg0 types0.InterfaceRegistry) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterInterfaces", arg0) +} + +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).RegisterInterfaces), arg0) +} + +// RegisterLegacyAminoCodec mocks base method. +func (m *MockPrepareCheckStateAppModule) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) +} + +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockPrepareCheckStateAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockPrepareCheckStateAppModule)(nil).RegisterLegacyAminoCodec), arg0) +} + +// MockPrecommitAppModule is a mock of PrecommitAppModule interface. +type MockPrecommitAppModule struct { + ctrl *gomock.Controller + recorder *MockPrecommitAppModuleMockRecorder +} + +// MockPrecommitAppModuleMockRecorder is the mock recorder for MockPrecommitAppModule. +type MockPrecommitAppModuleMockRecorder struct { + mock *MockPrecommitAppModule +} + +// NewMockPrecommitAppModule creates a new mock instance. +func NewMockPrecommitAppModule(ctrl *gomock.Controller) *MockPrecommitAppModule { + mock := &MockPrecommitAppModule{ctrl: ctrl} + mock.recorder = &MockPrecommitAppModuleMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPrecommitAppModule) EXPECT() *MockPrecommitAppModuleMockRecorder { + return m.recorder +} + +// GetQueryCmd mocks base method. +func (m *MockPrecommitAppModule) GetQueryCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQueryCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetQueryCmd indicates an expected call of GetQueryCmd. +func (mr *MockPrecommitAppModuleMockRecorder) GetQueryCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueryCmd", reflect.TypeOf((*MockPrecommitAppModule)(nil).GetQueryCmd)) +} + +// GetTxCmd mocks base method. +func (m *MockPrecommitAppModule) GetTxCmd() *cobra.Command { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTxCmd") + ret0, _ := ret[0].(*cobra.Command) + return ret0 +} + +// GetTxCmd indicates an expected call of GetTxCmd. +func (mr *MockPrecommitAppModuleMockRecorder) GetTxCmd() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxCmd", reflect.TypeOf((*MockPrecommitAppModule)(nil).GetTxCmd)) +} + +// Name mocks base method. +func (m *MockPrecommitAppModule) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockPrecommitAppModuleMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPrecommitAppModule)(nil).Name)) +} + +// Precommit mocks base method. +func (m *MockPrecommitAppModule) Precommit(arg0 types1.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Precommit", arg0) +} + +// Precommit indicates an expected call of Precommit. +func (mr *MockPrecommitAppModuleMockRecorder) Precommit(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Precommit", reflect.TypeOf((*MockPrecommitAppModule)(nil).Precommit), arg0) +} + +// RegisterGRPCGatewayRoutes mocks base method. +func (m *MockPrecommitAppModule) RegisterGRPCGatewayRoutes(arg0 client.Context, arg1 *runtime.ServeMux) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterGRPCGatewayRoutes", arg0, arg1) +} + +// RegisterGRPCGatewayRoutes indicates an expected call of RegisterGRPCGatewayRoutes. +func (mr *MockPrecommitAppModuleMockRecorder) RegisterGRPCGatewayRoutes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCGatewayRoutes", reflect.TypeOf((*MockPrecommitAppModule)(nil).RegisterGRPCGatewayRoutes), arg0, arg1) +} + +// RegisterInterfaces mocks base method. +func (m *MockPrecommitAppModule) RegisterInterfaces(arg0 types0.InterfaceRegistry) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterInterfaces", arg0) +} + +// RegisterInterfaces indicates an expected call of RegisterInterfaces. +func (mr *MockPrecommitAppModuleMockRecorder) RegisterInterfaces(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterfaces", reflect.TypeOf((*MockPrecommitAppModule)(nil).RegisterInterfaces), arg0) +} + +// RegisterLegacyAminoCodec mocks base method. +func (m *MockPrecommitAppModule) RegisterLegacyAminoCodec(arg0 *codec.LegacyAmino) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterLegacyAminoCodec", arg0) +} + +// RegisterLegacyAminoCodec indicates an expected call of RegisterLegacyAminoCodec. +func (mr *MockPrecommitAppModuleMockRecorder) RegisterLegacyAminoCodec(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterLegacyAminoCodec", reflect.TypeOf((*MockPrecommitAppModule)(nil).RegisterLegacyAminoCodec), arg0) +} + // MockHasABCIEndblock is a mock of HasABCIEndblock interface. type MockHasABCIEndblock struct { ctrl *gomock.Controller diff --git a/types/abci.go b/types/abci.go index b0e272a825c3..263747d758b7 100644 --- a/types/abci.go +++ b/types/abci.go @@ -19,6 +19,13 @@ type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) (abci.ResponseBe // e.g. BFT timestamps rather than block height for any periodic EndBlock logic type EndBlocker func(ctx Context, req abci.RequestEndBlock) (abci.ResponseEndBlock, error) +// PrepareCheckStater runs code during commit after the block has been committed, and the `checkState` +// has been branched for the new block. +type PrepareCheckStater func(ctx Context) + +// Precommiter runs code during commit immediately before the `deliverState` is written to the `rootMultiStore`. +type Precommiter func(ctx Context) + // PeerFilter responds to p2p filtering queries from Tendermint type PeerFilter func(info string) abci.ResponseQuery diff --git a/types/module/module.go b/types/module/module.go index e1891edda90a..3e52dc8b24d1 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -213,6 +213,19 @@ type EndBlockAppModule interface { EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate } +// PrepareCheckStateAppModule is an extension interface that contains information about the AppModule +// and PrepareCheckState. +type PrepareCheckStateAppModule interface { + AppModule + PrepareCheckState(sdk.Context) +} + +// PreommitAppModule is an extension interface that contains information about the AppModule and Precommit. +type PrecommitAppModule interface { + AppModule + Precommit(sdk.Context) +} + type HasABCIEndblock interface { AppModule EndBlock(context.Context) ([]abci.ValidatorUpdate, error) @@ -259,12 +272,14 @@ func (GenesisOnlyAppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []ab // Manager defines a module manager that provides the high level utility for managing and executing // operations for a group of modules type Manager struct { - Modules map[string]interface{} // interface{} is used now to support the legacy AppModule as well as new core appmodule.AppModule. - OrderInitGenesis []string - OrderExportGenesis []string - OrderBeginBlockers []string - OrderEndBlockers []string - OrderMigrations []string + Modules map[string]interface{} // interface{} is used now to support the legacy AppModule as well as new core appmodule.AppModule. + OrderInitGenesis []string + OrderExportGenesis []string + OrderBeginBlockers []string + OrderEndBlockers []string + OrderPrepareCheckStaters []string + OrderPrecommiters []string + OrderMigrations []string } // NewManager creates a new Manager object. @@ -277,11 +292,13 @@ func NewManager(modules ...AppModule) *Manager { } return &Manager{ - Modules: moduleMap, - OrderInitGenesis: modulesStr, - OrderExportGenesis: modulesStr, - OrderBeginBlockers: modulesStr, - OrderEndBlockers: modulesStr, + Modules: moduleMap, + OrderInitGenesis: modulesStr, + OrderExportGenesis: modulesStr, + OrderBeginBlockers: modulesStr, + OrderPrepareCheckStaters: modulesStr, + OrderPrecommiters: modulesStr, + OrderEndBlockers: modulesStr, } } @@ -299,11 +316,13 @@ func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager { sort.Strings(modulesStr) return &Manager{ - Modules: simpleModuleMap, - OrderInitGenesis: modulesStr, - OrderExportGenesis: modulesStr, - OrderBeginBlockers: modulesStr, - OrderEndBlockers: modulesStr, + Modules: simpleModuleMap, + OrderInitGenesis: modulesStr, + OrderExportGenesis: modulesStr, + OrderBeginBlockers: modulesStr, + OrderEndBlockers: modulesStr, + OrderPrecommiters: modulesStr, + OrderPrepareCheckStaters: modulesStr, } } @@ -357,6 +376,28 @@ func (m *Manager) SetOrderEndBlockers(moduleNames ...string) { m.OrderEndBlockers = moduleNames } +// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls +func (m *Manager) SetOrderPrepareCheckStaters(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames, + func(moduleName string) bool { + module := m.Modules[moduleName] + _, hasPrepareCheckState := module.(PrepareCheckStateAppModule) + return !hasPrepareCheckState + }) + m.OrderPrepareCheckStaters = moduleNames +} + +// SetOrderPrecommiters sets the order of set precommiter calls +func (m *Manager) SetOrderPrecommiters(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames, + func(moduleName string) bool { + module := m.Modules[moduleName] + _, hasPrecommit := module.(PrecommitAppModule) + return !hasPrecommit + }) + m.OrderPrecommiters = moduleNames +} + // SetOrderMigrations sets the order of migrations to be run. If not set // then migrations will be run with an order defined in `DefaultMigrationsOrder`. func (m *Manager) SetOrderMigrations(moduleNames ...string) { @@ -728,6 +769,28 @@ func (m *Manager) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) (abci.Resp }, nil } +// Precommit performs precommit functionality for all modules. +func (m *Manager) Precommit(ctx sdk.Context) { + for _, moduleName := range m.OrderPrecommiters { + module, ok := m.Modules[moduleName].(PrecommitAppModule) + if !ok { + continue + } + module.Precommit(ctx) + } +} + +// PrepareCheckState performs functionality for preparing the check state for all modules. +func (m *Manager) PrepareCheckState(ctx sdk.Context) { + for _, moduleName := range m.OrderPrepareCheckStaters { + module, ok := m.Modules[moduleName].(PrepareCheckStateAppModule) + if !ok { + continue + } + module.PrepareCheckState(ctx) + } +} + // GetVersionMap gets consensus version from all modules func (m *Manager) GetVersionMap() VersionMap { vermap := make(VersionMap) diff --git a/types/module/module_test.go b/types/module/module_test.go index 89a924172365..2701309d1225 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -100,6 +100,60 @@ func TestGenesisOnlyAppModule(t *testing.T) { goam.RegisterInvariants(mockInvariantRegistry) } +func TestAssertNoForgottenModules(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + mockAppModule1 := mock.NewMockEndBlockAppModule(mockCtrl) + mockAppModule2 := mock.NewMockBeginBlockAppModule(mockCtrl) + mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl) + mockAppModule4 := mock.NewMockPrecommitAppModule(mockCtrl) + mockAppModule5 := mock.NewMockPrepareCheckStateAppModule(mockCtrl) + + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mockAppModule4.EXPECT().Name().Times(2).Return("module4") + mockAppModule5.EXPECT().Name().Times(2).Return("module5") + mm := module.NewManager( + mockAppModule1, + mockAppModule2, + module.CoreAppModuleBasicAdaptor("module3", mockAppModule3), + mockAppModule4, + mockAppModule5, + ) + require.NotNil(t, mm) + require.Equal(t, 5, len(mm.Modules)) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderInitGenesis) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderInitGenesis, missing: [module3]", func() { + mm.SetOrderInitGenesis("module2", "module1") + }) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderExportGenesis) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderExportGenesis, missing: [module3]", func() { + mm.SetOrderExportGenesis("module2", "module1") + }) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderBeginBlockers) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderBeginBlockers, missing: [module2]", func() { + mm.SetOrderBeginBlockers("module1", "module3") + }) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderEndBlockers) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderEndBlockers, missing: [module1]", func() { + mm.SetOrderEndBlockers("module2", "module3") + }) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderPrecommiters) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderPrecommiters, missing: [module4]", func() { + mm.SetOrderPrecommiters("module2", "module1") + }) + + require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderPrepareCheckStaters) + require.PanicsWithValue(t, "all modules must be defined when setting SetOrderPrepareCheckStaters, missing: [module5]", func() { + mm.SetOrderPrepareCheckStaters("module2", "module1") + }) +} + func TestManagerOrderSetters(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -128,6 +182,14 @@ func TestManagerOrderSetters(t *testing.T) { require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers) mm.SetOrderEndBlockers("module2", "module1", "module3") require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers) + + require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrepareCheckStaters) + mm.SetOrderPrepareCheckStaters("module3", "module2", "module1") + require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrepareCheckStaters) + + require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrecommiters) + mm.SetOrderPrecommiters("module3", "module2", "module1") + require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters) } func TestManager_RegisterInvariants(t *testing.T) { @@ -319,6 +381,40 @@ func TestManager_EndBlock(t *testing.T) { require.Error(t, err) } +func TestManager_PrepareCheckState(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mock.NewMockPrepareCheckStateAppModule(mockCtrl) + mockAppModule2 := mock.NewMockPrepareCheckStateAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + mockAppModule1.EXPECT().PrepareCheckState(gomock.Any()).Times(1) + mockAppModule2.EXPECT().PrepareCheckState(gomock.Any()).Times(1) + mm.PrepareCheckState(sdk.Context{}) +} + +func TestManager_Precommit(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mock.NewMockPrecommitAppModule(mockCtrl) + mockAppModule2 := mock.NewMockPrecommitAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mm := module.NewManager(mockAppModule1, mockAppModule2) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.Modules)) + + mockAppModule1.EXPECT().Precommit(gomock.Any()).Times(1) + mockAppModule2.EXPECT().Precommit(gomock.Any()).Times(1) + mm.Precommit(sdk.Context{}) +} + // Core API exclusive tests func TestCoreAPIManager(t *testing.T) { mockCtrl := gomock.NewController(t) @@ -431,6 +527,14 @@ func TestCoreAPIManagerOrderSetters(t *testing.T) { require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers) mm.SetOrderEndBlockers("module2", "module1", "module3") require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers) + + require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrepareCheckStaters) + mm.SetOrderPrepareCheckStaters("module3", "module2", "module1") + require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrepareCheckStaters) + + require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrecommiters) + mm.SetOrderPrecommiters("module3", "module2", "module1") + require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters) } func TestCoreAPIManager_BeginBlock(t *testing.T) {