diff --git a/Makefile b/Makefile index cde147271..698c188c1 100644 --- a/Makefile +++ b/Makefile @@ -317,12 +317,19 @@ localnet_regenesis: check_yq acc_initialize_pubkeys_warn_message ## Regenerate t @cp -r ${HOME}/.poktroll/keyring-test $(POKTROLLD_HOME) @cp -r ${HOME}/.poktroll/config $(POKTROLLD_HOME)/ -.PHONY: send_relay -send_relay: +.PHONY: send_relay_sovereign_app +send_relay_sovereign_app: # Send a relay through the AppGateServer as a sovereign application curl -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ http://localhost:42069/anvil +.PHONY: send_relay_delegating_app +send_relay_delegating_app: # Send a relay through the gateway as an application that's delegating to this gateway + @appAddr=$$(poktrolld keys show app1 -a) && \ + curl -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + $(GATEWAY_URL)/anvil?applicationAddr=$$appAddr + # TODO_BLOCKER(@okdas): Figure out how to copy these over w/ a functional state. # cp ${HOME}/.poktroll/config/app.toml $(POKTROLLD_HOME)/config/app.toml # cp ${HOME}/.poktroll/config/config.toml $(POKTROLLD_HOME)/config/config.toml diff --git a/api/poktroll/application/application.pulsar.go b/api/poktroll/application/application.pulsar.go index 24ca85c5c..ef3812c23 100644 --- a/api/poktroll/application/application.pulsar.go +++ b/api/poktroll/application/application.pulsar.go @@ -13,6 +13,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" io "io" reflect "reflect" + sort "sort" sync "sync" ) @@ -113,12 +114,103 @@ func (x *_Application_4_list) IsValid() bool { return x.list != nil } +var _ protoreflect.Map = (*_Application_5_map)(nil) + +type _Application_5_map struct { + m *map[uint64]*UndelegatingGatewayList +} + +func (x *_Application_5_map) Len() int { + if x.m == nil { + return 0 + } + return len(*x.m) +} + +func (x *_Application_5_map) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) { + if x.m == nil { + return + } + for k, v := range *x.m { + mapKey := (protoreflect.MapKey)(protoreflect.ValueOfUint64(k)) + mapValue := protoreflect.ValueOfMessage(v.ProtoReflect()) + if !f(mapKey, mapValue) { + break + } + } +} + +func (x *_Application_5_map) Has(key protoreflect.MapKey) bool { + if x.m == nil { + return false + } + keyUnwrapped := key.Uint() + concreteValue := keyUnwrapped + _, ok := (*x.m)[concreteValue] + return ok +} + +func (x *_Application_5_map) Clear(key protoreflect.MapKey) { + if x.m == nil { + return + } + keyUnwrapped := key.Uint() + concreteKey := keyUnwrapped + delete(*x.m, concreteKey) +} + +func (x *_Application_5_map) Get(key protoreflect.MapKey) protoreflect.Value { + if x.m == nil { + return protoreflect.Value{} + } + keyUnwrapped := key.Uint() + concreteKey := keyUnwrapped + v, ok := (*x.m)[concreteKey] + if !ok { + return protoreflect.Value{} + } + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_Application_5_map) Set(key protoreflect.MapKey, value protoreflect.Value) { + if !key.IsValid() || !value.IsValid() { + panic("invalid key or value provided") + } + keyUnwrapped := key.Uint() + concreteKey := keyUnwrapped + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*UndelegatingGatewayList) + (*x.m)[concreteKey] = concreteValue +} + +func (x *_Application_5_map) Mutable(key protoreflect.MapKey) protoreflect.Value { + keyUnwrapped := key.Uint() + concreteKey := keyUnwrapped + v, ok := (*x.m)[concreteKey] + if ok { + return protoreflect.ValueOfMessage(v.ProtoReflect()) + } + newValue := new(UndelegatingGatewayList) + (*x.m)[concreteKey] = newValue + return protoreflect.ValueOfMessage(newValue.ProtoReflect()) +} + +func (x *_Application_5_map) NewValue() protoreflect.Value { + v := new(UndelegatingGatewayList) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_Application_5_map) IsValid() bool { + return x.m != nil +} + var ( md_Application protoreflect.MessageDescriptor fd_Application_address protoreflect.FieldDescriptor fd_Application_stake protoreflect.FieldDescriptor fd_Application_service_configs protoreflect.FieldDescriptor fd_Application_delegatee_gateway_addresses protoreflect.FieldDescriptor + fd_Application_pending_undelegations protoreflect.FieldDescriptor ) func init() { @@ -128,6 +220,7 @@ func init() { fd_Application_stake = md_Application.Fields().ByName("stake") fd_Application_service_configs = md_Application.Fields().ByName("service_configs") fd_Application_delegatee_gateway_addresses = md_Application.Fields().ByName("delegatee_gateway_addresses") + fd_Application_pending_undelegations = md_Application.Fields().ByName("pending_undelegations") } var _ protoreflect.Message = (*fastReflection_Application)(nil) @@ -219,6 +312,12 @@ func (x *fastReflection_Application) Range(f func(protoreflect.FieldDescriptor, return } } + if len(x.PendingUndelegations) != 0 { + value := protoreflect.ValueOfMap(&_Application_5_map{m: &x.PendingUndelegations}) + if !f(fd_Application_pending_undelegations, value) { + return + } + } } // Has reports whether a field is populated. @@ -242,6 +341,8 @@ func (x *fastReflection_Application) Has(fd protoreflect.FieldDescriptor) bool { return len(x.ServiceConfigs) != 0 case "poktroll.application.Application.delegatee_gateway_addresses": return len(x.DelegateeGatewayAddresses) != 0 + case "poktroll.application.Application.pending_undelegations": + return len(x.PendingUndelegations) != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -266,6 +367,8 @@ func (x *fastReflection_Application) Clear(fd protoreflect.FieldDescriptor) { x.ServiceConfigs = nil case "poktroll.application.Application.delegatee_gateway_addresses": x.DelegateeGatewayAddresses = nil + case "poktroll.application.Application.pending_undelegations": + x.PendingUndelegations = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -300,6 +403,12 @@ func (x *fastReflection_Application) Get(descriptor protoreflect.FieldDescriptor } listValue := &_Application_4_list{list: &x.DelegateeGatewayAddresses} return protoreflect.ValueOfList(listValue) + case "poktroll.application.Application.pending_undelegations": + if len(x.PendingUndelegations) == 0 { + return protoreflect.ValueOfMap(&_Application_5_map{}) + } + mapValue := &_Application_5_map{m: &x.PendingUndelegations} + return protoreflect.ValueOfMap(mapValue) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -332,6 +441,10 @@ func (x *fastReflection_Application) Set(fd protoreflect.FieldDescriptor, value lv := value.List() clv := lv.(*_Application_4_list) x.DelegateeGatewayAddresses = *clv.list + case "poktroll.application.Application.pending_undelegations": + mv := value.Map() + cmv := mv.(*_Application_5_map) + x.PendingUndelegations = *cmv.m default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -369,6 +482,12 @@ func (x *fastReflection_Application) Mutable(fd protoreflect.FieldDescriptor) pr } value := &_Application_4_list{list: &x.DelegateeGatewayAddresses} return protoreflect.ValueOfList(value) + case "poktroll.application.Application.pending_undelegations": + if x.PendingUndelegations == nil { + x.PendingUndelegations = make(map[uint64]*UndelegatingGatewayList) + } + value := &_Application_5_map{m: &x.PendingUndelegations} + return protoreflect.ValueOfMap(value) case "poktroll.application.Application.address": panic(fmt.Errorf("field address of message poktroll.application.Application is not mutable")) default: @@ -395,6 +514,9 @@ func (x *fastReflection_Application) NewField(fd protoreflect.FieldDescriptor) p case "poktroll.application.Application.delegatee_gateway_addresses": list := []string{} return protoreflect.ValueOfList(&_Application_4_list{list: &list}) + case "poktroll.application.Application.pending_undelegations": + m := make(map[uint64]*UndelegatingGatewayList) + return protoreflect.ValueOfMap(&_Application_5_map{m: &m}) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.Application")) @@ -484,6 +606,34 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } + if len(x.PendingUndelegations) > 0 { + SiZeMaP := func(k uint64, v *UndelegatingGatewayList) { + l := 0 + if v != nil { + l = options.Size(v) + } + l += 1 + runtime.Sov(uint64(l)) + mapEntrySize := 1 + runtime.Sov(uint64(k)) + l + n += mapEntrySize + 1 + runtime.Sov(uint64(mapEntrySize)) + } + if options.Deterministic { + sortme := make([]uint64, 0, len(x.PendingUndelegations)) + for k := range x.PendingUndelegations { + sortme = append(sortme, k) + } + sort.Slice(sortme, func(i, j int) bool { + return sortme[i] < sortme[j] + }) + for _, k := range sortme { + v := x.PendingUndelegations[k] + SiZeMaP(k, v) + } + } else { + for k, v := range x.PendingUndelegations { + SiZeMaP(k, v) + } + } + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -513,6 +663,54 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.PendingUndelegations) > 0 { + MaRsHaLmAp := func(k uint64, v *UndelegatingGatewayList) (protoiface.MarshalOutput, error) { + baseI := i + encoded, err := options.Marshal(v) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + i = runtime.EncodeVarint(dAtA, i, uint64(k)) + i-- + dAtA[i] = 0x8 + i = runtime.EncodeVarint(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a + return protoiface.MarshalOutput{}, nil + } + if options.Deterministic { + keysForPendingUndelegations := make([]uint64, 0, len(x.PendingUndelegations)) + for k := range x.PendingUndelegations { + keysForPendingUndelegations = append(keysForPendingUndelegations, uint64(k)) + } + sort.Slice(keysForPendingUndelegations, func(i, j int) bool { + return keysForPendingUndelegations[i] < keysForPendingUndelegations[j] + }) + for iNdEx := len(keysForPendingUndelegations) - 1; iNdEx >= 0; iNdEx-- { + v := x.PendingUndelegations[uint64(keysForPendingUndelegations[iNdEx])] + out, err := MaRsHaLmAp(keysForPendingUndelegations[iNdEx], v) + if err != nil { + return out, err + } + } + } else { + for k := range x.PendingUndelegations { + v := x.PendingUndelegations[k] + out, err := MaRsHaLmAp(k, v) + if err != nil { + return out, err + } + } + } + } if len(x.DelegateeGatewayAddresses) > 0 { for iNdEx := len(x.DelegateeGatewayAddresses) - 1; iNdEx >= 0; iNdEx-- { i -= len(x.DelegateeGatewayAddresses[iNdEx]) @@ -742,6 +940,121 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { } x.DelegateeGatewayAddresses = append(x.DelegateeGatewayAddresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field PendingUndelegations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.PendingUndelegations == nil { + x.PendingUndelegations = make(map[uint64]*UndelegatingGatewayList) + } + var mapkey uint64 + var mapvalue *UndelegatingGatewayList + for iNdEx < postIndex { + entryPreIndex := 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) + if fieldNum == 1 { + 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++ + mapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else if fieldNum == 2 { + var mapmsglen 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++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postmsgIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + mapvalue = &UndelegatingGatewayList{} + if err := options.Unmarshal(dAtA[iNdEx:postmsgIndex], mapvalue); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + 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) > postIndex { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + x.PendingUndelegations[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -777,163 +1090,733 @@ func (x *fastReflection_Application) ProtoMethods() *protoiface.Methods { } } -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.27.0 -// protoc (unknown) -// source: poktroll/application/application.proto +var _ protoreflect.List = (*_UndelegatingGatewayList_2_list)(nil) -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) +type _UndelegatingGatewayList_2_list struct { + list *[]string +} -// Application defines the type used to store an on-chain definition and state for an application -type Application struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *_UndelegatingGatewayList_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the application using cosmos' ScalarDescriptor to ensure deterministic encoding - Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the application has staked - ServiceConfigs []*shared.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` // The list of services this appliccation is configured to request service for - DelegateeGatewayAddresses []string `protobuf:"bytes,4,rep,name=delegatee_gateway_addresses,json=delegateeGatewayAddresses,proto3" json:"delegatee_gateway_addresses,omitempty"` // The Bech32 encoded addresses for all delegatee Gateways, in a non-nullable slice +func (x *_UndelegatingGatewayList_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfString((*x.list)[i]) } -func (x *Application) Reset() { - *x = Application{} - if protoimpl.UnsafeEnabled { - mi := &file_poktroll_application_application_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } +func (x *_UndelegatingGatewayList_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue } -func (x *Application) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *_UndelegatingGatewayList_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) } -func (*Application) ProtoMessage() {} +func (x *_UndelegatingGatewayList_2_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message UndelegatingGatewayList at list field GatewayAddresses as it is not of Message kind")) +} -// Deprecated: Use Application.ProtoReflect.Descriptor instead. -func (*Application) Descriptor() ([]byte, []int) { - return file_poktroll_application_application_proto_rawDescGZIP(), []int{0} +func (x *_UndelegatingGatewayList_2_list) Truncate(n int) { + *x.list = (*x.list)[:n] } -func (x *Application) GetAddress() string { - if x != nil { - return x.Address - } - return "" +func (x *_UndelegatingGatewayList_2_list) NewElement() protoreflect.Value { + v := "" + return protoreflect.ValueOfString(v) } -func (x *Application) GetStake() *v1beta1.Coin { - if x != nil { - return x.Stake - } - return nil +func (x *_UndelegatingGatewayList_2_list) IsValid() bool { + return x.list != nil } -func (x *Application) GetServiceConfigs() []*shared.ApplicationServiceConfig { - if x != nil { - return x.ServiceConfigs - } - return nil +var ( + md_UndelegatingGatewayList protoreflect.MessageDescriptor + fd_UndelegatingGatewayList_gateway_addresses protoreflect.FieldDescriptor +) + +func init() { + file_poktroll_application_application_proto_init() + md_UndelegatingGatewayList = File_poktroll_application_application_proto.Messages().ByName("UndelegatingGatewayList") + fd_UndelegatingGatewayList_gateway_addresses = md_UndelegatingGatewayList.Fields().ByName("gateway_addresses") } -func (x *Application) GetDelegateeGatewayAddresses() []string { - if x != nil { - return x.DelegateeGatewayAddresses +var _ protoreflect.Message = (*fastReflection_UndelegatingGatewayList)(nil) + +type fastReflection_UndelegatingGatewayList UndelegatingGatewayList + +func (x *UndelegatingGatewayList) ProtoReflect() protoreflect.Message { + return (*fastReflection_UndelegatingGatewayList)(x) +} + +func (x *UndelegatingGatewayList) slowProtoReflect() protoreflect.Message { + mi := &file_poktroll_application_application_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -var File_poktroll_application_application_proto protoreflect.FileDescriptor +var _fastReflection_UndelegatingGatewayList_messageType fastReflection_UndelegatingGatewayList_messageType +var _ protoreflect.MessageType = fastReflection_UndelegatingGatewayList_messageType{} -var file_poktroll_application_application_proto_rawDesc = []byte{ - 0x0a, 0x26, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x14, - 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, - 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa4, - 0x02, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x6b, 0x65, 0x12, 0x52, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, - 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x1b, 0x64, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x65, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x42, 0x1c, 0xc8, 0xde, - 0x1f, 0x00, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x19, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x42, 0xc4, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, - 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x42, 0x10, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, - 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, - 0x50, 0x41, 0x58, 0xaa, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x14, 0x50, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0xe2, 0x02, 0x20, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, - 0x3a, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, +type fastReflection_UndelegatingGatewayList_messageType struct{} + +func (x fastReflection_UndelegatingGatewayList_messageType) Zero() protoreflect.Message { + return (*fastReflection_UndelegatingGatewayList)(nil) +} +func (x fastReflection_UndelegatingGatewayList_messageType) New() protoreflect.Message { + return new(fastReflection_UndelegatingGatewayList) +} +func (x fastReflection_UndelegatingGatewayList_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_UndelegatingGatewayList } -var ( - file_poktroll_application_application_proto_rawDescOnce sync.Once - file_poktroll_application_application_proto_rawDescData = file_poktroll_application_application_proto_rawDesc -) +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_UndelegatingGatewayList) Descriptor() protoreflect.MessageDescriptor { + return md_UndelegatingGatewayList +} -func file_poktroll_application_application_proto_rawDescGZIP() []byte { - file_poktroll_application_application_proto_rawDescOnce.Do(func() { - file_poktroll_application_application_proto_rawDescData = protoimpl.X.CompressGZIP(file_poktroll_application_application_proto_rawDescData) - }) - return file_poktroll_application_application_proto_rawDescData +// 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_UndelegatingGatewayList) Type() protoreflect.MessageType { + return _fastReflection_UndelegatingGatewayList_messageType } -var file_poktroll_application_application_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_poktroll_application_application_proto_goTypes = []interface{}{ - (*Application)(nil), // 0: poktroll.application.Application - (*v1beta1.Coin)(nil), // 1: cosmos.base.v1beta1.Coin - (*shared.ApplicationServiceConfig)(nil), // 2: poktroll.shared.ApplicationServiceConfig +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_UndelegatingGatewayList) New() protoreflect.Message { + return new(fastReflection_UndelegatingGatewayList) } -var file_poktroll_application_application_proto_depIdxs = []int32{ - 1, // 0: poktroll.application.Application.stake:type_name -> cosmos.base.v1beta1.Coin - 2, // 1: poktroll.application.Application.service_configs:type_name -> poktroll.shared.ApplicationServiceConfig - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_UndelegatingGatewayList) Interface() protoreflect.ProtoMessage { + return (*UndelegatingGatewayList)(x) } -func init() { file_poktroll_application_application_proto_init() } -func file_poktroll_application_application_proto_init() { - if File_poktroll_application_application_proto != nil { - return +// 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_UndelegatingGatewayList) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if len(x.GatewayAddresses) != 0 { + value := protoreflect.ValueOfList(&_UndelegatingGatewayList_2_list{list: &x.GatewayAddresses}) + if !f(fd_UndelegatingGatewayList_gateway_addresses, value) { + return + } } - if !protoimpl.UnsafeEnabled { - file_poktroll_application_application_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Application); i { +} + +// 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_UndelegatingGatewayList) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + return len(x.GatewayAddresses) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + x.GatewayAddresses = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + if len(x.GatewayAddresses) == 0 { + return protoreflect.ValueOfList(&_UndelegatingGatewayList_2_list{}) + } + listValue := &_UndelegatingGatewayList_2_list{list: &x.GatewayAddresses} + return protoreflect.ValueOfList(listValue) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + lv := value.List() + clv := lv.(*_UndelegatingGatewayList_2_list) + x.GatewayAddresses = *clv.list + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + if x.GatewayAddresses == nil { + x.GatewayAddresses = []string{} + } + value := &_UndelegatingGatewayList_2_list{list: &x.GatewayAddresses} + return protoreflect.ValueOfList(value) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "poktroll.application.UndelegatingGatewayList.gateway_addresses": + list := []string{} + return protoreflect.ValueOfList(&_UndelegatingGatewayList_2_list{list: &list}) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.application.UndelegatingGatewayList")) + } + panic(fmt.Errorf("message poktroll.application.UndelegatingGatewayList 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_UndelegatingGatewayList) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in poktroll.application.UndelegatingGatewayList", 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_UndelegatingGatewayList) 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_UndelegatingGatewayList) 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_UndelegatingGatewayList) 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_UndelegatingGatewayList) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*UndelegatingGatewayList) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if len(x.GatewayAddresses) > 0 { + for _, s := range x.GatewayAddresses { + l = len(s) + 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().(*UndelegatingGatewayList) + 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.GatewayAddresses) > 0 { + for iNdEx := len(x.GatewayAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.GatewayAddresses[iNdEx]) + copy(dAtA[i:], x.GatewayAddresses[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.GatewayAddresses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + 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().(*UndelegatingGatewayList) + 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: UndelegatingGatewayList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: UndelegatingGatewayList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field GatewayAddresses", 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.GatewayAddresses = append(x.GatewayAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: poktroll/application/application.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Application defines the type used to store an on-chain definition and state for an application +type Application struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The Bech32 address of the application using cosmos' ScalarDescriptor to ensure deterministic encoding + Stake *v1beta1.Coin `protobuf:"bytes,2,opt,name=stake,proto3" json:"stake,omitempty"` // The total amount of uPOKT the application has staked + ServiceConfigs []*shared.ApplicationServiceConfig `protobuf:"bytes,3,rep,name=service_configs,json=serviceConfigs,proto3" json:"service_configs,omitempty"` // The list of services this appliccation is configured to request service for + // TODO_TECHDEBT: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. + // Ensure to rename all relevant configs, comments, variables, function names, etc as well. + DelegateeGatewayAddresses []string `protobuf:"bytes,4,rep,name=delegatee_gateway_addresses,json=delegateeGatewayAddresses,proto3" json:"delegatee_gateway_addresses,omitempty"` // The Bech32 encoded addresses for all delegatee Gateways, in a non-nullable slice + // A map from sessionEndHeights to a list of Gateways. + // The key is the height of the last block of the session during which the + // respective undelegation was committed. + // The value is a list of gateways being undelegated from. + // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment + // so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. + PendingUndelegations map[uint64]*UndelegatingGatewayList `protobuf:"bytes,5,rep,name=pending_undelegations,json=pendingUndelegations,proto3" json:"pending_undelegations,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Application) Reset() { + *x = Application{} + if protoimpl.UnsafeEnabled { + mi := &file_poktroll_application_application_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Application) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Application) ProtoMessage() {} + +// Deprecated: Use Application.ProtoReflect.Descriptor instead. +func (*Application) Descriptor() ([]byte, []int) { + return file_poktroll_application_application_proto_rawDescGZIP(), []int{0} +} + +func (x *Application) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *Application) GetStake() *v1beta1.Coin { + if x != nil { + return x.Stake + } + return nil +} + +func (x *Application) GetServiceConfigs() []*shared.ApplicationServiceConfig { + if x != nil { + return x.ServiceConfigs + } + return nil +} + +func (x *Application) GetDelegateeGatewayAddresses() []string { + if x != nil { + return x.DelegateeGatewayAddresses + } + return nil +} + +func (x *Application) GetPendingUndelegations() map[uint64]*UndelegatingGatewayList { + if x != nil { + return x.PendingUndelegations + } + return nil +} + +// UndelegatingGatewayList is used as the Value of `pending_undelegations`. +// It is required to store a repeated list of strings as a map value. +type UndelegatingGatewayList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GatewayAddresses []string `protobuf:"bytes,2,rep,name=gateway_addresses,json=gatewayAddresses,proto3" json:"gateway_addresses,omitempty"` +} + +func (x *UndelegatingGatewayList) Reset() { + *x = UndelegatingGatewayList{} + if protoimpl.UnsafeEnabled { + mi := &file_poktroll_application_application_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UndelegatingGatewayList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UndelegatingGatewayList) ProtoMessage() {} + +// Deprecated: Use UndelegatingGatewayList.ProtoReflect.Descriptor instead. +func (*UndelegatingGatewayList) Descriptor() ([]byte, []int) { + return file_poktroll_application_application_proto_rawDescGZIP(), []int{1} +} + +func (x *UndelegatingGatewayList) GetGatewayAddresses() []string { + if x != nil { + return x.GatewayAddresses + } + return nil +} + +var File_poktroll_application_application_proto protoreflect.FileDescriptor + +var file_poktroll_application_application_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x14, + 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, + 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1d, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, + 0x04, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x6b, 0x65, 0x12, 0x52, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x1b, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x65, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x42, 0x1c, 0xc8, 0xde, + 0x1f, 0x00, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x19, 0x64, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x76, 0x0a, 0x15, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, + 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x76, 0x0a, + 0x19, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x43, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x64, 0x0a, 0x17, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x49, 0x0a, 0x11, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x1c, 0xc8, 0xde, 0x1f, + 0x00, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x42, 0xc4, 0x01, 0x0a, 0x18, + 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x10, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, + 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x50, 0x41, 0x58, 0xaa, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0xca, 0x02, 0x14, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x20, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x5c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, 0x50, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_poktroll_application_application_proto_rawDescOnce sync.Once + file_poktroll_application_application_proto_rawDescData = file_poktroll_application_application_proto_rawDesc +) + +func file_poktroll_application_application_proto_rawDescGZIP() []byte { + file_poktroll_application_application_proto_rawDescOnce.Do(func() { + file_poktroll_application_application_proto_rawDescData = protoimpl.X.CompressGZIP(file_poktroll_application_application_proto_rawDescData) + }) + return file_poktroll_application_application_proto_rawDescData +} + +var file_poktroll_application_application_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_poktroll_application_application_proto_goTypes = []interface{}{ + (*Application)(nil), // 0: poktroll.application.Application + (*UndelegatingGatewayList)(nil), // 1: poktroll.application.UndelegatingGatewayList + nil, // 2: poktroll.application.Application.PendingUndelegationsEntry + (*v1beta1.Coin)(nil), // 3: cosmos.base.v1beta1.Coin + (*shared.ApplicationServiceConfig)(nil), // 4: poktroll.shared.ApplicationServiceConfig +} +var file_poktroll_application_application_proto_depIdxs = []int32{ + 3, // 0: poktroll.application.Application.stake:type_name -> cosmos.base.v1beta1.Coin + 4, // 1: poktroll.application.Application.service_configs:type_name -> poktroll.shared.ApplicationServiceConfig + 2, // 2: poktroll.application.Application.pending_undelegations:type_name -> poktroll.application.Application.PendingUndelegationsEntry + 1, // 3: poktroll.application.Application.PendingUndelegationsEntry.value:type_name -> poktroll.application.UndelegatingGatewayList + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_poktroll_application_application_proto_init() } +func file_poktroll_application_application_proto_init() { + if File_poktroll_application_application_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_poktroll_application_application_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Application); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_poktroll_application_application_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UndelegatingGatewayList); i { case 0: return &v.state case 1: @@ -951,7 +1834,7 @@ func file_poktroll_application_application_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poktroll_application_application_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/appgateserver/config/appgate_configs_reader.go b/pkg/appgateserver/config/appgate_configs_reader.go index d0b42cd67..8ee4a2301 100644 --- a/pkg/appgateserver/config/appgate_configs_reader.go +++ b/pkg/appgateserver/config/appgate_configs_reader.go @@ -7,7 +7,8 @@ import ( ) // YAMLAppGateServerConfig is the structure used to unmarshal the AppGateServer config file -// TODO_DOCUMENT(@red-0ne): Add proper README documentation for yaml config files. +// TODO_TECHDEBT: Rename self_signing parameter to `sovereign` in code, configs +// and documentation type YAMLAppGateServerConfig struct { ListeningEndpoint string `yaml:"listening_endpoint"` Metrics YAMLAppGateServerMetricsConfig `yaml:"metrics"` diff --git a/pkg/client/delegation/redelegation.go b/pkg/client/delegation/redelegation.go index 18772a86a..f907afa9a 100644 --- a/pkg/client/delegation/redelegation.go +++ b/pkg/client/delegation/redelegation.go @@ -14,7 +14,7 @@ import ( // redelegationEventType is the type of the EventRedelegation event emitted by // both the MsgDelegateToGateway and MsgUndelegateFromGateway messages. -const redelegationEventType = "pocket.application.EventRedelegation" +const redelegationEventType = "poktroll.application.EventRedelegation" var _ client.Redelegation = (*redelegation)(nil) @@ -69,8 +69,6 @@ func newRedelegationEventFactoryFn() events.NewEventsFn[client.Redelegation] { return nil, events.ErrEventsUnmarshalEvent.Wrapf("cannot retrieve gateway address: %v", err) } redelegationEvent.GatewayAddress = gatewayAddr - default: - return nil, events.ErrEventsUnmarshalEvent.Wrapf("unknown attribute key: %s", attr.Key) } } // Handle the redelegation event diff --git a/pkg/client/query/accquerier.go b/pkg/client/query/accquerier.go index 7e84bdbde..27fcbd7e6 100644 --- a/pkg/client/query/accquerier.go +++ b/pkg/client/query/accquerier.go @@ -67,6 +67,15 @@ func (aq *accQuerier) GetAccount( if err = queryCodec.UnpackAny(res.Account, &fetchedAccount); err != nil { return nil, ErrQueryUnableToDeserializeAccount.Wrapf("address: %s [%v]", address, err) } + + // Fetched accounts must have their public key set. Do not cache accounts + // that do not have a public key set, such as the ones resulting from genesis + // as they may continue failing due to the caching mechanism, even after they + // got their public key recorded on-chain. + if fetchedAccount.GetPubKey() == nil { + return nil, ErrQueryPubKeyNotFound + } + aq.accountCache[address] = fetchedAccount return fetchedAccount, nil diff --git a/pkg/crypto/interface.go b/pkg/crypto/interface.go index a2e35931d..083b950ca 100644 --- a/pkg/crypto/interface.go +++ b/pkg/crypto/interface.go @@ -33,9 +33,13 @@ type RingCache interface { // the addresses of the gateways the application delegated to, and converting // them into their corresponding public key points on the secp256k1 curve. type RingClient interface { - // GetRingForAddress returns the ring for the given application address if - // it exists. - GetRingForAddress(ctx context.Context, appAddress string) (*ring.Ring, error) + // GetRingForAddressAtHeight returns the ring for the given application address + // and blockHeight if it exists. + GetRingForAddressAtHeight( + ctx context.Context, + appAddress string, + blockHeight int64, + ) (*ring.Ring, error) // VerifyRelayRequestSignature verifies the relay request signature against // the ring for the application address in the relay request. diff --git a/pkg/crypto/pubkey_client/client.go b/pkg/crypto/pubkey_client/client.go deleted file mode 100644 index 042bed580..000000000 --- a/pkg/crypto/pubkey_client/client.go +++ /dev/null @@ -1,59 +0,0 @@ -package pubkeyclient - -import ( - "context" - - "cosmossdk.io/depinject" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - - "github.com/pokt-network/poktroll/pkg/client" - "github.com/pokt-network/poktroll/pkg/crypto" -) - -var _ crypto.PubKeyClient = (*pubKeyClient)(nil) - -// pubKeyClient is an implementation of the PubKeyClient that uses an account -// querier to get the public key of an address. -type pubKeyClient struct { - // accountQuerier is the querier for the account module, it is used to get - // the public key corresponding to an address. - accountQuerier client.AccountQueryClient -} - -// NewPubKeyClient creates a new PubKeyClient with the given dependencies. -// The querier is injected using depinject and has to be specific to the -// environment in which the pubKeyClient is initialized as on-chain and off-chain -// environments may have different queriers. -// -// Required dependencies: -// - client.AccountQueryClient -func NewPubKeyClient(deps depinject.Config) (crypto.PubKeyClient, error) { - pc := new(pubKeyClient) - - if err := depinject.Inject( - deps, - &pc.accountQuerier, - ); err != nil { - return nil, err - } - - return pc, nil -} - -// GetPubKeyFromAddress returns the public key of the given address. -// It retrieves the corresponding account by querying for it and returns -// the associated public key. -func (pc *pubKeyClient) GetPubKeyFromAddress(ctx context.Context, address string) (cryptotypes.PubKey, error) { - acc, err := pc.accountQuerier.GetAccount(ctx, address) - if err != nil { - return nil, err - } - - // If the account's public key is nil, then return an error. - pubKey := acc.GetPubKey() - if pubKey == nil { - return nil, ErrPubKeyClientEmptyPubKey - } - - return pubKey, nil -} diff --git a/pkg/crypto/pubkey_client/errors.go b/pkg/crypto/pubkey_client/errors.go deleted file mode 100644 index d59d7f0a5..000000000 --- a/pkg/crypto/pubkey_client/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package pubkeyclient - -import sdkerrors "cosmossdk.io/errors" - -var ( - codespace = "pubkeyclient" - ErrPubKeyClientEmptyPubKey = sdkerrors.Register(codespace, 1, "empty public key") -) diff --git a/pkg/crypto/rings/cache.go b/pkg/crypto/rings/cache.go index 4817832d4..cbc966f2e 100644 --- a/pkg/crypto/rings/cache.go +++ b/pkg/crypto/rings/cache.go @@ -70,10 +70,8 @@ func (rc *ringCache) Start(ctx context.Context) { rc.logger.Info().Msg("starting ring cache") // Stop the ringCache when the context is cancelled. go func() { - select { - case <-ctx.Done(): - rc.Stop() - } + <-ctx.Done() + rc.Stop() }() // Listen for redelegation events and invalidate the cache if it contains an // address corresponding to the redelegation event's. @@ -130,13 +128,14 @@ func (rc *ringCache) GetCachedAddresses() []string { return appAddresses } -// GetRingForAddress returns the ring for the address provided. If it does not -// exist in the cache, it will be created by querying the application module. -// and converting the addresses into their corresponding public key points on +// GetRingForAddressAtHeight returns the ring for the address and block height provided. +// If it does not exist in the cache, it will be created by querying the application +// module and converting the addresses into their corresponding public key points on // the secp256k1 curve. It will then be cached for future use. -func (rc *ringCache) GetRingForAddress( +func (rc *ringCache) GetRingForAddressAtHeight( ctx context.Context, appAddress string, + blockHeight int64, ) (ring *ring.Ring, err error) { rc.ringsByAddrMu.Lock() defer rc.ringsByAddrMu.Unlock() @@ -158,7 +157,7 @@ func (rc *ringCache) GetRingForAddress( Str("app_address", appAddress). Msg("ring cache miss; fetching from application module") - ring, err = rc.ringClient.GetRingForAddress(ctx, appAddress) + ring, err = rc.ringClient.GetRingForAddressAtHeight(ctx, appAddress, blockHeight) if err != nil { return nil, err } diff --git a/pkg/crypto/rings/cache_test.go b/pkg/crypto/rings/cache_test.go index 8505fa3dd..258f90ebd 100644 --- a/pkg/crypto/rings/cache_test.go +++ b/pkg/crypto/rings/cache_test.go @@ -20,7 +20,10 @@ import ( apptypes "github.com/pokt-network/poktroll/x/application/types" ) -const noDelegateesRingSize = 2 +const ( + noDelegateesRingSize = 2 + defaultHeight = 1 +) // account is an internal struct used to define an (address, public_key) pairing type account struct { @@ -113,7 +116,7 @@ func TestRingCache_BuildRing_Uncached(t *testing.T) { testqueryclients.AddAddressToApplicationMap(t, test.appAccount.address, test.appAccount.pubKey, accMap) } // Attempt to retrieve the ring for the address - ring, err := rc.GetRingForAddress(ctx, test.appAccount.address) + ring, err := rc.GetRingForAddressAtHeight(ctx, test.appAccount.address, defaultHeight) if test.expectedErr != nil { require.ErrorAs(t, err, &test.expectedErr) return @@ -164,7 +167,7 @@ func TestRingCache_BuildRing_Cached(t *testing.T) { testqueryclients.AddAddressToApplicationMap(t, test.appAccount.address, test.appAccount.pubKey, nil) // Attempt to retrieve the ring for the address and cache it - ring1, err := rc.GetRingForAddress(ctx, test.appAccount.address) + ring1, err := rc.GetRingForAddressAtHeight(ctx, test.appAccount.address, defaultHeight) require.NoError(t, err) require.Equal(t, noDelegateesRingSize, ring1.Size()) require.Equal(t, 1, len(rc.GetCachedAddresses())) @@ -195,7 +198,7 @@ func TestRingCache_BuildRing_Cached(t *testing.T) { // Attempt to retrieve the ring for the address and cache it if // the ring was updated - ring2, err := rc.GetRingForAddress(ctx, test.appAccount.address) + ring2, err := rc.GetRingForAddressAtHeight(ctx, test.appAccount.address, defaultHeight) require.NoError(t, err) // If the ring was updated then the rings should not be equal if test.expectedRingSize != noDelegateesRingSize { @@ -207,7 +210,7 @@ func TestRingCache_BuildRing_Cached(t *testing.T) { require.Equal(t, 1, len(rc.GetCachedAddresses())) // Attempt to retrieve the ring for the address after its been cached - ring3, err := rc.GetRingForAddress(ctx, test.appAccount.address) + ring3, err := rc.GetRingForAddressAtHeight(ctx, test.appAccount.address, defaultHeight) require.NoError(t, err) require.Equal(t, 1, len(rc.GetCachedAddresses())) @@ -237,13 +240,13 @@ func TestRingCache_Stop(t *testing.T) { }) // Attempt to retrieve the ring for the address and cache it - ring1, err := rc.GetRingForAddress(ctx, appAccount.address) + ring1, err := rc.GetRingForAddressAtHeight(ctx, appAccount.address, defaultHeight) require.NoError(t, err) require.Equal(t, 2, ring1.Size()) require.Equal(t, 1, len(rc.GetCachedAddresses())) // Retrieve the cached ring - ring2, err := rc.GetRingForAddress(ctx, appAccount.address) + ring2, err := rc.GetRingForAddressAtHeight(ctx, appAccount.address, defaultHeight) require.NoError(t, err) require.True(t, ring1.Equals(ring2)) require.Equal(t, 1, len(rc.GetCachedAddresses())) @@ -272,13 +275,13 @@ func TestRingCache_CancelContext(t *testing.T) { }) // Attempt to retrieve the ring for the address and cache it - ring1, err := rc.GetRingForAddress(ctx, appAccount.address) + ring1, err := rc.GetRingForAddressAtHeight(ctx, appAccount.address, defaultHeight) require.NoError(t, err) require.Equal(t, 2, ring1.Size()) require.Equal(t, 1, len(rc.GetCachedAddresses())) // Retrieve the cached ring - ring2, err := rc.GetRingForAddress(ctx, appAccount.address) + ring2, err := rc.GetRingForAddressAtHeight(ctx, appAccount.address, defaultHeight) require.NoError(t, err) require.True(t, ring1.Equals(ring2)) require.Equal(t, 1, len(rc.GetCachedAddresses())) diff --git a/pkg/crypto/rings/client.go b/pkg/crypto/rings/client.go index fd1106327..0850d7189 100644 --- a/pkg/crypto/rings/client.go +++ b/pkg/crypto/rings/client.go @@ -3,6 +3,7 @@ package rings import ( "context" "fmt" + "slices" "cosmossdk.io/depinject" ring_secp256k1 "github.com/athanorlabs/go-dleq/secp256k1" @@ -12,7 +13,9 @@ import ( "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/crypto" "github.com/pokt-network/poktroll/pkg/polylog" + apptypes "github.com/pokt-network/poktroll/x/application/types" "github.com/pokt-network/poktroll/x/service/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" ) var _ crypto.RingClient = (*ringClient)(nil) @@ -53,21 +56,29 @@ func NewRingClient(deps depinject.Config) (_ crypto.RingClient, err error) { return rc, nil } -// GetRingForAddress returns the ring for the address provided. +// GetRingForAddressAtHeight returns the ring for the address and block height provided. +// The height provided is used to determine the appropriate delegated gateways +// to use at that height since signature verification may be performed for +// delegations that are no longer active. +// The height provided will be rounded up to the session end height to ensure +// the ring is constructed from the correct past delegations since they become +// effective at the next session's start height. +// TODO(@red-0ne): Link to the docs once they are available. // The ring is created by querying for the application's and its delegated // gateways public keys. These keys are converted to secp256k1 curve points // before forming the ring. -func (rc *ringClient) GetRingForAddress( +func (rc *ringClient) GetRingForAddressAtHeight( ctx context.Context, appAddress string, + blockHeight int64, ) (*ring.Ring, error) { - pubKeys, err := rc.getDelegatedPubKeysForAddress(ctx, appAddress) + ringPubKeys, err := rc.getRingPubKeysForAddress(ctx, appAddress, blockHeight) if err != nil { return nil, err } // Get the points on the secp256k1 curve for the public keys in the ring. - points, err := pointsFromPublicKeys(pubKeys...) + points, err := pointsFromPublicKeys(ringPubKeys...) if err != nil { return nil, err } @@ -113,8 +124,9 @@ func (rc *ringClient) VerifyRelayRequestSignature( } // Get the ring for the application address of the relay request. + sessionEndHeight := sessionHeader.GetSessionEndBlockHeight() appAddress := sessionHeader.GetApplicationAddress() - expectedAppRing, err := rc.GetRingForAddress(ctx, appAddress) + expectedAppRing, err := rc.GetRingForAddressAtHeight(ctx, appAddress, sessionEndHeight) if err != nil { return ErrRingClientInvalidRelayRequest.Wrapf( "error getting ring for application address %s: %v", appAddress, err, @@ -142,11 +154,14 @@ func (rc *ringClient) VerifyRelayRequestSignature( return nil } -// getDelegatedPubKeysForAddress returns the gateway public keys an application -// delegated the ability to sign relay requests on its behalf. -func (rc *ringClient) getDelegatedPubKeysForAddress( +// getRingPubKeysForAddress returns the public keys corresponding to a ring. +// It returns a slice consisting of the application's public key and the public +// keys of the gateways to which the application delegated the authority to sign +// relay requests on its behalf at the given block height. +func (rc *ringClient) getRingPubKeysForAddress( ctx context.Context, appAddress string, + blockHeight int64, ) ([]cryptotypes.PubKey, error) { // Get the application's on chain state. app, err := rc.applicationQuerier.GetApplication(ctx, appAddress) @@ -154,22 +169,29 @@ func (rc *ringClient) getDelegatedPubKeysForAddress( return nil, err } + // Reconstruct the delegatee gateway addresses at the given block height and + // add them to the ring addresses. + delegateeGatewayAddresses := GetRingAddressesAtBlock(&app, blockHeight) + // Create a slice of addresses for the ring. ringAddresses := make([]string, 0) ringAddresses = append(ringAddresses, appAddress) // app address is index 0 - if len(app.DelegateeGatewayAddresses) == 0 { - // add app address twice to make the ring size of minimum 2 - // TODO_IMPROVE: The appAddress is added twice because a ring signature - // requires AT LEAST two pubKeys. If the Application has not delegated - // to any gateways, the app's own address needs to be used twice to - // create a ring. This is not a huge issue but an improvement should - // be investigated in the future. - ringAddresses = append(ringAddresses, appAddress) - } else { - // add the delegatee gateway addresses - ringAddresses = append(ringAddresses, app.DelegateeGatewayAddresses...) + + // TODO_IMPROVE: The appAddress is added twice because a ring signature + // requires AT LEAST two pubKeys. If the Application has not delegated + // to any gateways, the app's own address needs to be used twice to + // create a ring. This is not a huge issue but an improvement should + // be investigated in the future. + if len(delegateeGatewayAddresses) == 0 { + delegateeGatewayAddresses = append(delegateeGatewayAddresses, app.Address) } + ringAddresses = append(ringAddresses, delegateeGatewayAddresses...) + + // Sort the ring addresses to ensure the ring is consistent between signing and + // verification by satisfying relayRequestRingSig.Ring().Equals(expectedAppRing) + slices.Sort(ringAddresses) + rc.logger.Debug(). // TODO_TECHDEBT: implement and use `polylog.Event#Strs([]string)` Str("addresses", fmt.Sprintf("%v", ringAddresses)). @@ -194,3 +216,45 @@ func (rc *ringClient) addressesToPubKeys( } return pubKeys, nil } + +// GetRingAddressesAtBlock returns the active gateway addresses that need to be +// used to construct the ring in order to validate that the given app should pay for. +// It takes into account both active delegations and pending undelegations that +// should still be part of the ring at the given block height. +// The ring addresses slice is reconstructed by adding back the past delegated +// gateways that have been undelegated after the target session end height. +func GetRingAddressesAtBlock(app *apptypes.Application, blockHeight int64) []string { + // Get the target session end height at which we want to get the active delegations. + targetSessionEndHeight := uint64(sessionkeeper.GetSessionEndBlockHeight(blockHeight)) + // Get the current active delegations for the application and use them as a base. + activeDelegationsAtHeight := app.DelegateeGatewayAddresses + + // Use a map to keep track of the gateways addresses that have been added to + // the active delegations slice to avoid duplicates. + addedDelegations := make(map[string]struct{}) + + // Iterate over the pending undelegations recorded at their respective block + // height and check whether to add them back as active delegations. + for pendingUndelegationHeight, undelegatedGateways := range app.PendingUndelegations { + // If the pending undelegation happened BEFORE the target session end height, skip it. + // The gateway is pending undelegation and simply has not been pruned yet. + // It will be pruned in the near future. + if pendingUndelegationHeight < targetSessionEndHeight { + continue + } + // Add back any gateway address that was undelegated after the target session + // end height, as we consider it not happening yet relative to the target height. + for _, gatewayAddress := range undelegatedGateways.GatewayAddresses { + if _, ok := addedDelegations[gatewayAddress]; ok { + continue + } + + activeDelegationsAtHeight = append(activeDelegationsAtHeight, gatewayAddress) + // Mark the gateway address as added to avoid duplicates. + addedDelegations[gatewayAddress] = struct{}{} + } + + } + + return activeDelegationsAtHeight +} diff --git a/pkg/relayer/interface.go b/pkg/relayer/interface.go index ba426f9e8..b513e0cea 100644 --- a/pkg/relayer/interface.go +++ b/pkg/relayer/interface.go @@ -130,6 +130,9 @@ type SessionTree interface { // This function should be called several blocks after a session has been claimed and needs to be proven. ProveClosest(path []byte) (proof *smt.SparseMerkleClosestProof, err error) + // GetProof returns the proof for the SMST if it has been generated or nil otherwise. + GetProof() *smt.SparseMerkleClosestProof + // Flush gets the root hash of the SMST needed for submitting the claim; // then commits the entire tree to disk and stops the KVStore. // It should be called before submitting the claim on-chain. This function frees up diff --git a/pkg/relayer/proxy/relay_verifier.go b/pkg/relayer/proxy/relay_verifier.go index 5aeff8589..011b1b293 100644 --- a/pkg/relayer/proxy/relay_verifier.go +++ b/pkg/relayer/proxy/relay_verifier.go @@ -15,6 +15,14 @@ func (rp *relayerProxy) VerifyRelayRequest( relayRequest *types.RelayRequest, supplierService *sharedtypes.Service, ) error { + // Get the block height at which the relayRequest should be processed. + // Check if the relayRequest is on time or within the session's grace period + // before attempting to verify the relayRequest signature. + sessionBlockHeight, err := rp.getTargetSessionBlockHeight(ctx, relayRequest) + if err != nil { + return err + } + // Verify the relayRequest metadata, signature, session header and other // basic validation. if err := rp.ringCache.VerifyRelayRequestSignature(ctx, relayRequest); err != nil { @@ -38,12 +46,6 @@ func (rp *relayerProxy) VerifyRelayRequest( }). Msg("verifying relay request session") - // Get the block height at which the relayRequest should be processed. - sessionBlockHeight, err := rp.getTargetSessionBlockHeight(ctx, relayRequest) - if err != nil { - return err - } - // Query for the current session to check if relayRequest sessionId matches the current session. session, err := rp.sessionQuerier.GetSession( ctx, diff --git a/pkg/relayer/session/proof.go b/pkg/relayer/session/proof.go index 3bc14bc49..e8304459c 100644 --- a/pkg/relayer/session/proof.go +++ b/pkg/relayer/session/proof.go @@ -24,15 +24,16 @@ func (rs *relayerSessionsManager) submitProofs( ctx context.Context, claimedSessionsObs observable.Observable[relayer.SessionTree], ) { + failedSubmitProofSessionsObs, failedSubmitProofSessionsPublishCh := + channel.NewObservable[relayer.SessionTree]() + // Map claimedSessionsObs to a new observable of the same type which is notified // when the session is eligible to be proven. sessionsWithOpenProofWindowObs := channel.Map( ctx, claimedSessionsObs, - rs.mapWaitForEarliestSubmitProofHeight, + rs.mapWaitForEarliestSubmitProofHeight(failedSubmitProofSessionsPublishCh), ) - failedSubmitProofSessionsObs, failedSubmitProofSessionsPublishCh := channel.NewObservable[relayer.SessionTree]() - // Map sessionsWithOpenProofWindow to a new observable of an either type, // populated with the session or an error, which is notified after the session // proof has been submitted or an error has been encountered, respectively. @@ -51,27 +52,37 @@ func (rs *relayerSessionsManager) submitProofs( // at which a proof can be submitted for the given session, then emits the session // **at that moment**. func (rs *relayerSessionsManager) mapWaitForEarliestSubmitProofHeight( - ctx context.Context, - session relayer.SessionTree, -) (_ relayer.SessionTree, skip bool) { - rs.waitForEarliestSubmitProofHeight( - ctx, session.GetSessionHeader().GetSessionEndBlockHeight(), - ) - return session, false + failedSubmitProofSessionsCh chan<- relayer.SessionTree, +) channel.MapFn[relayer.SessionTree, relayer.SessionTree] { + return func( + ctx context.Context, + session relayer.SessionTree, + ) (_ relayer.SessionTree, skip bool) { + if err := rs.waitForEarliestSubmitProofHeightAndGenerateProof(ctx, session); err != nil { + failedSubmitProofSessionsCh <- session + return nil, true + } + + return session, false + } } -// waitForEarliestSubmitProofHeight calculates and waits for (blocking until) the -// earliest block height, allowed by the protocol, at which a proof can be submitted -// for a session which was claimed at createClaimHeight. It is calculated relative -// to createClaimHeight using on-chain governance parameters and randomized input. +// waitForEarliestSubmitProofHeightAndGenerateProof calculates and waits for +// (blocking until) the earliest block height, allowed by the protocol, at which +// a proof can be submitted for a session which was claimed at createClaimHeight. +// It also generates the proof for the session once the height is reached and +// its hash is available for proof path generation. +// It is calculated relative to createClaimHeight using on-chain governance +// parameters and randomized input. // It IS A BLOCKING function. -func (rs *relayerSessionsManager) waitForEarliestSubmitProofHeight( +func (rs *relayerSessionsManager) waitForEarliestSubmitProofHeightAndGenerateProof( ctx context.Context, - createClaimHeight int64, -) { + session relayer.SessionTree, +) error { // TODO_TECHDEBT(@red-0ne): Centralize the business logic that involves taking // into account the heights, windows and grace periods into helper functions. - submitProofWindowStartHeight := createClaimHeight + sessionkeeper.GetSessionGracePeriodBlockCount() + submitProofWindowStartHeight := session.GetSessionHeader().GetSessionEndBlockHeight() + + sessionkeeper.GetSessionGracePeriodBlockCount() // TODO_BLOCKER: query the on-chain governance parameter once available. // + claimproofparams.GovSubmitProofWindowStartHeightOffset @@ -81,8 +92,19 @@ func (rs *relayerSessionsManager) waitForEarliestSubmitProofHeight( Msg("waiting & blocking for global earliest proof submission height") submitProofWindowStartBlock := rs.waitForBlock(ctx, submitProofWindowStartHeight) + // Use the submitProofWindowStartBlock hash to generate the proof. + path := proofkeeper.GetPathForProof( + submitProofWindowStartBlock.Hash(), + session.GetSessionHeader().GetSessionId(), + ) + if _, err := session.ProveClosest(path); err != nil { + return err + } + earliestSubmitProofHeight := protocol.GetEarliestSubmitProofHeight(ctx, submitProofWindowStartBlock) _ = rs.waitForBlock(ctx, earliestSubmitProofHeight) + + return nil } // newMapProveSessionFn returns a new MapFn that submits a proof for the given @@ -95,36 +117,16 @@ func (rs *relayerSessionsManager) newMapProveSessionFn( ctx context.Context, session relayer.SessionTree, ) (_ either.SessionTree, skip bool) { - rs.pendingTxMu.Lock() - defer rs.pendingTxMu.Unlock() - - // TODO_BLOCKER(@bryanchriswhite): The block that'll be used as a source of entropy for - // which branch(es) to prove should be deterministic and use on-chain governance params. - pathBlockHeight := session.GetSessionHeader().GetSessionEndBlockHeight() + - sessionkeeper.GetSessionGracePeriodBlockCount() - pathBlock, err := rs.blockQueryClient.Block(ctx, &pathBlockHeight) - if err != nil { - return either.Error[relayer.SessionTree](err), false - } - - path := proofkeeper.GetPathForProof( - pathBlock.BlockID.Hash, - session.GetSessionHeader().GetSessionId(), - ) - proof, err := session.ProveClosest(path) - if err != nil { - return either.Error[relayer.SessionTree](err), false - } - + currentHeight := rs.blockClient.LastBlock(ctx).Height() rs.logger.Info(). - Int64("session_end_height_with_grace_period", pathBlock.Block.Height). + Int64("currentBlockHeight", currentHeight). Msg("submitting proof") // SubmitProof ensures on-chain proof inclusion so we can safely prune the tree. if err := rs.supplierClient.SubmitProof( ctx, *session.GetSessionHeader(), - proof, + session.GetProof(), ); err != nil { failedSubmitProofSessionsCh <- session return either.Error[relayer.SessionTree](err), false diff --git a/pkg/relayer/session/sessiontree.go b/pkg/relayer/session/sessiontree.go index 22d7d8457..e65efdb53 100644 --- a/pkg/relayer/session/sessiontree.go +++ b/pkg/relayer/session/sessiontree.go @@ -158,6 +158,11 @@ func (st *sessionTree) ProveClosest(path []byte) (proof *smt.SparseMerkleClosest return st.proof, err } +// GetProof returns the proof for the SMST if it has been generated or nil otherwise. +func (st *sessionTree) GetProof() *smt.SparseMerkleClosestProof { + return st.proof +} + // Flush gets the root hash of the SMST needed for submitting the claim; // then commits the entire tree to disk and stops the KVStore. // It should be called before submitting the claim on-chain. This function frees up the KVStore resources. diff --git a/pkg/sdk/send_relay.go b/pkg/sdk/send_relay.go index a00c8ebc2..99d853634 100644 --- a/pkg/sdk/send_relay.go +++ b/pkg/sdk/send_relay.go @@ -42,7 +42,8 @@ func (sdk *poktrollSDK) SendRelay( // Get the application's signer. appAddress := supplierEndpoint.Header.ApplicationAddress - appRing, err := sdk.ringCache.GetRingForAddress(ctx, appAddress) + sessionEndHeight := supplierEndpoint.Header.SessionEndBlockHeight + appRing, err := sdk.ringCache.GetRingForAddressAtHeight(ctx, appAddress, sessionEndHeight) if err != nil { return nil, ErrSDKHandleRelay.Wrapf("getting app ring: %s", err) } diff --git a/proto/poktroll/application/application.proto b/proto/poktroll/application/application.proto index b9a7d0a18..b302b21bd 100644 --- a/proto/poktroll/application/application.proto +++ b/proto/poktroll/application/application.proto @@ -14,5 +14,20 @@ message Application { string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The Bech32 address of the application using cosmos' ScalarDescriptor to ensure deterministic encoding cosmos.base.v1beta1.Coin stake = 2; // The total amount of uPOKT the application has staked repeated poktroll.shared.ApplicationServiceConfig service_configs = 3; // The list of services this appliccation is configured to request service for + // TODO_TECHDEBT: Rename `delegatee_gateway_addresses` to `gateway_addresses_delegated_to`. + // Ensure to rename all relevant configs, comments, variables, function names, etc as well. repeated string delegatee_gateway_addresses = 4 [(cosmos_proto.scalar) = "cosmos.AddressString", (gogoproto.nullable) = false]; // The Bech32 encoded addresses for all delegatee Gateways, in a non-nullable slice + // A map from sessionEndHeights to a list of Gateways. + // The key is the height of the last block of the session during which the + // respective undelegation was committed. + // The value is a list of gateways being undelegated from. + // TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment + // so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. + map pending_undelegations = 5 [(gogoproto.nullable) = false]; } + +// UndelegatingGatewayList is used as the Value of `pending_undelegations`. +// It is required to store a repeated list of strings as a map value. +message UndelegatingGatewayList { + repeated string gateway_addresses = 2 [(cosmos_proto.scalar) = "cosmos.AddressString", (gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/testutil/network/network.go b/testutil/network/network.go index c2c1f13b9..ed8076e1d 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -121,6 +121,7 @@ func DefaultApplicationModuleGenesisState(t *testing.T, n int) *apptypes.Genesis Service: &sharedtypes.Service{Id: fmt.Sprintf("svc%d%d", i, i)}, }, }, + PendingUndelegations: map[uint64]apptypes.UndelegatingGatewayList{}, } // TODO_CONSIDERATION: Evaluate whether we need `nullify.Fill` or if we should enforce `(gogoproto.nullable) = false` everywhere // nullify.Fill(&application) diff --git a/testutil/testclient/testdelegation/client.go b/testutil/testclient/testdelegation/client.go index c019ae0d3..59f8f8a27 100644 --- a/testutil/testclient/testdelegation/client.go +++ b/testutil/testclient/testdelegation/client.go @@ -151,7 +151,7 @@ func NewRedelegationEventBytes( gatewayAddress string, ) []byte { t.Helper() - jsonTemplate := `{"tx":"SGVsbG8sIHdvcmxkIQ==","result":{"events":[{"type":"message","attributes":[{"key":"action","value":"/pocket.application.MsgDelegateToGateway"},{"key":"sender","value":"pokt1exampleaddress"},{"key":"module","value":"application"}]},{"type":"pocket.application.EventRedelegation","attributes":[{"key":"app_address","value":"\"%s\""},{"key":"gateway_address","value":"\"%s\""}]}]}}` + jsonTemplate := `{"tx":"SGVsbG8sIHdvcmxkIQ==","result":{"events":[{"type":"message","attributes":[{"key":"action","value":"/poktroll.application.MsgDelegateToGateway"},{"key":"sender","value":"pokt1exampleaddress"},{"key":"module","value":"application"}]},{"type":"poktroll.application.EventRedelegation","attributes":[{"key":"app_address","value":"\"%s\""},{"key":"gateway_address","value":"\"%s\""}]}]}}` txResultEvent := &tx.CometTxEvent{} diff --git a/x/application/keeper/application.go b/x/application/keeper/application.go index 032d74128..e48068f3e 100644 --- a/x/application/keeper/application.go +++ b/x/application/keeper/application.go @@ -32,6 +32,13 @@ func (k Keeper) GetApplication( } k.cdc.MustUnmarshal(appBz, &app) + + // Ensure that the PendingUndelegations is an empty map and not nil when + // unmarshalling an app that has no pending undelegations. + if app.PendingUndelegations == nil { + app.PendingUndelegations = make(map[uint64]types.UndelegatingGatewayList) + } + return app, true } @@ -53,6 +60,13 @@ func (k Keeper) GetAllApplications(ctx context.Context) (apps []types.Applicatio for ; iterator.Valid(); iterator.Next() { var app types.Application k.cdc.MustUnmarshal(iterator.Value(), &app) + + // Ensure that the PendingUndelegations is an empty map and not nil when + // unmarshalling an app that has no pending undelegations. + if app.PendingUndelegations == nil { + app.PendingUndelegations = make(map[uint64]types.UndelegatingGatewayList) + } + apps = append(apps, app) } diff --git a/x/application/keeper/application_test.go b/x/application/keeper/application_test.go index 6196c8e44..77ff951d0 100644 --- a/x/application/keeper/application_test.go +++ b/x/application/keeper/application_test.go @@ -22,6 +22,8 @@ func createNApplications(keeper keeper.Keeper, ctx context.Context, n int) []typ apps := make([]types.Application, n) for i := range apps { apps[i].Address = strconv.Itoa(i) + // Setting pending undelegations since nullify.Fill() does not seem to do it. + apps[i].PendingUndelegations = make(map[uint64]types.UndelegatingGatewayList) keeper.SetApplication(ctx, apps[i]) } diff --git a/x/application/keeper/msg_server_stake_application.go b/x/application/keeper/msg_server_stake_application.go index 4b4a76aa5..cb83ca787 100644 --- a/x/application/keeper/msg_server_stake_application.go +++ b/x/application/keeper/msg_server_stake_application.go @@ -87,6 +87,7 @@ func (k msgServer) createApplication( Stake: msg.Stake, ServiceConfigs: msg.Services, DelegateeGatewayAddresses: make([]string, 0), + PendingUndelegations: make(map[uint64]types.UndelegatingGatewayList), } } diff --git a/x/application/keeper/msg_server_undelegate_from_gateway.go b/x/application/keeper/msg_server_undelegate_from_gateway.go index 12bc29ed7..3a782e36b 100644 --- a/x/application/keeper/msg_server_undelegate_from_gateway.go +++ b/x/application/keeper/msg_server_undelegate_from_gateway.go @@ -3,11 +3,13 @@ package keeper import ( "context" "fmt" + "slices" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/telemetry" "github.com/pokt-network/poktroll/x/application/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" ) func (k msgServer) UndelegateFromGateway(ctx context.Context, msg *types.MsgUndelegateFromGateway) (*types.MsgUndelegateFromGatewayResponse, error) { @@ -21,6 +23,7 @@ func (k msgServer) UndelegateFromGateway(ctx context.Context, msg *types.MsgUnde logger := k.Logger().With("method", "UndelegateFromGateway") logger.Info(fmt.Sprintf("About to undelegate application from gateway with msg: %v", msg)) + // Basic validation of the message if err := msg.ValidateBasic(); err != nil { logger.Error(fmt.Sprintf("Undelegation Message failed basic validation: %v", err)) return nil, err @@ -49,21 +52,50 @@ func (k msgServer) UndelegateFromGateway(ctx context.Context, msg *types.MsgUnde // Remove the gateway from the application's delegatee gateway public keys foundApp.DelegateeGatewayAddresses = append(foundApp.DelegateeGatewayAddresses[:foundIdx], foundApp.DelegateeGatewayAddresses[foundIdx+1:]...) + sdkCtx := sdk.UnwrapSDKContext(ctx) + currentBlock := sdkCtx.BlockHeight() + + k.recordPendingUndelegation(&foundApp, msg.GatewayAddress, currentBlock) + // Update the application store with the new delegation k.SetApplication(ctx, foundApp) logger.Info(fmt.Sprintf("Successfully undelegated application from gateway for app: %+v", foundApp)) // Emit the application redelegation event event := msg.NewRedelegationEvent() - logger.Info(fmt.Sprintf("Emitting application redelegation event %v", event)) - - sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := sdkCtx.EventManager().EmitTypedEvent(event); err != nil { logger.Error(fmt.Sprintf("Failed to emit application redelegation event: %v", err)) return nil, err } + logger.Info(fmt.Sprintf("Emitted application redelegation event %v", event)) isSuccessful = true return &types.MsgUndelegateFromGatewayResponse{}, nil } + +// recordPendingUndelegation adds the given gateway address to the application's +// pending undelegations list. +func (k Keeper) recordPendingUndelegation( + app *types.Application, + gatewayAddress string, + currentBlockHeight int64, +) { + sessionEndHeight := uint64(sessionkeeper.GetSessionEndBlockHeight(currentBlockHeight)) + undelegatingGatewayListAtBlock := app.PendingUndelegations[sessionEndHeight] + + // Add the gateway address to the undelegated gateways list if it's not already there. + if !slices.Contains(undelegatingGatewayListAtBlock.GatewayAddresses, gatewayAddress) { + undelegatingGatewayListAtBlock.GatewayAddresses = append( + undelegatingGatewayListAtBlock.GatewayAddresses, + gatewayAddress, + ) + app.PendingUndelegations[sessionEndHeight] = undelegatingGatewayListAtBlock + } else { + k.logger.Info(fmt.Sprintf( + "Application with address [%s] undelegating (again) from a gateway it's already undelegating from with address [%s]", + app.Address, + gatewayAddress, + )) + } + +} diff --git a/x/application/keeper/msg_server_undelegate_from_gateway_test.go b/x/application/keeper/msg_server_undelegate_from_gateway_test.go index aba13dd99..682340ab6 100644 --- a/x/application/keeper/msg_server_undelegate_from_gateway_test.go +++ b/x/application/keeper/msg_server_undelegate_from_gateway_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "context" "fmt" "testing" @@ -8,10 +9,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/pkg/crypto/rings" keepertest "github.com/pokt-network/poktroll/testutil/keeper" "github.com/pokt-network/poktroll/testutil/sample" "github.com/pokt-network/poktroll/x/application/keeper" "github.com/pokt-network/poktroll/x/application/types" + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -272,3 +275,266 @@ func TestMsgServer_UndelegateFromGateway_SuccessfullyUndelegateFromUnstakedGatew require.Equal(t, appAddr, foundApp.Address) require.Equal(t, 0, len(foundApp.DelegateeGatewayAddresses)) } + +// Test an undelegation at different stages of the undelegation lifecycle: +// +// - Create an application, stake it, delegate then undelegate it from a gateway. +// +// - Increment the block height without moving to the next session and check that +// the undelegated gateway is still part of the application's delegate gateways. +// +// - Increment the block height to the next session and check that the undelegated +// gateway is no longer part of the application's delegate gateways. +// +// - Increment the block height past the tested session's grace period and check: +// +// - The undelegated gateway is still not part of the application's delegate gateways +// +// - If queried for a past block height, corresponding to the session at which the +// undelegation occurred, the reconstructed delegate gateway list does include +// the undelegated gateway. +func TestMsgServer_UndelegateFromGateway_DelegationIsActiveUntilNextSession(t *testing.T) { + k, ctx := keepertest.ApplicationKeeper(t) + srv := keeper.NewMsgServerImpl(k) + + undelegationHeight := int64(1) + sdkCtx, app, delegateAddr, pendingUndelegateFromAddr := + createAppStakeDelegateAndUndelegate(ctx, t, srv, k, undelegationHeight) + + // Increment the block height without moving to the next session, then run the + // pruning undelegations logic. + sdkCtx = sdkCtx.WithBlockHeight(undelegationHeight + 1) + k.EndBlockerPruneAppToGatewayPendingUndelegation(sdkCtx) + + // Get the updated application state after pruning logic is run. + app, isAppFound := k.GetApplication(sdkCtx, app.Address) + require.True(t, isAppFound) + require.NotNil(t, app) + + // Verify that the gateway was removed from the application's delegatee gateway addresses. + require.NotContains(t, app.DelegateeGatewayAddresses, pendingUndelegateFromAddr) + + // Verify that the gateway is added to the pending undelegation list with the + // right sessionEndHeight as the map key. + sessionEndHeight := uint64(sessionkeeper.GetSessionEndBlockHeight(undelegationHeight)) + require.Contains(t, + app.PendingUndelegations[sessionEndHeight].GatewayAddresses, + pendingUndelegateFromAddr, + ) + + // Verify that the application is still delegating to other gateways. + require.Contains(t, app.DelegateeGatewayAddresses, delegateAddr) + + // Verify that the reconstructed delegatee gateway list includes the undelegated gateway. + gatewayAddresses := rings.GetRingAddressesAtBlock(&app, sdkCtx.BlockHeight()) + require.Contains(t, gatewayAddresses, pendingUndelegateFromAddr) + + // Increment the block height to the next session and run the pruning + // undelegations logic again. + nextSessionStartHeight := int64(sessionEndHeight + 1) + sdkCtx = sdkCtx.WithBlockHeight(nextSessionStartHeight) + k.EndBlockerPruneAppToGatewayPendingUndelegation(sdkCtx) + + // Get the updated application state. + app, isAppFound = k.GetApplication(sdkCtx, app.Address) + require.True(t, isAppFound) + require.NotNil(t, app) + + // Verify that when queried for the next session the reconstructed delegatee + // gateway list does not include the undelegated gateway. + nextSessionGatewayAddresses := rings.GetRingAddressesAtBlock(&app, nextSessionStartHeight) + require.NotContains(t, nextSessionGatewayAddresses, pendingUndelegateFromAddr) + + // Increment the block height past the tested session's grace period and run + // the pruning undelegations logic again. + sessionGracePeriodBlockCount := uint64(sessionkeeper.GetSessionGracePeriodBlockCount()) + afterSessionGracePeriodHeight := int64(sessionEndHeight + sessionGracePeriodBlockCount + 1) + sdkCtx = sdkCtx.WithBlockHeight(afterSessionGracePeriodHeight) + k.EndBlockerPruneAppToGatewayPendingUndelegation(sdkCtx) + + // Verify that when queried for a block height past the tested session's grace period, + // the reconstructed delegatee gateway list does not include the undelegated gateway. + pastGracePeriodGatewayAddresses := rings.GetRingAddressesAtBlock(&app, afterSessionGracePeriodHeight) + require.NotContains(t, pastGracePeriodGatewayAddresses, pendingUndelegateFromAddr) + + // Ensure that when queried for the block height corresponding to the session + // at which the undelegation occurred, the reconstructed delegatee gateway list + // includes the undelegated gateway. + gatewayAddressesBeforeUndelegation := rings.GetRingAddressesAtBlock(&app, int64(sessionEndHeight)) + require.Contains(t, gatewayAddressesBeforeUndelegation, pendingUndelegateFromAddr) +} + +func TestMsgServer_UndelegateFromGateway_DelegationIsPrunedAfterRetentionPeriod(t *testing.T) { + k, ctx := keepertest.ApplicationKeeper(t) + srv := keeper.NewMsgServerImpl(k) + + undelegationHeight := int64(1) + sdkCtx, app, delegateAddr, pendingUndelegateFromAddr := + createAppStakeDelegateAndUndelegate(ctx, t, srv, k, undelegationHeight) + + // Increment the block height past the undelegation retention period then run + // the pruning undelegations logic. + pruningBlockHeight := getUndelegationPruningBlockHeight(undelegationHeight) + sdkCtx = sdkCtx.WithBlockHeight(pruningBlockHeight) + k.EndBlockerPruneAppToGatewayPendingUndelegation(sdkCtx) + + // Get the updated application state. + app, isAppFound := k.GetApplication(sdkCtx, app.Address) + require.True(t, isAppFound) + require.NotNil(t, app) + + // Verify that the the pending undelegation map no longer contains the + // sessionEndHeight key. + sessionEndHeight := uint64(sessionkeeper.GetSessionEndBlockHeight(undelegationHeight)) + require.Empty(t, app.PendingUndelegations[sessionEndHeight]) + + // Verify that the reconstructed delegatee gateway list can no longer include + // the undelegated gateway since it has been pruned. + gatewayAddressesAfterPruning := rings.GetRingAddressesAtBlock(&app, undelegationHeight) + require.NotContains(t, gatewayAddressesAfterPruning, pendingUndelegateFromAddr) + require.Contains(t, gatewayAddressesAfterPruning, delegateAddr) +} + +func TestMsgServer_UndelegateFromGateway_RedelegationAfterUndelegationAtTheSameSessionNumber(t *testing.T) { + k, ctx := keepertest.ApplicationKeeper(t) + srv := keeper.NewMsgServerImpl(k) + + undelegationHeight := int64(1) + sdkCtx, app, _, gatewayAddrToRedelegate := + createAppStakeDelegateAndUndelegate(ctx, t, srv, k, undelegationHeight) + + // Increment the block height without moving to the next session. + sdkCtx = sdkCtx.WithBlockHeight(undelegationHeight + 1) + + // Delegate back the application to the gateway that was undelegated from. + delegateMsg := &types.MsgDelegateToGateway{ + AppAddress: app.Address, + GatewayAddress: gatewayAddrToRedelegate, + } + _, err := srv.DelegateToGateway(ctx, delegateMsg) + require.NoError(t, err) + + // Get the updated application state. + app, isAppFound := k.GetApplication(sdkCtx, app.Address) + require.True(t, isAppFound) + require.NotNil(t, app) + + // Verify that the gateway is still in the application's delegatee gateway addresses. + require.Contains(t, app.DelegateeGatewayAddresses, gatewayAddrToRedelegate) + + // Verify that the gateway is also present in the pending undelegation list with the + // right sessionEndHeight as the map key. + sessionEndHeight := uint64(sessionkeeper.GetSessionEndBlockHeight(undelegationHeight)) + require.Contains(t, + app.PendingUndelegations[sessionEndHeight].GatewayAddresses, + gatewayAddrToRedelegate, + ) + + // Verify that the reconstructed delegatee gateway list includes the redelegated gateway. + gatewayAddresses := rings.GetRingAddressesAtBlock(&app, sdkCtx.BlockHeight()) + require.Contains(t, gatewayAddresses, gatewayAddrToRedelegate) + + // Increment the block height past the undelegation retention period then run + // the pruning undelegations logic. + pruningBlockHeight := getUndelegationPruningBlockHeight(undelegationHeight) + sdkCtx = sdkCtx.WithBlockHeight(pruningBlockHeight) + k.EndBlockerPruneAppToGatewayPendingUndelegation(sdkCtx) + + // Get the updated application state after pruning logic is run. + app, isAppFound = k.GetApplication(sdkCtx, app.Address) + require.True(t, isAppFound) + require.NotNil(t, app) + + // Verify that the application is still delegated to the gateway + require.Contains(t, app.DelegateeGatewayAddresses, gatewayAddrToRedelegate) + + // Verify that the the pending undelegation map no longer contains the + // sessionEndHeight key. + require.Empty(t, app.PendingUndelegations[sessionEndHeight]) + + // Verify that the reconstructed delegatee gateway list includes the redelegated gateway + gatewayAddressesAfterPruning := rings.GetRingAddressesAtBlock(&app, sdkCtx.BlockHeight()) + require.Contains(t, gatewayAddressesAfterPruning, gatewayAddrToRedelegate) +} + +// createAppStakeDelegateAndUndelegate is a helper function that is used in the tests +// that exercise the pruning undelegations and ring addresses reconstruction logic. +// * It creates an account address and stakes it as an application. +// * Creates two gateway addresses and mocks them being staked. +// * Delegates the application to the gateways. +// * Undelegates the application from one of the gateways. +func createAppStakeDelegateAndUndelegate( + ctx context.Context, + t *testing.T, + srv types.MsgServer, + k keeper.Keeper, + undelegationHeight int64, +) ( + sdkCtx sdk.Context, + app types.Application, + delegateAddr, + pendingUndelegateFromAddr string, +) { + // Generate an application address and stake the application. + appAddr := sample.AccAddress() + stakeMsg := &types.MsgStakeApplication{ + Address: appAddr, + Stake: &sdk.Coin{Denom: "upokt", Amount: math.NewInt(100)}, + Services: []*sharedtypes.ApplicationServiceConfig{ + { + Service: &sharedtypes.Service{Id: "svc1"}, + }, + }, + } + _, err := srv.StakeApplication(ctx, stakeMsg) + require.NoError(t, err) + + // Generate gateway addresses, mock the gateways being staked then delegate the + // application to the gateways. + delegateAddr = sample.AccAddress() + keepertest.AddGatewayToStakedGatewayMap(t, delegateAddr) + + delegateMsg := &types.MsgDelegateToGateway{ + AppAddress: appAddr, + GatewayAddress: delegateAddr, + } + _, err = srv.DelegateToGateway(ctx, delegateMsg) + require.NoError(t, err) + + pendingUndelegateFromAddr = sample.AccAddress() + keepertest.AddGatewayToStakedGatewayMap(t, pendingUndelegateFromAddr) + + delegateMsg = &types.MsgDelegateToGateway{ + AppAddress: appAddr, + GatewayAddress: pendingUndelegateFromAddr, + } + _, err = srv.DelegateToGateway(ctx, delegateMsg) + require.NoError(t, err) + + // Create a context with a block height of 2. + sdkCtx = sdk.UnwrapSDKContext(ctx).WithBlockHeight(undelegationHeight) + + // Undelegate from the first gateway. + undelegateMsg := &types.MsgUndelegateFromGateway{ + AppAddress: appAddr, + GatewayAddress: pendingUndelegateFromAddr, + } + _, err = srv.UndelegateFromGateway(sdkCtx, undelegateMsg) + require.NoError(t, err) + + foundApp, isAppFound := k.GetApplication(sdkCtx, appAddr) + + // Verify that the application exists. + require.True(t, isAppFound) + require.NotNil(t, foundApp) + + return sdkCtx, foundApp, delegateAddr, pendingUndelegateFromAddr +} + +// getUndelegationPruningBlockHeight returns the block height at which undelegations +// should be pruned for a given undlegation block height. +func getUndelegationPruningBlockHeight(blockHeight int64) (pruningHeihgt int64) { + nextSessionStartHeight := sessionkeeper.GetSessionEndBlockHeight(blockHeight) + 1 + + return nextSessionStartHeight + keeper.GetNumBlocksUndelegationRetention() +} diff --git a/x/application/keeper/prune_undelegations.go b/x/application/keeper/prune_undelegations.go new file mode 100644 index 000000000..77aae88da --- /dev/null +++ b/x/application/keeper/prune_undelegations.go @@ -0,0 +1,50 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + sessionkeeper "github.com/pokt-network/poktroll/x/session/keeper" +) + +// NumSessionsAppToGatewayUndelegationRetention is the number of sessions for which +// undelegation from applications to gateways are delayed before being pruned. +// TODO_DOCUMENT(@red-0ne): Need to document the flow from this comment +// so its clear to everyone why this is necessary; https://github.com/pokt-network/poktroll/issues/476#issuecomment-2052639906. +// TODO_CONSIDERATION(#516): Should this be configurable? Note that it should +// likely be a function of SubmitProofCloseWindowNumBlocks once implemented. +const NumSessionsAppToGatewayUndelegationRetention = 2 + +// EndBlockerPruneAppToGatewayPendingUndelegation runs at the end of each block +// and prunes app to gateway undelegations that have exceeded the retention delay. +func (k Keeper) EndBlockerPruneAppToGatewayPendingUndelegation(ctx sdk.Context) error { + currentHeight := ctx.BlockHeight() + + // Calculate the block height at which undelegations should be pruned + numBlocksUndelegationRetention := GetNumBlocksUndelegationRetention() + if currentHeight <= numBlocksUndelegationRetention { + return nil + } + earliestUnprunedUndelegationHeight := uint64(currentHeight - numBlocksUndelegationRetention) + + // Iterate over all applications and prune undelegations that are older than + // the retention period. + for _, application := range k.GetAllApplications(ctx) { + for undelegationSessionEndHeight := range application.PendingUndelegations { + if undelegationSessionEndHeight < earliestUnprunedUndelegationHeight { + // prune undelegations + delete(application.PendingUndelegations, undelegationSessionEndHeight) + } + } + + k.SetApplication(ctx, application) + } + + return nil +} + +// GetNumBlocksUndelegationRetention returns the number of blocks for which +// undelegations should be kept before being pruned. +func GetNumBlocksUndelegationRetention() int64 { + return sessionkeeper.GetSessionGracePeriodBlockCount() + + (sessionkeeper.NumBlocksPerSession * NumSessionsAppToGatewayUndelegationRetention) +} diff --git a/x/application/keeper/query_application.go b/x/application/keeper/query_application.go index 466710696..af002bd19 100644 --- a/x/application/keeper/query_application.go +++ b/x/application/keeper/query_application.go @@ -27,6 +27,12 @@ func (k Keeper) AllApplications(ctx context.Context, req *types.QueryAllApplicat return err } + // Ensure that the PendingUndelegations is an empty map and not nil when + // unmarshalling an app that has no pending undelegations. + if application.PendingUndelegations == nil { + application.PendingUndelegations = make(map[uint64]types.UndelegatingGatewayList) + } + apps = append(apps, application) return nil }) diff --git a/x/application/module/abci.go b/x/application/module/abci.go new file mode 100644 index 000000000..209a81431 --- /dev/null +++ b/x/application/module/abci.go @@ -0,0 +1,16 @@ +package application + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/pokt-network/poktroll/x/application/keeper" +) + +// EndBlocker is called every block and handles application related updates. +func EndBlocker(ctx sdk.Context, k keeper.Keeper) error { + if err := k.EndBlockerPruneAppToGatewayPendingUndelegation(ctx); err != nil { + return err + } + + return nil +} diff --git a/x/application/module/module.go b/x/application/module/module.go index 9283099e7..72d0e86ac 100644 --- a/x/application/module/module.go +++ b/x/application/module/module.go @@ -95,29 +95,29 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r type AppModule struct { AppModuleBasic - keeper keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + applicationKeeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper } func NewAppModule( cdc codec.Codec, - keeper keeper.Keeper, + applicationKeeper keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, ) AppModule { return AppModule{ - AppModuleBasic: NewAppModuleBasic(cdc), - keeper: keeper, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, + AppModuleBasic: NewAppModuleBasic(cdc), + applicationKeeper: applicationKeeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, } } // RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.applicationKeeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.applicationKeeper) } // RegisterInvariants registers the invariants of the module. If an invariant deviates from its predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will be halted) @@ -129,12 +129,12 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.Ra // Initialize global index to index in genesis state cdc.MustUnmarshalJSON(gs, &genState) - InitGenesis(ctx, am.keeper, genState) + InitGenesis(ctx, am.applicationKeeper, genState) } // ExportGenesis returns the module's exported genesis state as raw JSON bytes. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - genState := ExportGenesis(ctx, am.keeper) + genState := ExportGenesis(ctx, am.applicationKeeper) return cdc.MustMarshalJSON(genState) } @@ -151,8 +151,9 @@ func (am AppModule) BeginBlock(_ context.Context) error { // EndBlock contains the logic that is automatically triggered at the end of each block. // The end block implementation is optional. -func (am AppModule) EndBlock(_ context.Context) error { - return nil +func (am AppModule) EndBlock(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + return EndBlocker(ctx, am.applicationKeeper) } // IsOnePerModuleType implements the depinject.OnePerModuleType interface. diff --git a/x/application/module/simulation.go b/x/application/module/simulation.go index 0cd35bfe6..45d596c1d 100644 --- a/x/application/module/simulation.go +++ b/x/application/module/simulation.go @@ -75,7 +75,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgStakeApplication, - applicationsimulation.SimulateMsgStakeApplication(am.accountKeeper, am.bankKeeper, am.keeper), + applicationsimulation.SimulateMsgStakeApplication(am.accountKeeper, am.bankKeeper, am.applicationKeeper), )) var weightMsgUnstakeApplication int @@ -86,7 +86,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgUnstakeApplication, - applicationsimulation.SimulateMsgUnstakeApplication(am.accountKeeper, am.bankKeeper, am.keeper), + applicationsimulation.SimulateMsgUnstakeApplication(am.accountKeeper, am.bankKeeper, am.applicationKeeper), )) var weightMsgDelegateToGateway int @@ -97,7 +97,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgDelegateToGateway, - applicationsimulation.SimulateMsgDelegateToGateway(am.accountKeeper, am.bankKeeper, am.keeper), + applicationsimulation.SimulateMsgDelegateToGateway(am.accountKeeper, am.bankKeeper, am.applicationKeeper), )) var weightMsgUndelegateFromGateway int @@ -108,7 +108,7 @@ func (am AppModule) WeightedOperations(simState module.SimulationState) []simtyp ) operations = append(operations, simulation.NewWeightedOperation( weightMsgUndelegateFromGateway, - applicationsimulation.SimulateMsgUndelegateFromGateway(am.accountKeeper, am.bankKeeper, am.keeper), + applicationsimulation.SimulateMsgUndelegateFromGateway(am.accountKeeper, am.bankKeeper, am.applicationKeeper), )) // this line is used by starport scaffolding # simapp/module/operation @@ -123,7 +123,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgStakeApplication, defaultWeightMsgStakeApplication, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - applicationsimulation.SimulateMsgStakeApplication(am.accountKeeper, am.bankKeeper, am.keeper) + applicationsimulation.SimulateMsgStakeApplication(am.accountKeeper, am.bankKeeper, am.applicationKeeper) return nil }, ), @@ -131,7 +131,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgUnstakeApplication, defaultWeightMsgUnstakeApplication, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - applicationsimulation.SimulateMsgUnstakeApplication(am.accountKeeper, am.bankKeeper, am.keeper) + applicationsimulation.SimulateMsgUnstakeApplication(am.accountKeeper, am.bankKeeper, am.applicationKeeper) return nil }, ), @@ -139,7 +139,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgDelegateToGateway, defaultWeightMsgDelegateToGateway, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - applicationsimulation.SimulateMsgDelegateToGateway(am.accountKeeper, am.bankKeeper, am.keeper) + applicationsimulation.SimulateMsgDelegateToGateway(am.accountKeeper, am.bankKeeper, am.applicationKeeper) return nil }, ), @@ -147,7 +147,7 @@ func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.Wei opWeightMsgUndelegateFromGateway, defaultWeightMsgUndelegateFromGateway, func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) sdk.Msg { - applicationsimulation.SimulateMsgUndelegateFromGateway(am.accountKeeper, am.bankKeeper, am.keeper) + applicationsimulation.SimulateMsgUndelegateFromGateway(am.accountKeeper, am.bankKeeper, am.applicationKeeper) return nil }, ), diff --git a/x/proof/keeper/msg_server_submit_proof_test.go b/x/proof/keeper/msg_server_submit_proof_test.go index 31469fc7f..569c18c6e 100644 --- a/x/proof/keeper/msg_server_submit_proof_test.go +++ b/x/proof/keeper/msg_server_submit_proof_test.go @@ -1205,8 +1205,11 @@ func signRelayRequest( ) { t.Helper() - // Retrieve the signing ring associated with the application address. - appRing, err := ringClient.GetRingForAddress(ctx, appAddr) + relayReqMeta := relay.GetReq().GetMeta() + sessionEndHeight := relayReqMeta.GetSessionHeader().GetSessionEndBlockHeight() + + // Retrieve the signing ring associated with the application address at the session end height. + appRing, err := ringClient.GetRingForAddressAtHeight(ctx, appAddr, sessionEndHeight) require.NoError(t, err) // Retrieve the signing key associated with the application address.