diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..debe5b8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## v0.4.9 - 2024.12.6 + +### Enhancements + +- Added support for ERC20-compatible mapping for IBC assets.[Issue #8](https://github.com/artela-network/artela-rollkit/issues/8) | [Commit b0570ae](https://github.com/artela-network/artela-rollkit/commit/b0570ae5e6ce6f8f7d14711e83d0d34644ca037f) | [Introduction](x/evm/precompile/erc20.md) + +### Improvements + +- Refactored Aspect storage and Aspect System Contract. [Issue #8](https://github.com/artela-network/artela-rollkit/issues/8) | [Commit a151dbc...afd1a43](https://github.com/artela-network/artela-rollkit/compare/a151dbc0a6f508de70763e76b978560b633bf020...afd1a43c8c7d24257d1f8cb9c50e4f106dc8682a) + +### Fixes + +- Fixed an encoding issue encountered during private key import. [Issue #6](https://github.com/artela-network/artela-rollkit/issues/6) +- Fixed support for the EthSecp256k1 private key algorithm. [Issue #9](https://github.com/artela-network/artela-rollkit/issues/9) | [Commit 0b8e174](https://github.com/artela-network/artela-rollkit/commit/0b8e174331cc71014acf7edc58db699f9ecdd450) +- Fixed transaction conversion support during trace tx. [Issue #9](https://github.com/artela-network/artela-rollkit/issues/9) | [Commit 4312d81](https://github.com/artela-network/artela-rollkit/commit/4312d8191412f76c434018431557f4634f97565a) +- Fixed an issue with block fetching caused by Rollkit block submission mechanism. [Issue #9](https://github.com/artela-network/artela-rollkit/issues/9) | [Commit e0ec03a](https://github.com/artela-network/artela-rollkit/commit/e0ec03a4f675a289e576558726f11c48d2524dfa) diff --git a/api/artela/aspect/genesis.pulsar.go b/api/artela/aspect/genesis.pulsar.go new file mode 100644 index 0000000..9f26f45 --- /dev/null +++ b/api/artela/aspect/genesis.pulsar.go @@ -0,0 +1,595 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package aspect + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + _ "cosmossdk.io/api/amino" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + md_GenesisState protoreflect.MessageDescriptor + fd_GenesisState_params protoreflect.FieldDescriptor +) + +func init() { + file_artela_aspect_genesis_proto_init() + md_GenesisState = File_artela_aspect_genesis_proto.Messages().ByName("GenesisState") + fd_GenesisState_params = md_GenesisState.Fields().ByName("params") +} + +var _ protoreflect.Message = (*fastReflection_GenesisState)(nil) + +type fastReflection_GenesisState GenesisState + +func (x *GenesisState) ProtoReflect() protoreflect.Message { + return (*fastReflection_GenesisState)(x) +} + +func (x *GenesisState) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_genesis_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_GenesisState_messageType fastReflection_GenesisState_messageType +var _ protoreflect.MessageType = fastReflection_GenesisState_messageType{} + +type fastReflection_GenesisState_messageType struct{} + +func (x fastReflection_GenesisState_messageType) Zero() protoreflect.Message { + return (*fastReflection_GenesisState)(nil) +} +func (x fastReflection_GenesisState_messageType) New() protoreflect.Message { + return new(fastReflection_GenesisState) +} +func (x fastReflection_GenesisState_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_GenesisState +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_GenesisState) Descriptor() protoreflect.MessageDescriptor { + return md_GenesisState +} + +// 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_GenesisState) Type() protoreflect.MessageType { + return _fastReflection_GenesisState_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_GenesisState) New() protoreflect.Message { + return new(fastReflection_GenesisState) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_GenesisState) Interface() protoreflect.ProtoMessage { + return (*GenesisState)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_GenesisState) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_GenesisState_params, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_GenesisState) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "artela.aspect.GenesisState.params": + return x.Params != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "artela.aspect.GenesisState.params": + x.Params = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "artela.aspect.GenesisState.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "artela.aspect.GenesisState.params": + x.Params = value.Message().Interface().(*Params) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.GenesisState.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.GenesisState.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.GenesisState")) + } + panic(fmt.Errorf("message artela.aspect.GenesisState 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_GenesisState) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.GenesisState", 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_GenesisState) 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_GenesisState) 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_GenesisState) 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_GenesisState) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*GenesisState) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Params != nil { + l = options.Size(x.Params) + 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().(*GenesisState) + 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 x.Params != nil { + encoded, err := options.Marshal(x.Params) + 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] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*GenesisState) + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", 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.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + 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: artela/aspect/genesis.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) +) + +// GenesisState defines the aspect module's genesis state. +type GenesisState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // params defines all the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (x *GenesisState) Reset() { + *x = GenesisState{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_genesis_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenesisState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenesisState) ProtoMessage() {} + +// Deprecated: Use GenesisState.ProtoReflect.Descriptor instead. +func (*GenesisState) Descriptor() ([]byte, []int) { + return file_artela_aspect_genesis_proto_rawDescGZIP(), []int{0} +} + +func (x *GenesisState) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +var File_artela_aspect_genesis_proto protoreflect.FileDescriptor + +var file_artela_aspect_genesis_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, + 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x1a, 0x11, 0x61, 0x6d, + 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x48, 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x38, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, + 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xaa, 0x01, 0x0a, 0x11, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x42, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x74, + 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, + 0x73, 0x70, 0x65, 0x63, 0x74, 0xa2, 0x02, 0x03, 0x41, 0x41, 0x58, 0xaa, 0x02, 0x0d, 0x41, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xca, 0x02, 0x0d, 0x41, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xe2, 0x02, 0x19, 0x41, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x3a, 0x3a, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_artela_aspect_genesis_proto_rawDescOnce sync.Once + file_artela_aspect_genesis_proto_rawDescData = file_artela_aspect_genesis_proto_rawDesc +) + +func file_artela_aspect_genesis_proto_rawDescGZIP() []byte { + file_artela_aspect_genesis_proto_rawDescOnce.Do(func() { + file_artela_aspect_genesis_proto_rawDescData = protoimpl.X.CompressGZIP(file_artela_aspect_genesis_proto_rawDescData) + }) + return file_artela_aspect_genesis_proto_rawDescData +} + +var file_artela_aspect_genesis_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_artela_aspect_genesis_proto_goTypes = []interface{}{ + (*GenesisState)(nil), // 0: artela.aspect.GenesisState + (*Params)(nil), // 1: artela.aspect.Params +} +var file_artela_aspect_genesis_proto_depIdxs = []int32{ + 1, // 0: artela.aspect.GenesisState.params:type_name -> artela.aspect.Params + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_artela_aspect_genesis_proto_init() } +func file_artela_aspect_genesis_proto_init() { + if File_artela_aspect_genesis_proto != nil { + return + } + file_artela_aspect_params_proto_init() + if !protoimpl.UnsafeEnabled { + file_artela_aspect_genesis_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenesisState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_artela_aspect_genesis_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_artela_aspect_genesis_proto_goTypes, + DependencyIndexes: file_artela_aspect_genesis_proto_depIdxs, + MessageInfos: file_artela_aspect_genesis_proto_msgTypes, + }.Build() + File_artela_aspect_genesis_proto = out.File + file_artela_aspect_genesis_proto_rawDesc = nil + file_artela_aspect_genesis_proto_goTypes = nil + file_artela_aspect_genesis_proto_depIdxs = nil +} diff --git a/api/artela/aspect/module/module.pulsar.go b/api/artela/aspect/module/module.pulsar.go new file mode 100644 index 0000000..000029a --- /dev/null +++ b/api/artela/aspect/module/module.pulsar.go @@ -0,0 +1,579 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package module + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + _ "cosmossdk.io/api/cosmos/app/v1alpha1" + runtime "github.com/cosmos/cosmos-proto/runtime" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + md_Module protoreflect.MessageDescriptor + fd_Module_authority protoreflect.FieldDescriptor +) + +func init() { + file_artela_aspect_module_module_proto_init() + md_Module = File_artela_aspect_module_module_proto.Messages().ByName("Module") + fd_Module_authority = md_Module.Fields().ByName("authority") +} + +var _ protoreflect.Message = (*fastReflection_Module)(nil) + +type fastReflection_Module Module + +func (x *Module) ProtoReflect() protoreflect.Message { + return (*fastReflection_Module)(x) +} + +func (x *Module) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_module_module_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Module_messageType fastReflection_Module_messageType +var _ protoreflect.MessageType = fastReflection_Module_messageType{} + +type fastReflection_Module_messageType struct{} + +func (x fastReflection_Module_messageType) Zero() protoreflect.Message { + return (*fastReflection_Module)(nil) +} +func (x fastReflection_Module_messageType) New() protoreflect.Message { + return new(fastReflection_Module) +} +func (x fastReflection_Module_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Module) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// 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_Module) Type() protoreflect.MessageType { + return _fastReflection_Module_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Module) New() protoreflect.Message { + return new(fastReflection_Module) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Module) Interface() protoreflect.ProtoMessage { + return (*Module)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Module) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Authority != "" { + value := protoreflect.ValueOfString(x.Authority) + if !f(fd_Module_authority, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "artela.aspect.module.Module.authority": + return x.Authority != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "artela.aspect.module.Module.authority": + x.Authority = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "artela.aspect.module.Module.authority": + value := x.Authority + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "artela.aspect.module.Module.authority": + x.Authority = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.module.Module.authority": + panic(fmt.Errorf("field authority of message artela.aspect.module.Module is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.module.Module.authority": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.module.Module")) + } + panic(fmt.Errorf("message artela.aspect.module.Module 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_Module) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.module.Module", 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_Module) 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_Module) 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_Module) 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_Module) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Authority) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Module) + 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.Authority) > 0 { + i -= len(x.Authority) + copy(dAtA[i:], x.Authority) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Authority))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Module) + 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: Module: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Module: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Authority", 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.Authority = 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: artela/aspect/module/module.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) +) + +// Module is the config object for the module. +type Module struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // authority defines the custom module authority. If not set, defaults to the governance module. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` +} + +func (x *Module) Reset() { + *x = Module{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_module_module_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Module) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Module) ProtoMessage() {} + +// Deprecated: Use Module.ProtoReflect.Descriptor instead. +func (*Module) Descriptor() ([]byte, []int) { + return file_artela_aspect_module_module_proto_rawDescGZIP(), []int{0} +} + +func (x *Module) GetAuthority() string { + if x != nil { + return x.Authority + } + return "" +} + +var File_artela_aspect_module_module_proto protoreflect.FileDescriptor + +var file_artela_aspect_module_module_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, + 0x63, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x1a, 0x20, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x59, 0x0a, 0x06, 0x4d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x3a, 0x31, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x2b, 0x0a, 0x29, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2d, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x78, 0x2f, + 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x42, 0xd4, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x6d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, + 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0xa2, 0x02, 0x03, + 0x41, 0x41, 0x4d, 0xaa, 0x02, 0x14, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x41, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0xca, 0x02, 0x14, 0x41, 0x72, 0x74, + 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0xe2, 0x02, 0x20, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x3a, 0x3a, 0x41, + 0x73, 0x70, 0x65, 0x63, 0x74, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_artela_aspect_module_module_proto_rawDescOnce sync.Once + file_artela_aspect_module_module_proto_rawDescData = file_artela_aspect_module_module_proto_rawDesc +) + +func file_artela_aspect_module_module_proto_rawDescGZIP() []byte { + file_artela_aspect_module_module_proto_rawDescOnce.Do(func() { + file_artela_aspect_module_module_proto_rawDescData = protoimpl.X.CompressGZIP(file_artela_aspect_module_module_proto_rawDescData) + }) + return file_artela_aspect_module_module_proto_rawDescData +} + +var file_artela_aspect_module_module_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_artela_aspect_module_module_proto_goTypes = []interface{}{ + (*Module)(nil), // 0: artela.aspect.module.Module +} +var file_artela_aspect_module_module_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_artela_aspect_module_module_proto_init() } +func file_artela_aspect_module_module_proto_init() { + if File_artela_aspect_module_module_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_artela_aspect_module_module_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Module); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_artela_aspect_module_module_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_artela_aspect_module_module_proto_goTypes, + DependencyIndexes: file_artela_aspect_module_module_proto_depIdxs, + MessageInfos: file_artela_aspect_module_module_proto_msgTypes, + }.Build() + File_artela_aspect_module_module_proto = out.File + file_artela_aspect_module_module_proto_rawDesc = nil + file_artela_aspect_module_module_proto_goTypes = nil + file_artela_aspect_module_module_proto_depIdxs = nil +} diff --git a/api/artela/aspect/params.pulsar.go b/api/artela/aspect/params.pulsar.go new file mode 100644 index 0000000..241e85b --- /dev/null +++ b/api/artela/aspect/params.pulsar.go @@ -0,0 +1,500 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package aspect + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + _ "cosmossdk.io/api/amino" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + md_Params protoreflect.MessageDescriptor +) + +func init() { + file_artela_aspect_params_proto_init() + md_Params = File_artela_aspect_params_proto.Messages().ByName("Params") +} + +var _ protoreflect.Message = (*fastReflection_Params)(nil) + +type fastReflection_Params Params + +func (x *Params) ProtoReflect() protoreflect.Message { + return (*fastReflection_Params)(x) +} + +func (x *Params) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_params_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Params_messageType fastReflection_Params_messageType +var _ protoreflect.MessageType = fastReflection_Params_messageType{} + +type fastReflection_Params_messageType struct{} + +func (x fastReflection_Params_messageType) Zero() protoreflect.Message { + return (*fastReflection_Params)(nil) +} +func (x fastReflection_Params_messageType) New() protoreflect.Message { + return new(fastReflection_Params) +} +func (x fastReflection_Params_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Params +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Params) Descriptor() protoreflect.MessageDescriptor { + return md_Params +} + +// 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_Params) Type() protoreflect.MessageType { + return _fastReflection_Params_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Params) New() protoreflect.Message { + return new(fastReflection_Params) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Params) Interface() protoreflect.ProtoMessage { + return (*Params)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// 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_Params) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.Params")) + } + panic(fmt.Errorf("message artela.aspect.Params 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_Params) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.Params", 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_Params) 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_Params) 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_Params) 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_Params) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Params) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.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().(*Params) + 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 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().(*Params) + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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: artela/aspect/params.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) +) + +// Params defines the parameters for the module. +type Params struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Params) Reset() { + *x = Params{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_params_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Params) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Params) ProtoMessage() {} + +// Deprecated: Use Params.ProtoReflect.Descriptor instead. +func (*Params) Descriptor() ([]byte, []int) { + return file_artela_aspect_params_proto_rawDescGZIP(), []int{0} +} + +var File_artela_aspect_params_proto protoreflect.FileDescriptor + +var file_artela_aspect_params_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x61, 0x72, + 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x1a, 0x11, 0x61, 0x6d, 0x69, + 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, + 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x29, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x1f, + 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x16, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, + 0x78, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, + 0xa9, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, + 0x73, 0x70, 0x65, 0x63, 0x74, 0x42, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, + 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, + 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0xa2, 0x02, 0x03, 0x41, 0x41, 0x58, 0xaa, 0x02, + 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xca, 0x02, + 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xe2, 0x02, + 0x19, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x41, 0x72, 0x74, + 0x65, 0x6c, 0x61, 0x3a, 0x3a, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_artela_aspect_params_proto_rawDescOnce sync.Once + file_artela_aspect_params_proto_rawDescData = file_artela_aspect_params_proto_rawDesc +) + +func file_artela_aspect_params_proto_rawDescGZIP() []byte { + file_artela_aspect_params_proto_rawDescOnce.Do(func() { + file_artela_aspect_params_proto_rawDescData = protoimpl.X.CompressGZIP(file_artela_aspect_params_proto_rawDescData) + }) + return file_artela_aspect_params_proto_rawDescData +} + +var file_artela_aspect_params_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_artela_aspect_params_proto_goTypes = []interface{}{ + (*Params)(nil), // 0: artela.aspect.Params +} +var file_artela_aspect_params_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_artela_aspect_params_proto_init() } +func file_artela_aspect_params_proto_init() { + if File_artela_aspect_params_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_artela_aspect_params_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Params); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_artela_aspect_params_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_artela_aspect_params_proto_goTypes, + DependencyIndexes: file_artela_aspect_params_proto_depIdxs, + MessageInfos: file_artela_aspect_params_proto_msgTypes, + }.Build() + File_artela_aspect_params_proto = out.File + file_artela_aspect_params_proto_rawDesc = nil + file_artela_aspect_params_proto_goTypes = nil + file_artela_aspect_params_proto_depIdxs = nil +} diff --git a/api/artela/aspect/query.pulsar.go b/api/artela/aspect/query.pulsar.go new file mode 100644 index 0000000..48e9da1 --- /dev/null +++ b/api/artela/aspect/query.pulsar.go @@ -0,0 +1,1010 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package aspect + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + _ "cosmossdk.io/api/amino" + _ "cosmossdk.io/api/cosmos/base/query/v1beta1" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + md_QueryParamsRequest protoreflect.MessageDescriptor +) + +func init() { + file_artela_aspect_query_proto_init() + md_QueryParamsRequest = File_artela_aspect_query_proto.Messages().ByName("QueryParamsRequest") +} + +var _ protoreflect.Message = (*fastReflection_QueryParamsRequest)(nil) + +type fastReflection_QueryParamsRequest QueryParamsRequest + +func (x *QueryParamsRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryParamsRequest)(x) +} + +func (x *QueryParamsRequest) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_query_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryParamsRequest_messageType fastReflection_QueryParamsRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryParamsRequest_messageType{} + +type fastReflection_QueryParamsRequest_messageType struct{} + +func (x fastReflection_QueryParamsRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryParamsRequest)(nil) +} +func (x fastReflection_QueryParamsRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryParamsRequest) +} +func (x fastReflection_QueryParamsRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryParamsRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsRequest +} + +// 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_QueryParamsRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryParamsRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryParamsRequest) New() protoreflect.Message { + return new(fastReflection_QueryParamsRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryParamsRequest) Interface() protoreflect.ProtoMessage { + return (*QueryParamsRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryParamsRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// 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_QueryParamsRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsRequest")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsRequest 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_QueryParamsRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.QueryParamsRequest", 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_QueryParamsRequest) 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_QueryParamsRequest) 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_QueryParamsRequest) 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_QueryParamsRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryParamsRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.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().(*QueryParamsRequest) + 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 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().(*QueryParamsRequest) + 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryParamsResponse protoreflect.MessageDescriptor + fd_QueryParamsResponse_params protoreflect.FieldDescriptor +) + +func init() { + file_artela_aspect_query_proto_init() + md_QueryParamsResponse = File_artela_aspect_query_proto.Messages().ByName("QueryParamsResponse") + fd_QueryParamsResponse_params = md_QueryParamsResponse.Fields().ByName("params") +} + +var _ protoreflect.Message = (*fastReflection_QueryParamsResponse)(nil) + +type fastReflection_QueryParamsResponse QueryParamsResponse + +func (x *QueryParamsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryParamsResponse)(x) +} + +func (x *QueryParamsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_query_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryParamsResponse_messageType fastReflection_QueryParamsResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryParamsResponse_messageType{} + +type fastReflection_QueryParamsResponse_messageType struct{} + +func (x fastReflection_QueryParamsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryParamsResponse)(nil) +} +func (x fastReflection_QueryParamsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryParamsResponse) +} +func (x fastReflection_QueryParamsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryParamsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryParamsResponse +} + +// 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_QueryParamsResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryParamsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryParamsResponse) New() protoreflect.Message { + return new(fastReflection_QueryParamsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryParamsResponse) Interface() protoreflect.ProtoMessage { + return (*QueryParamsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryParamsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_QueryParamsResponse_params, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryParamsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "artela.aspect.QueryParamsResponse.params": + return x.Params != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "artela.aspect.QueryParamsResponse.params": + x.Params = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "artela.aspect.QueryParamsResponse.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "artela.aspect.QueryParamsResponse.params": + x.Params = value.Message().Interface().(*Params) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.QueryParamsResponse.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.QueryParamsResponse.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.QueryParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.QueryParamsResponse 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_QueryParamsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.QueryParamsResponse", 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_QueryParamsResponse) 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_QueryParamsResponse) 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_QueryParamsResponse) 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_QueryParamsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryParamsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.Params != nil { + l = options.Size(x.Params) + 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().(*QueryParamsResponse) + 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 x.Params != nil { + encoded, err := options.Marshal(x.Params) + 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] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryParamsResponse) + 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", 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.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + 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: artela/aspect/query.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) +) + +// QueryParamsRequest is request type for the Query/Params RPC method. +type QueryParamsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *QueryParamsRequest) Reset() { + *x = QueryParamsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_query_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryParamsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryParamsRequest) ProtoMessage() {} + +// Deprecated: Use QueryParamsRequest.ProtoReflect.Descriptor instead. +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return file_artela_aspect_query_proto_rawDescGZIP(), []int{0} +} + +// QueryParamsResponse is response type for the Query/Params RPC method. +type QueryParamsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // params holds all the parameters of this module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (x *QueryParamsResponse) Reset() { + *x = QueryParamsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_query_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryParamsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryParamsResponse) ProtoMessage() {} + +// Deprecated: Use QueryParamsResponse.ProtoReflect.Descriptor instead. +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return file_artela_aspect_query_proto_rawDescGZIP(), []int{1} +} + +func (x *QueryParamsResponse) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +var File_artela_aspect_query_proto protoreflect.FileDescriptor + +var file_artela_aspect_query_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x61, 0x72, 0x74, + 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, + 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, + 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x14, 0x0a, 0x12, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x4f, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, + 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, + 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x32, 0x86, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x7d, 0x0a, 0x06, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2d, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, + 0x63, 0x74, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xa8, 0x01, 0x0a, 0x11, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x42, + 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, + 0x74, 0xa2, 0x02, 0x03, 0x41, 0x41, 0x58, 0xaa, 0x02, 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x2e, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xca, 0x02, 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xe2, 0x02, 0x19, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x5c, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x3a, 0x3a, 0x41, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_artela_aspect_query_proto_rawDescOnce sync.Once + file_artela_aspect_query_proto_rawDescData = file_artela_aspect_query_proto_rawDesc +) + +func file_artela_aspect_query_proto_rawDescGZIP() []byte { + file_artela_aspect_query_proto_rawDescOnce.Do(func() { + file_artela_aspect_query_proto_rawDescData = protoimpl.X.CompressGZIP(file_artela_aspect_query_proto_rawDescData) + }) + return file_artela_aspect_query_proto_rawDescData +} + +var file_artela_aspect_query_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_artela_aspect_query_proto_goTypes = []interface{}{ + (*QueryParamsRequest)(nil), // 0: artela.aspect.QueryParamsRequest + (*QueryParamsResponse)(nil), // 1: artela.aspect.QueryParamsResponse + (*Params)(nil), // 2: artela.aspect.Params +} +var file_artela_aspect_query_proto_depIdxs = []int32{ + 2, // 0: artela.aspect.QueryParamsResponse.params:type_name -> artela.aspect.Params + 0, // 1: artela.aspect.Query.Params:input_type -> artela.aspect.QueryParamsRequest + 1, // 2: artela.aspect.Query.Params:output_type -> artela.aspect.QueryParamsResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_artela_aspect_query_proto_init() } +func file_artela_aspect_query_proto_init() { + if File_artela_aspect_query_proto != nil { + return + } + file_artela_aspect_params_proto_init() + if !protoimpl.UnsafeEnabled { + file_artela_aspect_query_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryParamsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_artela_aspect_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryParamsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_artela_aspect_query_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_artela_aspect_query_proto_goTypes, + DependencyIndexes: file_artela_aspect_query_proto_depIdxs, + MessageInfos: file_artela_aspect_query_proto_msgTypes, + }.Build() + File_artela_aspect_query_proto = out.File + file_artela_aspect_query_proto_rawDesc = nil + file_artela_aspect_query_proto_goTypes = nil + file_artela_aspect_query_proto_depIdxs = nil +} diff --git a/api/artela/aspect/query_grpc.pb.go b/api/artela/aspect/query_grpc.pb.go new file mode 100644 index 0000000..12cb522 --- /dev/null +++ b/api/artela/aspect/query_grpc.pb.go @@ -0,0 +1,112 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: artela/aspect/query.proto + +package aspect + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Query_Params_FullMethodName = "/artela.aspect.Query/Params" +) + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QueryClient interface { + // Parameters queries the parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc.ClientConnInterface +} + +func NewQueryClient(cc grpc.ClientConnInterface) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, Query_Params_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +// All implementations must embed UnimplementedQueryServer +// for forward compatibility +type QueryServer interface { + // Parameters queries the parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + mustEmbedUnimplementedQueryServer() +} + +// UnimplementedQueryServer must be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {} + +// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QueryServer will +// result in compilation errors. +type UnsafeQueryServer interface { + mustEmbedUnimplementedQueryServer() +} + +func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) { + s.RegisterService(&Query_ServiceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_Params_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Query_ServiceDesc is the grpc.ServiceDesc for Query service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Query_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "artela.aspect.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "artela/aspect/query.proto", +} diff --git a/api/artela/aspect/tx.pulsar.go b/api/artela/aspect/tx.pulsar.go new file mode 100644 index 0000000..874f450 --- /dev/null +++ b/api/artela/aspect/tx.pulsar.go @@ -0,0 +1,1089 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package aspect + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + _ "cosmossdk.io/api/amino" + _ "cosmossdk.io/api/cosmos/msg/v1" + _ "github.com/cosmos/cosmos-proto" + runtime "github.com/cosmos/cosmos-proto/runtime" + _ "github.com/cosmos/gogoproto/gogoproto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +var ( + md_MsgUpdateParams protoreflect.MessageDescriptor + fd_MsgUpdateParams_authority protoreflect.FieldDescriptor + fd_MsgUpdateParams_params protoreflect.FieldDescriptor +) + +func init() { + file_artela_aspect_tx_proto_init() + md_MsgUpdateParams = File_artela_aspect_tx_proto.Messages().ByName("MsgUpdateParams") + fd_MsgUpdateParams_authority = md_MsgUpdateParams.Fields().ByName("authority") + fd_MsgUpdateParams_params = md_MsgUpdateParams.Fields().ByName("params") +} + +var _ protoreflect.Message = (*fastReflection_MsgUpdateParams)(nil) + +type fastReflection_MsgUpdateParams MsgUpdateParams + +func (x *MsgUpdateParams) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgUpdateParams)(x) +} + +func (x *MsgUpdateParams) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_tx_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgUpdateParams_messageType fastReflection_MsgUpdateParams_messageType +var _ protoreflect.MessageType = fastReflection_MsgUpdateParams_messageType{} + +type fastReflection_MsgUpdateParams_messageType struct{} + +func (x fastReflection_MsgUpdateParams_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgUpdateParams)(nil) +} +func (x fastReflection_MsgUpdateParams_messageType) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParams) +} +func (x fastReflection_MsgUpdateParams_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParams +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgUpdateParams) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParams +} + +// 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_MsgUpdateParams) Type() protoreflect.MessageType { + return _fastReflection_MsgUpdateParams_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgUpdateParams) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParams) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgUpdateParams) Interface() protoreflect.ProtoMessage { + return (*MsgUpdateParams)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgUpdateParams) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Authority != "" { + value := protoreflect.ValueOfString(x.Authority) + if !f(fd_MsgUpdateParams_authority, value) { + return + } + } + if x.Params != nil { + value := protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + if !f(fd_MsgUpdateParams_params, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgUpdateParams) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "artela.aspect.MsgUpdateParams.authority": + return x.Authority != "" + case "artela.aspect.MsgUpdateParams.params": + return x.Params != nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "artela.aspect.MsgUpdateParams.authority": + x.Authority = "" + case "artela.aspect.MsgUpdateParams.params": + x.Params = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "artela.aspect.MsgUpdateParams.authority": + value := x.Authority + return protoreflect.ValueOfString(value) + case "artela.aspect.MsgUpdateParams.params": + value := x.Params + return protoreflect.ValueOfMessage(value.ProtoReflect()) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "artela.aspect.MsgUpdateParams.authority": + x.Authority = value.Interface().(string) + case "artela.aspect.MsgUpdateParams.params": + x.Params = value.Message().Interface().(*Params) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.MsgUpdateParams.params": + if x.Params == nil { + x.Params = new(Params) + } + return protoreflect.ValueOfMessage(x.Params.ProtoReflect()) + case "artela.aspect.MsgUpdateParams.authority": + panic(fmt.Errorf("field authority of message artela.aspect.MsgUpdateParams is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "artela.aspect.MsgUpdateParams.authority": + return protoreflect.ValueOfString("") + case "artela.aspect.MsgUpdateParams.params": + m := new(Params) + return protoreflect.ValueOfMessage(m.ProtoReflect()) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParams")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParams 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_MsgUpdateParams) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.MsgUpdateParams", 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_MsgUpdateParams) 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_MsgUpdateParams) 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_MsgUpdateParams) 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_MsgUpdateParams) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgUpdateParams) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Authority) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Params != nil { + l = options.Size(x.Params) + 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().(*MsgUpdateParams) + 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 x.Params != nil { + encoded, err := options.Marshal(x.Params) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + if len(x.Authority) > 0 { + i -= len(x.Authority) + copy(dAtA[i:], x.Authority) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Authority))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgUpdateParams) + 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: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Authority", 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.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Params", 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.Params == nil { + x.Params = &Params{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Params); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgUpdateParamsResponse protoreflect.MessageDescriptor +) + +func init() { + file_artela_aspect_tx_proto_init() + md_MsgUpdateParamsResponse = File_artela_aspect_tx_proto.Messages().ByName("MsgUpdateParamsResponse") +} + +var _ protoreflect.Message = (*fastReflection_MsgUpdateParamsResponse)(nil) + +type fastReflection_MsgUpdateParamsResponse MsgUpdateParamsResponse + +func (x *MsgUpdateParamsResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgUpdateParamsResponse)(x) +} + +func (x *MsgUpdateParamsResponse) slowProtoReflect() protoreflect.Message { + mi := &file_artela_aspect_tx_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgUpdateParamsResponse_messageType fastReflection_MsgUpdateParamsResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgUpdateParamsResponse_messageType{} + +type fastReflection_MsgUpdateParamsResponse_messageType struct{} + +func (x fastReflection_MsgUpdateParamsResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgUpdateParamsResponse)(nil) +} +func (x fastReflection_MsgUpdateParamsResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParamsResponse) +} +func (x fastReflection_MsgUpdateParamsResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParamsResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgUpdateParamsResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgUpdateParamsResponse +} + +// 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_MsgUpdateParamsResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgUpdateParamsResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgUpdateParamsResponse) New() protoreflect.Message { + return new(fastReflection_MsgUpdateParamsResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgUpdateParamsResponse) Interface() protoreflect.ProtoMessage { + return (*MsgUpdateParamsResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgUpdateParamsResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// 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_MsgUpdateParamsResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: artela.aspect.MsgUpdateParamsResponse")) + } + panic(fmt.Errorf("message artela.aspect.MsgUpdateParamsResponse 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_MsgUpdateParamsResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in artela.aspect.MsgUpdateParamsResponse", 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_MsgUpdateParamsResponse) 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_MsgUpdateParamsResponse) 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_MsgUpdateParamsResponse) 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_MsgUpdateParamsResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgUpdateParamsResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.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().(*MsgUpdateParamsResponse) + 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 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().(*MsgUpdateParamsResponse) + 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: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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: artela/aspect/tx.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) +) + +// MsgUpdateParams is the Msg/UpdateParams request type. +type MsgUpdateParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the module parameters to update. + // + // NOTE: All parameters must be supplied. + Params *Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"` +} + +func (x *MsgUpdateParams) Reset() { + *x = MsgUpdateParams{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_tx_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgUpdateParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgUpdateParams) ProtoMessage() {} + +// Deprecated: Use MsgUpdateParams.ProtoReflect.Descriptor instead. +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return file_artela_aspect_tx_proto_rawDescGZIP(), []int{0} +} + +func (x *MsgUpdateParams) GetAuthority() string { + if x != nil { + return x.Authority + } + return "" +} + +func (x *MsgUpdateParams) GetParams() *Params { + if x != nil { + return x.Params + } + return nil +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +type MsgUpdateParamsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MsgUpdateParamsResponse) Reset() { + *x = MsgUpdateParamsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_artela_aspect_tx_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgUpdateParamsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgUpdateParamsResponse) ProtoMessage() {} + +// Deprecated: Use MsgUpdateParamsResponse.ProtoReflect.Descriptor instead. +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return file_artela_aspect_tx_proto_rawDescGZIP(), []int{1} +} + +var File_artela_aspect_tx_proto protoreflect.FileDescriptor + +var file_artela_aspect_tx_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, + 0x74, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, + 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, + 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2f, 0x6d, 0x73, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x73, 0x67, 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, 0x14, + 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xb7, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 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, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x38, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x32, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, 0xb0, 0x2a, 0x1f, 0x61, 0x72, 0x74, 0x65, 0x6c, + 0x61, 0x2f, 0x78, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, 0x4d, 0x73, 0x67, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, + 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x64, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x56, 0x0a, 0x0c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x2e, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x4d, 0x73, 0x67, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x26, 0x2e, 0x61, + 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x4d, 0x73, 0x67, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, 0xa5, 0x01, 0x0a, 0x11, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, 0x61, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2d, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2f, 0x61, 0x73, 0x70, 0x65, 0x63, 0x74, + 0xa2, 0x02, 0x03, 0x41, 0x41, 0x58, 0xaa, 0x02, 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x2e, + 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xca, 0x02, 0x0d, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x5c, + 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0xe2, 0x02, 0x19, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x5c, + 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x0e, 0x41, 0x72, 0x74, 0x65, 0x6c, 0x61, 0x3a, 0x3a, 0x41, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_artela_aspect_tx_proto_rawDescOnce sync.Once + file_artela_aspect_tx_proto_rawDescData = file_artela_aspect_tx_proto_rawDesc +) + +func file_artela_aspect_tx_proto_rawDescGZIP() []byte { + file_artela_aspect_tx_proto_rawDescOnce.Do(func() { + file_artela_aspect_tx_proto_rawDescData = protoimpl.X.CompressGZIP(file_artela_aspect_tx_proto_rawDescData) + }) + return file_artela_aspect_tx_proto_rawDescData +} + +var file_artela_aspect_tx_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_artela_aspect_tx_proto_goTypes = []interface{}{ + (*MsgUpdateParams)(nil), // 0: artela.aspect.MsgUpdateParams + (*MsgUpdateParamsResponse)(nil), // 1: artela.aspect.MsgUpdateParamsResponse + (*Params)(nil), // 2: artela.aspect.Params +} +var file_artela_aspect_tx_proto_depIdxs = []int32{ + 2, // 0: artela.aspect.MsgUpdateParams.params:type_name -> artela.aspect.Params + 0, // 1: artela.aspect.Msg.UpdateParams:input_type -> artela.aspect.MsgUpdateParams + 1, // 2: artela.aspect.Msg.UpdateParams:output_type -> artela.aspect.MsgUpdateParamsResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_artela_aspect_tx_proto_init() } +func file_artela_aspect_tx_proto_init() { + if File_artela_aspect_tx_proto != nil { + return + } + file_artela_aspect_params_proto_init() + if !protoimpl.UnsafeEnabled { + file_artela_aspect_tx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgUpdateParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_artela_aspect_tx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgUpdateParamsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_artela_aspect_tx_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_artela_aspect_tx_proto_goTypes, + DependencyIndexes: file_artela_aspect_tx_proto_depIdxs, + MessageInfos: file_artela_aspect_tx_proto_msgTypes, + }.Build() + File_artela_aspect_tx_proto = out.File + file_artela_aspect_tx_proto_rawDesc = nil + file_artela_aspect_tx_proto_goTypes = nil + file_artela_aspect_tx_proto_depIdxs = nil +} diff --git a/api/artela/aspect/tx_grpc.pb.go b/api/artela/aspect/tx_grpc.pb.go new file mode 100644 index 0000000..38de9ea --- /dev/null +++ b/api/artela/aspect/tx_grpc.pb.go @@ -0,0 +1,114 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: artela/aspect/tx.proto + +package aspect + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Msg_UpdateParams_FullMethodName = "/artela.aspect.Msg/UpdateParams" +) + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MsgClient interface { + // UpdateParams defines a (governance) operation for updating the module + // parameters. The authority defaults to the x/gov module account. + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc.ClientConnInterface +} + +func NewMsgClient(cc grpc.ClientConnInterface) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, Msg_UpdateParams_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +// All implementations must embed UnimplementedMsgServer +// for forward compatibility +type MsgServer interface { + // UpdateParams defines a (governance) operation for updating the module + // parameters. The authority defaults to the x/gov module account. + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + mustEmbedUnimplementedMsgServer() +} + +// UnimplementedMsgServer must be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (UnimplementedMsgServer) UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} +func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {} + +// UnsafeMsgServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MsgServer will +// result in compilation errors. +type UnsafeMsgServer interface { + mustEmbedUnimplementedMsgServer() +} + +func RegisterMsgServer(s grpc.ServiceRegistrar, srv MsgServer) { + s.RegisterService(&Msg_ServiceDesc, srv) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_UpdateParams_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +// Msg_ServiceDesc is the grpc.ServiceDesc for Msg service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Msg_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "artela.aspect.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "artela/aspect/tx.proto", +} diff --git a/app/ante/decorator.go b/app/ante/decorator.go index 37fb80b..8d8946a 100644 --- a/app/ante/decorator.go +++ b/app/ante/decorator.go @@ -34,6 +34,7 @@ type AnteDecorators struct { // StakingKeeper vestingtypes.StakingKeeper FeeKeeper interfaces.FeeKeeper EvmKeeper interfaces.EVMKeeper + AspectKeeper interfaces.AspectKeeper FeegrantKeeper ante.FeegrantKeeper ExtensionOptionChecker ante.ExtensionOptionChecker SignModeHandler *txs.HandlerMap @@ -65,6 +66,9 @@ func (options AnteDecorators) Validate() error { if options.EvmKeeper == nil { return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler") } + if options.AspectKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "aspect keeper is required for AnteHandler") + } if options.SigGasConsumer == nil { return errorsmod.Wrap(errortypes.ErrLogic, "signature gas consumer is required for AnteHandler") } diff --git a/app/ante/evm/aspect_context.go b/app/ante/evm/aspect_context.go index d9244b2..40121fb 100644 --- a/app/ante/evm/aspect_context.go +++ b/app/ante/evm/aspect_context.go @@ -13,7 +13,7 @@ import ( inherent "github.com/artela-network/aspect-core/chaincoreext/jit_inherent" "github.com/artela-network/artela-rollkit/app/interfaces" - "github.com/artela-network/artela-rollkit/x/evm/artela/provider" + "github.com/artela-network/artela-rollkit/x/aspect/provider" "github.com/artela-network/artela-rollkit/x/evm/artela/types" "github.com/artela-network/artela-rollkit/x/evm/states" evmmodule "github.com/artela-network/artela-rollkit/x/evm/types" diff --git a/app/app.go b/app/app.go index a139192..1bdbdc6 100644 --- a/app/app.go +++ b/app/app.go @@ -84,12 +84,22 @@ import ( "github.com/artela-network/artela-rollkit/common" srvflags "github.com/artela-network/artela-rollkit/ethereum/server/flags" artela "github.com/artela-network/artela-rollkit/ethereum/types" + aspectmodulekeeper "github.com/artela-network/artela-rollkit/x/aspect/keeper" evmmodulekeeper "github.com/artela-network/artela-rollkit/x/evm/keeper" "github.com/artela-network/artela-rollkit/x/evm/types" feemodulekeeper "github.com/artela-network/artela-rollkit/x/fee/keeper" + // this line is used by starport scaffolding # stargate/app/moduleImport "github.com/artela-network/artela-rollkit/docs" + + // do not remove this, this will register the native evm tracers + _ "github.com/artela-network/artela-evm/tracers/native" + _ "github.com/ethereum/go-ethereum/eth/tracers/js" + + // aspect related imports + _ "github.com/artela-network/artela-rollkit/x/aspect/store/v0" + _ "github.com/artela-network/artela-rollkit/x/aspect/store/v1" ) const ( @@ -158,8 +168,9 @@ type App struct { ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper ScopedICAHostKeeper capabilitykeeper.ScopedKeeper - EvmKeeper *evmmodulekeeper.Keeper - FeeKeeper feemodulekeeper.Keeper + EvmKeeper *evmmodulekeeper.Keeper + FeeKeeper feemodulekeeper.Keeper + AspectKeeper aspectmodulekeeper.Keeper // this line is used by starport scaffolding # stargate/app/keeperDeclaration // simulation manager @@ -315,6 +326,7 @@ func New( &app.CircuitBreakerKeeper, &app.FeeKeeper, &app.EvmKeeper, + &app.AspectKeeper, // this line is used by starport scaffolding # stargate/app/keeperDefinition ); err != nil { panic(err) @@ -460,6 +472,7 @@ func (app *App) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) { BankKeeper: app.BankKeeper, ExtensionOptionChecker: artela.HasDynamicFeeExtensionOption, EvmKeeper: app.EvmKeeper, + AspectKeeper: app.AspectKeeper, FeegrantKeeper: app.FeeGrantKeeper, DistributionKeeper: app.DistrKeeper, FeeKeeper: app.FeeKeeper, diff --git a/app/app_config.go b/app/app_config.go index 24b3518..9de7e96 100644 --- a/app/app_config.go +++ b/app/app_config.go @@ -11,6 +11,10 @@ import ( _ "github.com/artela-network/artela-rollkit/x/fee/module" // import for side-effects feemoduletypes "github.com/artela-network/artela-rollkit/x/fee/types" + aspectmodulev1 "github.com/artela-network/artela-rollkit/api/artela/aspect/module" + _ "github.com/artela-network/artela-rollkit/x/aspect/module" // import for side-effects + aspectmoduletypes "github.com/artela-network/artela-rollkit/x/aspect/types" + _ "github.com/artela-network/artela-rollkit/ethereum/types" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" @@ -84,6 +88,7 @@ var ( minttypes.ModuleName, crisistypes.ModuleName, evmmoduletypes.ModuleName, + aspectmoduletypes.ModuleName, feemoduletypes.ModuleName, ibcexported.ModuleName, genutiltypes.ModuleName, @@ -113,6 +118,7 @@ var ( upgradetypes.ModuleName, feemoduletypes.ModuleName, evmmoduletypes.ModuleName, + aspectmoduletypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, @@ -144,6 +150,7 @@ var ( govtypes.ModuleName, stakingtypes.ModuleName, evmmoduletypes.ModuleName, + aspectmoduletypes.ModuleName, feemoduletypes.ModuleName, feegrant.ModuleName, group.ModuleName, @@ -332,6 +339,10 @@ var ( Name: feemoduletypes.ModuleName, Config: appconfig.WrapAny(&feemodulev1.Module{}), }, + { + Name: aspectmoduletypes.ModuleName, + Config: appconfig.WrapAny(&aspectmodulev1.Module{}), + }, // this line is used by starport scaffolding # stargate/app/moduleConfig }, }) diff --git a/app/interfaces/interfaces.go b/app/interfaces/interfaces.go index 69f375d..ee4ef25 100644 --- a/app/interfaces/interfaces.go +++ b/app/interfaces/interfaces.go @@ -33,10 +33,11 @@ type EVMKeeper interface { VerifySig(ctx cosmos.Context, tx *ethereum.Transaction) (common.Address, []byte, error) EVMConfigFromCtx(ctx cosmos.Context) (*states.EVMConfig, error) GetBlockContext() *artvmtype.EthBlockContext - GetAspectRuntimeContext() *artvmtype.AspectRuntimeContext MakeSigner(ctx cosmos.Context, tx *ethereum.Transaction, config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) ethereum.Signer } +type AspectKeeper interface{} + type FeeKeeper interface { GetParams(ctx cosmos.Context) (params feemodule.Params) AddTransientGasWanted(ctx context.Context, gasWanted uint64) (uint64, error) diff --git a/cmd/artrolld/cmd/root.go b/cmd/artrolld/cmd/root.go index eb4fb74..6696b7d 100644 --- a/cmd/artrolld/cmd/root.go +++ b/cmd/artrolld/cmd/root.go @@ -25,6 +25,7 @@ import ( "github.com/spf13/pflag" "github.com/artela-network/artela-rollkit/app" + artelakeyring "github.com/artela-network/artela-rollkit/ethereum/crypto/keyring" evmmoduletypes "github.com/artela-network/artela-rollkit/x/evm/types" ) @@ -161,6 +162,7 @@ func ProvideClientContext( WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). WithHomeDir(app.DefaultNodeHome). + WithKeyringOptions(artelakeyring.Option()). WithViper(app.Name) // env variable prefix // Read the config again to overwrite the default values with the values from the config file diff --git a/common/aspect/aspect_abi_test.go b/common/aspect/aspect_abi_test.go index 2adc8dd..ff4d658 100644 --- a/common/aspect/aspect_abi_test.go +++ b/common/aspect/aspect_abi_test.go @@ -6,17 +6,13 @@ import ( "reflect" "testing" - pq "github.com/emirpasic/gods/queues/priorityqueue" "github.com/emirpasic/gods/sets/treeset" - "github.com/holiman/uint256" jsoniter "github.com/json-iterator/go" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - - "github.com/artela-network/artela-rollkit/x/evm/artela/types" ) func TestAbi(t *testing.T) { @@ -102,55 +98,6 @@ func TestPack(t *testing.T) { fmt.Println(properties) } -func TestAspectsOfPack(t *testing.T) { - ma := make(map[string]interface{}, 2) - ma[types.AspectIDMapKey] = "1111" - ma[types.VersionMapKey] = 0 - ma[types.PriorityMapKey] = 1 - mb := make(map[string]interface{}, 2) - mb[types.AspectIDMapKey] = "2222" - mb[types.VersionMapKey] = 1 - mb[types.PriorityMapKey] = -10 - mc := make(map[string]interface{}, 2) - mc[types.AspectIDMapKey] = "3333" - mc[types.VersionMapKey] = 2 - mc[types.PriorityMapKey] = 3 - - queue := pq.NewWith(types.ByMapKeyPriority) // empty - queue.Enqueue(ma) // {a 1} - queue.Enqueue(mb) // {c 3}, {a 1} - queue.Enqueue(mc) - - outputs := make([]types.AspectMeta, 0) - iterator := queue.Iterator() - - for iterator.Next() { - m := iterator.Value().(map[string]interface{}) - e := types.AspectMeta{ - Id: common.HexToAddress(m[types.AspectIDMapKey].(string)), - Priority: int64(m[types.PriorityMapKey].(int)), - Version: uint256.NewInt(m[types.VersionMapKey].(uint64)), - } - outputs = append(outputs, e) - } - pack, err := methods["AspectsOf"].Outputs.Pack(outputs) - if err != nil { - fmt.Println("pack error", err) - } - maps := make(map[string]interface{}, 0) - err2 := methods["AspectsOf"].Outputs.UnpackIntoMap(maps, pack) - if err2 != nil { - fmt.Println("pack error", err2) - } - fmt.Println("unpack==", maps) - aspects := maps["aspectBoundInfo"].([]struct { - AspectId common.Address `json:"AspectId"` - Version uint64 `json:"Version"` - Priority int8 `json:"Priority"` - }) - fmt.Println(aspects) -} - func TestContractOfPack(t *testing.T) { treeset := treeset.NewWithStringComparator() treeset.Add("aaaaaaa") diff --git a/ethereum/rpc/account.go b/ethereum/rpc/account.go deleted file mode 100644 index 37d8076..0000000 --- a/ethereum/rpc/account.go +++ /dev/null @@ -1,320 +0,0 @@ -package rpc - -import ( - "errors" - "fmt" - "math/big" - "time" - - "github.com/cosmos/cosmos-sdk/types/tx/signing" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - sdkmath "cosmossdk.io/math" - sdkcrypto "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdktypes "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/artela-network/artela-rollkit/ethereum/crypto/ethsecp256k1" - "github.com/artela-network/artela-rollkit/ethereum/crypto/hd" - ethapi2 "github.com/artela-network/artela-rollkit/ethereum/rpc/ethapi" - "github.com/artela-network/artela-rollkit/ethereum/rpc/types" - types2 "github.com/artela-network/artela-rollkit/ethereum/types" - "github.com/artela-network/artela-rollkit/ethereum/utils" - evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" -) - -func (b *BackendImpl) Accounts() []common.Address { - addresses := make([]common.Address, 0) // return [] instead of nil if empty - - infos, err := b.clientCtx.Keyring.List() - if err != nil { - b.logger.Info("keying list failed", "error", err) - return nil - } - - for _, info := range infos { - pubKey, err := info.GetPubKey() - if err != nil { - b.logger.Info("getPubKey failed", "info", info, "error", err) - return nil - } - addressBytes := pubKey.Address().Bytes() - addresses = append(addresses, common.BytesToAddress(addressBytes)) - } - - return addresses -} - -func (b *BackendImpl) NewAccount(password string) (common.AddressEIP55, error) { - name := "key_" + time.Now().UTC().Format(time.RFC3339) - - cfg := sdktypes.GetConfig() - basePath := cfg.GetFullBIP44Path() - - hdPathIter, err := types2.NewHDPathIterator(basePath, true) - if err != nil { - b.logger.Info("NewHDPathIterator failed", "error", err) - return common.AddressEIP55{}, err - } - // create the mnemonic and save the account - hdPath := hdPathIter() - - info, _, err := b.clientCtx.Keyring.NewMnemonic(name, keyring.English, hdPath.String(), password, hd.EthSecp256k1) - if err != nil { - b.logger.Info("NewMnemonic failed", "error", err) - return common.AddressEIP55{}, err - } - - pubKey, err := info.GetPubKey() - if err != nil { - b.logger.Info("GetPubKey failed", "error", err) - return common.AddressEIP55{}, err - } - addr := common.BytesToAddress(pubKey.Address().Bytes()) - return common.AddressEIP55(addr), nil -} - -func (b *BackendImpl) ImportRawKey(privkey, password string) (common.Address, error) { - priv, err := crypto.HexToECDSA(privkey) - if err != nil { - return common.Address{}, err - } - - privKey := ðsecp256k1.PrivKey{Key: crypto.FromECDSA(priv)} - - addr := sdktypes.AccAddress(privKey.PubKey().Address().Bytes()) - ethereumAddr := common.BytesToAddress(addr) - - // return if the key has already been imported - if _, err := b.clientCtx.Keyring.KeyByAddress(addr); err == nil { - return ethereumAddr, nil - } - - // ignore error as we only care about the length of the list - list, _ := b.clientCtx.Keyring.List() // #nosec G703 - privKeyName := fmt.Sprintf("personal_%d", len(list)) - - armor := sdkcrypto.EncryptArmorPrivKey(privKey, password, ethsecp256k1.KeyType) - - if err := b.clientCtx.Keyring.ImportPrivKey(privKeyName, armor, password); err != nil { - return common.Address{}, err - } - - return ethereumAddr, nil -} - -func (b *BackendImpl) SignTransaction(args *ethapi2.TransactionArgs) (*ethtypes.Transaction, error) { - _, err := b.clientCtx.Keyring.KeyByAddress(sdktypes.AccAddress(args.From.Bytes())) - if err != nil { - return nil, fmt.Errorf("failed to find key in the node's keyring; %s; %s", keystore.ErrNoMatch, err.Error()) - } - - if args.ChainID != nil && (b.chainID).Cmp((*big.Int)(args.ChainID)) != 0 { - return nil, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", args.ChainID, (*hexutil.Big)(b.chainID)) - } - - bn, err := b.BlockNumber() - if err != nil { - return nil, err - } - - bt, err := b.BlockTimeByNumber(int64(bn)) - if err != nil { - return nil, err - } - - cfg, err := b.chainConfig() - if err != nil { - return nil, err - } - signer := ethtypes.MakeSigner(cfg, new(big.Int).SetUint64(uint64(bn)), bt) - - // LegacyTx derives chainID from the signature. To make sure the msg.ValidateBasic makes - // the corresponding chainID validation, we need to sign the transaction before calling it - - // Sign transaction - msg := args.ToEVMTransaction() - return msg.SignEthereumTx(signer, b.clientCtx.Keyring) -} - -// Sign signs the provided data using the private key of address via Geth's signature standard. -func (b *BackendImpl) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { - from := sdktypes.AccAddress(address.Bytes()) - - _, err := b.clientCtx.Keyring.KeyByAddress(from) - if err != nil { - return nil, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error()) - } - - // Sign the requested hash with the wallet - signature, _, err := b.clientCtx.Keyring.SignByAddress(from, data, signing.SignMode_SIGN_MODE_DIRECT) - if err != nil { - return nil, err - } - - signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper - return signature, nil -} - -func (b *BackendImpl) GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { - n := hexutil.Uint64(0) - height, err := b.blockNumberFromCosmos(blockNrOrHash) - if err != nil { - return &n, err - } - header, err := b.CurrentHeader() - if err != nil { - return &n, err - } - if height.Int64() > header.Number.Int64() { - return &n, fmt.Errorf( - "cannot query with height in the future (current: %d, queried: %d); please provide a valid height", - header.Number, height) - } - // Get nonce (sequence) from account - from := sdktypes.AccAddress(address.Bytes()) - accRet := b.clientCtx.AccountRetriever - - if err = accRet.EnsureExists(b.clientCtx, from); err != nil { - // account doesn't exist yet, return 0 - b.logger.Info("GetTransactionCount faild, return 0. Account doesn't exist yet", "account", address.Hex(), "error", err) - return &n, nil - } - - includePending := height == rpc.PendingBlockNumber - nonce, err := b.getAccountNonce(address, includePending, height.Int64()) - if err != nil { - return nil, err - } - - n = hexutil.Uint64(nonce) - return &n, nil -} - -func (b *BackendImpl) getAccountNonce(accAddr common.Address, pending bool, height int64) (uint64, error) { - queryClient := authtypes.NewQueryClient(b.clientCtx) - adr := sdktypes.AccAddress(accAddr.Bytes()).String() - ctx := types.ContextWithHeight(height) - res, err := queryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: adr}) - if err != nil { - st, ok := status.FromError(err) - // treat as account doesn't exist yet - if ok && st.Code() == codes.NotFound { - b.logger.Info("getAccountNonce faild, account not found", "error", err) - return 0, nil - } - return 0, err - } - var acc authtypes.AccountI - if err := b.clientCtx.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { - return 0, err - } - - nonce := acc.GetSequence() - - if !pending { - return nonce, nil - } - - // the account retriever doesn't include the uncommitted transactions on the nonce so we need to - // to manually add them. - pendingTxs, err := b.PendingTransactions() - if err != nil { - return nonce, nil - } - - // add the uncommitted txs to the nonce counter - // only supports `MsgEthereumTx` style tx - for _, tx := range pendingTxs { - for _, msg := range (*tx).GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - // not ethereum tx - break - } - - sender, err := b.GetSender(ethMsg, b.chainID) - if err != nil { - continue - } - if sender == accAddr { - nonce++ - } - } - } - - return nonce, nil -} - -func (b *BackendImpl) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { - blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) - if err != nil { - return nil, err - } - - req := &evmtypes.QueryBalanceRequest{ - Address: address.String(), - } - - _, err = b.CosmosBlockByNumber(blockNum) - if err != nil { - return nil, err - } - - res, err := b.queryClient.Balance(types.ContextWithHeight(blockNum.Int64()), req) - if err != nil { - return nil, err - } - - val, ok := sdkmath.NewIntFromString(res.Balance) - if !ok { - return nil, errors.New("invalid balance") - } - - if val.IsNegative() { - return nil, errors.New("couldn't fetch balance. Node state is pruned") - } - - return (*hexutil.Big)(val.BigInt()), nil -} - -// GetSender extracts the sender address from the signature values using the latest signer for the given chainID. -func (b *BackendImpl) GetSender(msg *evmtypes.MsgEthereumTx, chainID *big.Int) (from common.Address, err error) { - if msg.From != "" { - return common.HexToAddress(msg.From), nil - } - - tx := msg.AsTransaction() - // retrieve sender info from aspect if tx is not signed - if utils.IsCustomizedVerification(tx) { - bn, err := b.BlockNumber() - if err != nil { - return common.Address{}, err - } - ctx := types.ContextWithHeight(int64(bn)) - - res, err := b.queryClient.GetSender(ctx, msg) - if err != nil { - return common.Address{}, err - } - - from = common.HexToAddress(res.Sender) - } else { - signer := ethtypes.LatestSignerForChainID(chainID) - from, err = signer.Sender(tx) - if err != nil { - return common.Address{}, err - } - } - - msg.From = from.Hex() - return from, nil -} diff --git a/ethereum/rpc/ethapi/addrlock.go b/ethereum/rpc/api/addrlock.go similarity index 98% rename from ethereum/rpc/ethapi/addrlock.go rename to ethereum/rpc/api/addrlock.go index 5bc5bbc..05471a5 100644 --- a/ethereum/rpc/ethapi/addrlock.go +++ b/ethereum/rpc/api/addrlock.go @@ -1,4 +1,4 @@ -package ethapi +package api import ( "sync" diff --git a/ethereum/rpc/ethapi/dbapi.go b/ethereum/rpc/api/dbapi.go similarity index 98% rename from ethereum/rpc/ethapi/dbapi.go rename to ethereum/rpc/api/dbapi.go index 1675375..f78b84e 100644 --- a/ethereum/rpc/ethapi/dbapi.go +++ b/ethereum/rpc/api/dbapi.go @@ -1,4 +1,4 @@ -package ethapi +package api import ( "errors" diff --git a/ethereum/rpc/api/debug.go b/ethereum/rpc/api/debug.go index 059df60..1044d8b 100644 --- a/ethereum/rpc/api/debug.go +++ b/ethereum/rpc/api/debug.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "fmt" "io" "os" "os/user" @@ -18,33 +19,20 @@ import ( stderrors "github.com/pkg/errors" - "github.com/cometbft/cometbft/libs/log" - tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cosmos/cosmos-sdk/server" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - evmsupport "github.com/artela-network/artela-rollkit/x/evm/types" - + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" evmtxs "github.com/artela-network/artela-rollkit/x/evm/txs" + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" ) -type DebugBackend interface { - TraceTransaction(hash common.Hash, config *evmsupport.TraceConfig) (interface{}, error) - TraceBlock(height rpc.BlockNumber, - config *evmsupport.TraceConfig, - block *tmrpctypes.ResultBlock, - ) ([]*evmtxs.TxTraceResult, error) - CosmosBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) - CosmosBlockByNumber(blockNum rpc.BlockNumber) (*tmrpctypes.ResultBlock, error) - HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*ethtypes.Header, error) - BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*ethtypes.Block, error) -} - // HandlerT keeps track of the cpu profiler and trace execution type HandlerT struct { cpuFilename string @@ -58,49 +46,179 @@ type HandlerT struct { type DebugAPI struct { ctx *server.Context logger log.Logger - backend DebugBackend + b rpctypes.DebugBackend handler *HandlerT } // NewDebugAPI creates a new DebugAPI definition for the tracing methods of the Ethereum service. func NewDebugAPI( - backend DebugBackend, + backend rpctypes.DebugBackend, + logger log.Logger, + ctx *server.Context, ) *DebugAPI { return &DebugAPI{ - backend: backend, + b: backend, handler: new(HandlerT), + logger: logger, + ctx: ctx, + } +} + +// GetRawHeader retrieves the RLP encoding for a single header. +func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + header, err := api.b.HeaderByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if header == nil { + return nil, fmt.Errorf("block not found") + } + return rlp.EncodeToBytes(header) +} + +// GetRawBlock retrieves the RLP encoded for a single block. +func (api *DebugAPI) GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + block, err := api.b.ArtBlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if block == nil { + return nil, fmt.Errorf("block not found") + } + + // marshal the eth block, be care that the block hash is not matched to + // what was saved in cosmos db. + return rlp.EncodeToBytes(block.EthBlock()) +} + +func (api *DebugAPI) GetReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (types.Receipts, error) { + block, err := api.b.ArtBlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if block == nil { + return nil, fmt.Errorf("block not found") + } + + return api.b.GetReceipts(ctx, block.Hash()) +} + +// GetRawReceipts retrieves the binary-encoded receipts of a single block. +func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) { + block, err := api.b.ArtBlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if block == nil { + return nil, fmt.Errorf("block not found") + } + + receipts, err := api.b.GetReceipts(ctx, block.Hash()) + if err != nil { + return nil, err + } + result := make([]hexutil.Bytes, len(receipts)) + for i, receipt := range receipts { + b, err := receipt.MarshalBinary() + if err != nil { + return nil, err + } + result[i] = b + } + return result, nil +} + +// GetRawTransaction returns the bytes of the transaction for the given hash. +func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + txMsg, err := api.b.GetTxMsg(ctx, hash) + if err != nil { + return nil, err + } + if txMsg == nil { + pendingTxs, err := api.b.PendingTransactions() + if err != nil { + return nil, nil + } + + cfg := api.b.ChainConfig() + if cfg == nil { + return nil, nil + } + + for _, pendingTx := range pendingTxs { + for _, msg := range (*pendingTx).GetMsgs() { + if ethMsg, ok := msg.(*evmtypes.MsgEthereumTx); ok { + if ethMsg.AsTransaction().Hash() == hash { + txMsg = ethMsg + } + } + } + } + } + return txMsg.AsTransaction().MarshalBinary() +} + +// PrintBlock retrieves a block and returns its pretty printed form. +func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { + block, _ := api.b.ArtBlockByNumber(ctx, rpc.BlockNumber(number)) + if block == nil { + return "", fmt.Errorf("block #%d not found", number) } + return spew.Sdump(block), nil +} + +// ChaindbProperty returns leveldb properties of the key-value database. +func (api *DebugAPI) ChaindbProperty(property string) (string, error) { + return api.b.DBProperty(property) +} + +// ChaindbCompact flattens the entire key-value database into a single level, +// removing all unused slots and merging all keys. +func (api *DebugAPI) ChaindbCompact() error { + for b := byte(0); b < 255; b++ { + api.logger.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1)) + if err := api.b.DBCompact([]byte{b}, []byte{b + 1}); err != nil { + api.logger.Error("Database compaction failed", "err", err) + return err + } + } + return nil +} + +// SetHead rewinds the head of the blockchain to a previous block. +func (api *DebugAPI) SetHead(_ hexutil.Uint64) { + // not support, for a cosmos chain, use rollback instead } // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. -func (a *DebugAPI) TraceTransaction(hash common.Hash, config evmsupport.TraceConfig) (interface{}, error) { - return a.backend.TraceTransaction(hash, &config) +func (a *DebugAPI) TraceTransaction(hash common.Hash, config evmtypes.TraceConfig) (interface{}, error) { + return a.b.TraceTransaction(hash, &config) } // TraceBlockByNumber returns the structured logs created during the execution of // EVM and returns them as a JSON object. -func (a *DebugAPI) TraceBlockByNumber(height rpc.BlockNumber, config evmsupport.TraceConfig) ([]*evmtxs.TxTraceResult, error) { +func (a *DebugAPI) TraceBlockByNumber(height rpc.BlockNumber, config evmtypes.TraceConfig) ([]*evmtxs.TxTraceResult, error) { a.logger.Debug("debug_traceBlockByNumber", "height", height) if height == 0 { return nil, errors.New("genesis is not traceable") } // Get Tendermint Block - resBlock, err := a.backend.CosmosBlockByNumber(height) + resBlock, err := a.b.CosmosBlockByNumber(height) if err != nil { a.logger.Debug("get block failed", "height", height, "error", err.Error()) return nil, err } - return a.backend.TraceBlock(rpc.BlockNumber(resBlock.Block.Height), &config, resBlock) + return a.b.TraceBlock(rpc.BlockNumber(resBlock.Block.Height), &config, resBlock) } // TraceBlockByHash returns the structured logs created during the execution of // EVM and returns them as a JSON object. -func (a *DebugAPI) TraceBlockByHash(hash common.Hash, config evmsupport.TraceConfig) ([]*evmtxs.TxTraceResult, error) { +func (a *DebugAPI) TraceBlockByHash(hash common.Hash, config evmtypes.TraceConfig) ([]*evmtxs.TxTraceResult, error) { a.logger.Debug("debug_traceBlockByHash", "hash", hash) // Get Tendermint Block - resBlock, err := a.backend.CosmosBlockByHash(hash) + resBlock, err := a.b.CosmosBlockByHash(hash) if err != nil { a.logger.Debug("get block failed", "hash", hash.Hex(), "error", err.Error()) return nil, err @@ -111,7 +229,7 @@ func (a *DebugAPI) TraceBlockByHash(hash common.Hash, config evmsupport.TraceCon return nil, errors.New("block not found") } - return a.backend.TraceBlock(rpc.BlockNumber(resBlock.Block.Height), &config, resBlock) + return a.b.TraceBlock(rpc.BlockNumber(resBlock.Block.Height), &config, resBlock) } // BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to @@ -300,7 +418,7 @@ func (a *DebugAPI) SetGCPercent(v int) int { // GetHeaderRlp retrieves the RLP encoded for of a single header. func (a *DebugAPI) GetHeaderRlp(number uint64) (hexutil.Bytes, error) { - header, err := a.backend.HeaderByNumber(context.TODO(), rpc.BlockNumber(number)) + header, err := a.b.HeaderByNumber(context.TODO(), rpc.BlockNumber(number)) if err != nil { return nil, err } @@ -310,32 +428,24 @@ func (a *DebugAPI) GetHeaderRlp(number uint64) (hexutil.Bytes, error) { // GetBlockRlp retrieves the RLP encoded for of a single block. func (a *DebugAPI) GetBlockRlp(number uint64) (hexutil.Bytes, error) { - block, err := a.backend.BlockByNumber(context.TODO(), rpc.BlockNumber(number)) + block, err := a.b.ArtBlockByNumber(context.TODO(), rpc.BlockNumber(number)) if err != nil { return nil, err } - return rlp.EncodeToBytes(block) -} - -// PrintBlock retrieves a block and returns its pretty printed form. -func (a *DebugAPI) PrintBlock(number uint64) (string, error) { - block, err := a.backend.BlockByNumber(context.TODO(), rpc.BlockNumber(number)) - if err != nil { - return "", err - } - - return spew.Sdump(block), nil + // marshal the eth block, be care that the block hash is not matched to + // what was saved in cosmos db. + return rlp.EncodeToBytes(block.EthBlock()) } // SeedHash retrieves the seed hash of a block. func (a *DebugAPI) SeedHash(_ uint64) (string, error) { - return "", errors.New("SeedHash is not implemented") + return "", errors.New("SeedHash is not valid") } // IntermediateRoots executes a block, and returns a list // of intermediate roots: the stateroot after each transaction. -func (a *DebugAPI) IntermediateRoots(hash common.Hash, _ *evmsupport.TraceConfig) ([]common.Hash, error) { +func (a *DebugAPI) IntermediateRoots(hash common.Hash, _ *evmtypes.TraceConfig) ([]common.Hash, error) { a.logger.Debug("debug_intermediateRoots", "hash", hash) return ([]common.Hash)(nil), nil } diff --git a/ethereum/rpc/ethapi/api.go b/ethereum/rpc/api/eth.go similarity index 57% rename from ethereum/rpc/ethapi/api.go rename to ethereum/rpc/api/eth.go index 78a5234..45e46ca 100644 --- a/ethereum/rpc/ethapi/api.go +++ b/ethereum/rpc/api/eth.go @@ -1,28 +1,20 @@ -package ethapi +package api import ( "context" "errors" "fmt" "math/big" - "time" - "github.com/davecgh/go-spew/spew" - - sdktypes "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/artela-network/artela-evm/vm" @@ -34,12 +26,12 @@ import ( // EthereumAPI provides an API to access Ethereum related information. type EthereumAPI struct { - b Backend + b rpctypes.EthereumBackend logger log.Logger } // NewEthereumAPI creates a new Ethereum protocol API. -func NewEthereumAPI(b Backend, logger log.Logger) *EthereumAPI { +func NewEthereumAPI(b rpctypes.EthereumBackend, logger log.Logger) *EthereumAPI { return &EthereumAPI{b, logger} } @@ -57,7 +49,15 @@ func (s *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. func (s *EthereumAPI) MaxPriorityFeePerGas(_ context.Context) (*hexutil.Big, error) { - return nil, errors.New("MaxPriorityFeePerGas is not implemented") + head, err := s.b.CurrentHeader() + if err != nil { + return nil, err + } + tipcap, err := s.b.SuggestGasTipCap(head.BaseFee) + if err != nil { + return nil, err + } + return (*hexutil.Big)(tipcap), nil } // FeeHistory returns the fee market history. @@ -77,49 +77,14 @@ func (s *EthereumAPI) Syncing() (interface{}, error) { return s.b.Syncing() } -// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non-confidential. -type TxPoolAPI struct { - b Backend -} - -// NewTxPoolAPI creates a new tx pool service that gives information about the transaction pool. -func NewTxPoolAPI(b Backend) *TxPoolAPI { - return &TxPoolAPI{b} -} - -// Content returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { - // not implemented - return nil -} - -// ContentFrom returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) ContentFrom(_ common.Address) map[string]map[string]*RPCTransaction { - // not implemented - return nil -} - -// Status returns the number of pending and queued transaction in the pool. -func (s *TxPoolAPI) Status() map[string]hexutil.Uint { - // not implemented - return nil -} - -// Inspect retrieves the content of the transaction pool and flattens it into an -// easily inspectable list. -func (s *TxPoolAPI) Inspect() map[string]map[string]map[string]string { - // not implemented - return nil -} - // EthereumAccountAPI provides an API to access accounts managed by this node. // It offers only methods that can retrieve accounts. type EthereumAccountAPI struct { - b Backend + b rpctypes.EthereumBackend } // NewEthereumAccountAPI creates a new EthereumAccountAPI. -func NewEthereumAccountAPI(b Backend) *EthereumAccountAPI { +func NewEthereumAccountAPI(b rpctypes.EthereumBackend) *EthereumAccountAPI { return &EthereumAccountAPI{b} } @@ -128,178 +93,14 @@ func (s *EthereumAccountAPI) Accounts() []common.Address { return s.b.Accounts() } -// PersonalAccountAPI provides an API to access accounts managed by this node. -// It offers methods to create, (un)lock en list accounts. Some methods accept -// passwords and are therefore considered private by default. -type PersonalAccountAPI struct { - nonceLock *AddrLocker - logger log.Logger - b Backend -} - -// NewPersonalAccountAPI create a new PersonalAccountAPI. -func NewPersonalAccountAPI(b Backend, logger log.Logger, nonceLock *AddrLocker) *PersonalAccountAPI { - return &PersonalAccountAPI{ - nonceLock: nonceLock, - logger: logger, - b: b, - } -} - -// ListAccounts will return a list of addresses for accounts this node manages. -func (s *PersonalAccountAPI) ListAccounts() []common.Address { - return s.b.Accounts() -} - -// rawWallet is a JSON representation of an accounts.Wallet interface, with its -// data contents extracted into plain fields. -type rawWallet struct { - URL string `json:"url"` - Status string `json:"status"` - Failure string `json:"failure,omitempty"` - Accounts []accounts.Account `json:"accounts,omitempty"` -} - -// ListWallets will return a list of wallets this node manages. -func (s *PersonalAccountAPI) ListWallets() []rawWallet { - // not implemented - wallets := make([]rawWallet, 0) // return [] instead of nil if empty - return wallets -} - -// OpenWallet initiates a hardware wallet opening procedure, establishing a USB -// connection and attempting to authenticate via the provided passphrase. Note, -// the method may return an extra challenge requiring a second open (e.g. the -// Trezor PIN matrix challenge). -func (s *PersonalAccountAPI) OpenWallet(_ string, _ *string) error { - return errors.New("OpenWallet is not implemented") -} - -// DeriveAccount requests an HD wallet to derive a new account, optionally pinning -// it for later reuse. -func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { - return accounts.Account{}, errors.New("DeriveAccount is not implemented") -} - -// NewAccount will create a new account and returns the address for the new account. -func (s *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { - return s.b.NewAccount(password) -} - -// ImportRawKey stores the given hex encoded ECDSA key into the key directory, -// encrypting it with the passphrase. -func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { - return s.b.ImportRawKey(privkey, password) -} - -// UnlockAccount will unlock the account associated with the given address with -// the given password for duration seconds. If duration is nil it will use a -// default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PersonalAccountAPI) UnlockAccount(_ context.Context, _ common.Address, _ string, duration *uint64) (bool, error) { - // not implemented - return false, errors.New("UnlockAccount is not implemented") -} - -// LockAccount will lock the account associated with the given address when it's unlocked. -func (s *PersonalAccountAPI) LockAccount(_ common.Address) bool { - // not implemented" - return false -} - -// signTransaction sets defaults and signs the given transaction -// NOTE: the caller needs to ensure that the nonceLock is held, if applicable, -// and release it after the transaction has been submitted to the tx pool -func (s *PersonalAccountAPI) signTransaction(_ context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { - // return s.b.SignTransaction(args, passwd) - // TODO - return nil, fmt.Errorf("signTransaction is not implemented, args: %v, passwd: %s", args, passwd) -} - -// SendTransaction will create a transaction from the given arguments and -// tries to sign it with the key associated with args.From. If the given -// passwd isn't able to decrypt the key it fails. -func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { - if args.Nonce == nil { - // Hold the mutex around signing to prevent concurrent assignment of - // the same nonce to multiple accounts. - s.nonceLock.LockAddr(args.from()) - defer s.nonceLock.UnlockAddr(args.from()) - } - signed, err := s.signTransaction(ctx, &args, passwd) - if err != nil { - log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) - return common.Hash{}, err - } - return SubmitTransaction(ctx, s.logger, s.b, signed) -} - -// SignTransaction will create a transaction from the given arguments and -// tries to sign it with the key associated with args.From. If the given passwd isn't -// able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast -// to other nodes -func (s *PersonalAccountAPI) SignTransaction(_ context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { - // TODO - return nil, fmt.Errorf("SignTransaction is not implemented, args: %v, passwd: %s", args, passwd) -} - -// Sign calculates an Ethereum ECDSA signature for: -// keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)) -// -// Note, the produced signature conforms to the secp256k1 curve R, S and V values, -// where the V value will be 27 or 28 for legacy reasons. -// -// The key used to calculate the signature is decrypted with the given password. -// -// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign -func (s *PersonalAccountAPI) Sign(_ context.Context, _ hexutil.Bytes, _ common.Address, _ string) (hexutil.Bytes, error) { - // TODO - return nil, errors.New("Sign is not implemented") -} - -// EcRecover returns the address for the account that was used to create the signature. -// Note, this function is compatible with eth_sign and personal_sign. As such it recovers -// the address of: -// hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message}) -// addr = ecrecover(hash, signature) -// -// Note, the signature must conform to the secp256k1 curve R, S and V values, where -// the V value must be 27 or 28 for legacy reasons. -// -// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover -func (s *PersonalAccountAPI) EcRecover(_ context.Context, data, sig hexutil.Bytes) (common.Address, error) { - if len(sig) != crypto.SignatureLength { - return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength) - } - if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 { - return common.Address{}, errors.New("invalid Ethereum signature (V is not 27 or 28)") - } - sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1 - - rpk, err := crypto.SigToPub(accounts.TextHash(data), sig) - if err != nil { - return common.Address{}, err - } - return crypto.PubkeyToAddress(*rpk), nil -} - -// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. -func (s *PersonalAccountAPI) InitializeWallet(_ context.Context, _ string) (string, error) { - return "", errors.New("InitializeWallet is not implemented") -} - -// Unpair deletes a pairing between wallet and geth. -func (s *PersonalAccountAPI) Unpair(_ context.Context, _ string, _ string) error { - return errors.New("unpair is not implemented") -} - // BlockChainAPI provides an API to access Ethereum blockchain data. type BlockChainAPI struct { logger log.Logger - b Backend + b rpctypes.BlockChainBackend } // NewBlockChainAPI creates a new Ethereum blockchain API. -func NewBlockChainAPI(b Backend, logger log.Logger) *BlockChainAPI { +func NewBlockChainAPI(b rpctypes.BlockChainBackend, logger log.Logger) *BlockChainAPI { return &BlockChainAPI{logger, b} } @@ -313,8 +114,14 @@ func (s *BlockChainAPI) ChainId() *hexutil.Big { return (*hexutil.Big)(s.b.ChainConfig().ChainID) } -func (s *BlockChainAPI) Coinbase() (sdktypes.AccAddress, error) { - return s.b.GetCoinbase() +func (s *BlockChainAPI) Coinbase() (common.Address, error) { + // coinbase return the operator address of the validator node + coinbase, err := s.b.GetCoinbase() + if err != nil { + return common.Address{}, err + } + ethAddr := common.BytesToAddress(coinbase.Bytes()) + return ethAddr, nil } // BlockNumber returns the block number of the chain head. @@ -480,6 +287,14 @@ func (s *BlockChainAPI) GetStorageAt(_ context.Context, address common.Address, return s.b.GetStorageAt(address, hexKey, blockNrOrHash) } +func (s *BlockChainAPI) GetDenomByAddress(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (string, error) { + return s.b.GetDenomByAddress(ctx, address, blockNrOrHash) +} + +func (s *BlockChainAPI) GetAddressByDenom(ctx context.Context, denom string, blockNrOrHash rpc.BlockNumberOrHash) ([]string, error) { + return s.b.GetAddressByDenom(ctx, denom, blockNrOrHash) +} + // OverrideAccount indicates the overriding fields of account during the execution // of a message call. // Note, states and stateDiff can't be specified at the same time. If states is @@ -613,7 +428,7 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H // // Note, this function doesn't make and changes in the states/blockchain and is // useful to execute and retrieve values. -func (s *BlockChainAPI) Call(_ context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, _ *StateOverride, _ *BlockOverrides) (hexutil.Bytes, error) { +func (s *BlockChainAPI) Call(_ context.Context, args rpctypes.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, _ *StateOverride, _ *BlockOverrides) (hexutil.Bytes, error) { data, err := s.b.DoCall(args, blockNrOrHash) if err != nil { return hexutil.Bytes{}, err @@ -624,7 +439,7 @@ func (s *BlockChainAPI) Call(_ context.Context, args TransactionArgs, blockNrOrH // EstimateGas returns an estimate of the amount of gas needed to execute the // given transaction against the current pending block. -func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { +func (s *BlockChainAPI) EstimateGas(ctx context.Context, args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { return s.b.EstimateGas(ctx, args, blockNrOrHash) } @@ -674,7 +489,7 @@ func RPCMarshalBlock(block *rpctypes.Block, inclTx bool, fullTx bool, config *pa } if fullTx { formatTx = func(idx int, tx *types.Transaction) interface{} { - return newRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(idx), config) + return rpctypes.NewRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(idx), config) } } txs := block.Transactions() @@ -710,138 +525,6 @@ func (s *BlockChainAPI) rpcMarshalBlock(_ context.Context, b *rpctypes.Block, in return RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) } -// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction -type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *types.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` -} - -// newRPCTransaction returns a transaction that will serialize to the RPC -// representation, with the given location metadata set (if available). -func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { - signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) - from, _ := types.Sender(signer, tx) - - return newRPCTransactionWithFrom(tx, blockHash, blockNumber, index, baseFee, from) -} - -func newRPCTransactionWithFrom(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, from common.Address) *RPCTransaction { - v, r, s := tx.RawSignatureValues() - result := &RPCTransaction{ - Type: hexutil.Uint64(tx.Type()), - From: from, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - Hash: tx.Hash(), - Input: hexutil.Bytes(tx.Data()), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - V: (*hexutil.Big)(v), - R: (*hexutil.Big)(r), - S: (*hexutil.Big)(s), - } - if blockHash != (common.Hash{}) { - result.BlockHash = &blockHash - result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) - result.TransactionIndex = (*hexutil.Uint64)(&index) - } - switch tx.Type() { - case types.LegacyTxType: - // if a legacy transaction has an EIP-155 chain id, include it explicitly - if id := tx.ChainId(); id.Sign() != 0 { - result.ChainID = (*hexutil.Big)(id) - } - case types.AccessListTxType: - al := tx.AccessList() - result.Accesses = &al - result.ChainID = (*hexutil.Big)(tx.ChainId()) - case types.DynamicFeeTxType: - al := tx.AccessList() - result.Accesses = &al - result.ChainID = (*hexutil.Big)(tx.ChainId()) - result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) - result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) - // if the transaction has been mined, compute the effective gas price - if baseFee != nil && blockHash != (common.Hash{}) { - // price = min(tip, gasFeeCap - baseFee) + baseFee - price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) - result.GasPrice = (*hexutil.Big)(price) - } else { - result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) - } - } - return result -} - -// NewTransactionFromMsg returns a txs that will serialize to the RPC -// representation, with the given location metadata set (if available). -func NewTransactionFromMsg( - msg *evmtypes.MsgEthereumTx, - blockHash common.Hash, - blockNumber, index uint64, - baseFee *big.Int, - cfg *params.ChainConfig, -) *RPCTransaction { - tx := msg.AsTransaction() - // use latest singer, so use time.now as block time. - if msg.From != "" { - return newRPCTransactionWithFrom(tx, blockHash, blockNumber, index, baseFee, common.HexToAddress(msg.From)) - } - return newRPCTransaction(tx, blockHash, blockNumber, uint64(time.Now().Unix()), index, baseFee, cfg) -} - -// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation -func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { - var ( - baseFee *big.Int - blockNumber = uint64(0) - blockTime = uint64(0) - ) - if current != nil { - baseFee = misc.CalcBaseFee(config, current) - blockNumber = current.Number.Uint64() - blockTime = current.Time - } - return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config) -} - -// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, blockHash common.Hash, index uint64, config *params.ChainConfig) *RPCTransaction { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - return newRPCTransaction(txs[index], blockHash, b.NumberU64(), b.Time(), index, b.BaseFee(), config) -} - -// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - blob, _ := txs[index].MarshalBinary() - return blob -} - // AccessListResult returns an optional access list // It's the result of the `debug_createAccessList` RPC call. // It contains an error if the transaction itself failed. @@ -853,19 +536,19 @@ type AccessListResult struct { // CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain states. -func (s *BlockChainAPI) CreateAccessList(_ context.Context, _ TransactionArgs, _ *rpc.BlockNumberOrHash) (*AccessListResult, error) { +func (s *BlockChainAPI) CreateAccessList(_ context.Context, _ rpctypes.TransactionArgs, _ *rpc.BlockNumberOrHash) (*AccessListResult, error) { return nil, errors.New("CreateAccessList is not implemented") } // TransactionAPI exposes methods for reading and creating transaction data. type TransactionAPI struct { - b Backend + b rpctypes.TrancsactionBackend logger log.Logger nonceLock *AddrLocker } // NewTransactionAPI creates a new RPC service with methods for interacting with transactions. -func NewTransactionAPI(b Backend, logger log.Logger, nonceLock *AddrLocker) *TransactionAPI { +func NewTransactionAPI(b rpctypes.TrancsactionBackend, logger log.Logger, nonceLock *AddrLocker) *TransactionAPI { // The signer used by the API should always be the 'latest' known one because we expect // signers to be backwards-compatible with old transactions. return &TransactionAPI{b, logger, nonceLock} @@ -890,17 +573,17 @@ func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blo } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { +func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *rpctypes.RPCTransaction { if block, _ := s.b.ArtBlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(index), s.b.ChainConfig()) + return rpctypes.NewRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(index), s.b.ChainConfig()) } return nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { +func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *rpctypes.RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(index), s.b.ChainConfig()) + return rpctypes.NewRPCTransactionFromBlockIndex(block.EthBlock(), block.Hash(), uint64(index), s.b.ChainConfig()) } return nil } @@ -908,7 +591,7 @@ func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.ArtBlockByNumber(ctx, blockNr); block != nil { - return newRPCRawTransactionFromBlockIndex(block.EthBlock(), uint64(index)) + return rpctypes.NewRPCRawTransactionFromBlockIndex(block.EthBlock(), uint64(index)) } return nil } @@ -916,7 +599,7 @@ func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Cont // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. func (s *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCRawTransactionFromBlockIndex(block.EthBlock(), uint64(index)) + return rpctypes.NewRPCRawTransactionFromBlockIndex(block.EthBlock(), uint64(index)) } return nil } @@ -927,14 +610,22 @@ func (s *TransactionAPI) GetTransactionCount(_ context.Context, address common.A } // GetTransactionByHash returns the transaction for the given hash -func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { +func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*rpctypes.RPCTransaction, error) { return s.b.GetTransaction(ctx, hash) } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *TransactionAPI) GetRawTransactionByHash(_ context.Context, _ common.Hash) (hexutil.Bytes, error) { - // TODO - return nil, errors.New("GetRawTransactionByHash is not implemented") +func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + msg, err := s.b.GetTxMsg(ctx, hash) + if err != nil { + return nil, err + } + + if msg == nil { + return nil, nil + } + + return msg.AsTransaction().MarshalBinary() } // GetTransactionReceipt returns the transaction receipt for the given transaction hash. @@ -943,7 +634,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. } // SubmitTransaction is a helper function that submits tx to txPool and logs a message. -func SubmitTransaction(ctx context.Context, logger log.Logger, b Backend, tx *types.Transaction) (common.Hash, error) { +func SubmitTransaction(ctx context.Context, logger log.Logger, b rpctypes.TrancsactionBackend, tx *types.Transaction) (common.Hash, error) { // If the transaction fee cap is already specified, ensure the // fee of the given transaction is _reasonable_. if err := checkTxFee(tx.GasPrice(), tx.Gas(), b.RPCTxFeeCap()); err != nil { @@ -964,12 +655,17 @@ func SubmitTransaction(ctx context.Context, logger log.Logger, b Backend, tx *ty return tx.Hash(), nil } - head, err := b.CurrentHeader() + blockNum, err := b.BlockNumber() + if err != nil { + return common.Hash{}, err + } + + blockTime, err := b.BlockTimeByNumber(int64(blockNum)) if err != nil { return common.Hash{}, err } - signer := types.MakeSigner(b.ChainConfig(), head.Number, head.Time) + signer := types.MakeSigner(b.ChainConfig(), big.NewInt(int64(blockNum)), blockTime) from, err := types.Sender(signer, tx) if err != nil { return common.Hash{}, err @@ -986,13 +682,13 @@ func SubmitTransaction(ctx context.Context, logger log.Logger, b Backend, tx *ty // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. -func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { - if err := args.setDefaults(ctx, s.b); err != nil { +func (s *TransactionAPI) SendTransaction(ctx context.Context, args rpctypes.TransactionArgs) (common.Hash, error) { + if err := args.SetDefaults(ctx, s.b); err != nil { return common.Hash{}, err } signed, err := s.b.SignTransaction(&args) if err != nil { - log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) + log.Warn("Failed transaction send attempt", "from", args.FromAddr(), "to", args.To, "value", args.Value.ToInt(), "err", err) return common.Hash{}, err } return SubmitTransaction(ctx, s.logger, s.b, signed) @@ -1001,13 +697,13 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr // FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) // on a given unsigned transaction, and returns it to the caller for further // processing (signing + broadcast). -func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (s *TransactionAPI) FillTransaction(ctx context.Context, args rpctypes.TransactionArgs) (*SignTransactionResult, error) { // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b); err != nil { + if err := args.SetDefaults(ctx, s.b); err != nil { return nil, err } // Assemble the transaction and obtain rlp - tx := args.toTransaction() + tx := args.ToTransaction() data, err := tx.MarshalBinary() if err != nil { return nil, err @@ -1048,7 +744,7 @@ type SignTransactionResult struct { // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (s *TransactionAPI) SignTransaction(ctx context.Context, args rpctypes.TransactionArgs) (*SignTransactionResult, error) { // gas, gas limit, nonce checking are made in SignTransaction signed, err := s.b.SignTransaction(&args) if err != nil { @@ -1064,131 +760,58 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { - // TODO - return nil, errors.New("PendingTransactions is not implemented") -} - -// Resend accepts an existing transaction and a new gas price and limit. It will remove -// the given transaction from the pool and reinsert it with the new gas price and limit. -func (s *TransactionAPI) Resend(_ context.Context, _ TransactionArgs, _ *hexutil.Big, _ *hexutil.Uint64) (common.Hash, error) { - // TODO - return common.Hash{}, errors.New("Resend is not implemented") -} - -// DebugAPI is the collection of Ethereum APIs exposed over the debugging -// namespace. -type DebugAPI struct { - b Backend -} - -// NewDebugAPI creates a new instance of DebugAPI. -func NewDebugAPI(b Backend) *DebugAPI { - return &DebugAPI{b: b} -} - -// GetRawHeader retrieves the RLP encoding for a single header. -func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - var hash common.Hash - if h, ok := blockNrOrHash.Hash(); ok { - hash = h - } else { - block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) - if err != nil { - return nil, err - } - hash = block.Hash() - } - header, _ := api.b.HeaderByHash(ctx, hash) - if header == nil { - return nil, fmt.Errorf("header #%d not found", hash) +func (s *TransactionAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) { + pendingTxs, err := s.b.PendingTransactions() + if err != nil { + return nil, err } - return rlp.EncodeToBytes(header) -} -// GetRawBlock retrieves the RLP encoded for a single block. -func (api *DebugAPI) GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - var hash common.Hash - if h, ok := blockNrOrHash.Hash(); ok { - hash = h - } else { - block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) - if err != nil { - return nil, err - } - hash = block.Hash() + cfg := s.b.ChainConfig() + if cfg == nil { + return nil, errors.New("failed to get chain config") } - block, _ := api.b.BlockByHash(ctx, hash) - if block == nil { - return nil, fmt.Errorf("block #%d not found", hash) + result := make([]*rpctypes.RPCTransaction, 0, len(pendingTxs)) + for _, tx := range pendingTxs { + for _, msg := range (*tx).GetMsgs() { + if ethMsg, ok := msg.(*evmtypes.MsgEthereumTx); ok { + rpctx := rpctypes.NewTransactionFromMsg(ethMsg, common.Hash{}, uint64(0), uint64(0), nil, cfg) + result = append(result, rpctx) + } + } } - return rlp.EncodeToBytes(block) -} -// GetRawReceipts retrieves the binary-encoded receipts of a single block. -func (api *DebugAPI) GetRawReceipts(_ context.Context, _ rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) { - return nil, errors.New("GetRawReceipts is not implemented") + return result, nil } -// GetRawTransaction returns the bytes of the transaction for the given hash. -func (api *DebugAPI) GetRawTransaction(_ context.Context, _ common.Hash) (hexutil.Bytes, error) { - // TODO - return hexutil.Bytes{}, errors.New("GetRawTransaction is not implemented") -} - -// PrintBlock retrieves a block and returns its pretty printed form. -func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { - block, _ := api.b.ArtBlockByNumber(ctx, rpc.BlockNumber(number)) - if block == nil { - return "", fmt.Errorf("block #%d not found", number) +// Resend accepts an existing transaction and a new gas price and limit. It will remove +// the given transaction from the pool and reinsert it with the new gas price and limit. +func (s *TransactionAPI) Resend(ctx context.Context, args rpctypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { + if args.Nonce == nil { + return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") } - return spew.Sdump(block), nil -} - -// ChaindbProperty returns leveldb properties of the key-value database. -func (api *DebugAPI) ChaindbProperty(_ string) (string, error) { - return "", errors.New("ChaindbProperty is not implemented") -} -// ChaindbCompact flattens the entire key-value database into a single level, -// removing all unused slots and merging all keys. -func (api *DebugAPI) ChaindbCompact() error { - return errors.New("ChaindbCompact is not implemented") -} - -// SetHead rewinds the head of the blockchain to a previous block. -func (api *DebugAPI) SetHead(_ hexutil.Uint64) { - // TODO -} - -// NetAPI offers network related RPC methods -type NetAPI struct { - net *p2p.Server - networkVersion uint64 -} + if err := args.SetDefaults(ctx, s.b); err != nil { + return common.Hash{}, err + } -// NewNetAPI creates a new net API instance. -func NewNetAPI(net *p2p.Server, networkVersion uint64) *NetAPI { - return &NetAPI{net, networkVersion} -} + fixedArgs, err := s.b.GetResendArgs(args, gasPrice, gasLimit) + if err != nil { + return common.Hash{}, err + } -// Listening returns an indication if the node is listening for network connections. -func (s *NetAPI) Listening() bool { - return true // always listening + return s.SendTransaction(ctx, fixedArgs) } -// PeerCount returns the number of connected peers -func (s *NetAPI) PeerCount() hexutil.Uint { - if s.net == nil { - return 0 - } - return hexutil.Uint(s.net.PeerCount()) -} +// // DebugAPI is the collection of Ethereum APIs exposed over the debugging +// // namespace. +// type DebugAPI struct { +// b Backend +// } -// Version returns the current ethereum protocol version. -func (s *NetAPI) Version() string { - return fmt.Sprintf("%d", s.networkVersion) -} +// // NewDebugAPI creates a new instance of DebugAPI. +// func NewDebugAPI(b Backend) *DebugAPI { +// return &DebugAPI{b: b} +// } // checkTxFee is an internal function used to check whether the fee of // the given transaction is _reasonable_(under the cap). diff --git a/ethereum/rpc/api/net.go b/ethereum/rpc/api/net.go index a4c312f..500e0cd 100644 --- a/ethereum/rpc/api/net.go +++ b/ethereum/rpc/api/net.go @@ -2,42 +2,31 @@ package api import ( "github.com/ethereum/go-ethereum/common/hexutil" -) - -// NetBackend is the collection of methods required to satisfy the net -// RPC DebugAPI. -type NetBackend interface { - NetAPI -} -// NetAPI is the collection of net RPC DebugAPI methods. -type NetAPI interface { - PeerCount() hexutil.Uint - Listening() bool - Version() string -} + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" +) -// netAPI offers network related RPC methods. -type netAPI struct { - b NetBackend +// NetAPI offers network related RPC methods. +type NetAPI struct { + b rpctypes.NetBackend } // NewNetAPI creates a new net DebugAPI instance. -func NewNetAPI(b NetBackend) NetAPI { - return &netAPI{b} +func NewNetAPI(b rpctypes.NetBackend) *NetAPI { + return &NetAPI{b} } // Listening returns an indication if the node is listening for network connections. -func (api *netAPI) Listening() bool { +func (api *NetAPI) Listening() bool { return api.b.Listening() } // PeerCount returns the number of connected peers. -func (api *netAPI) PeerCount() hexutil.Uint { +func (api *NetAPI) PeerCount() hexutil.Uint { return api.b.PeerCount() } // Version returns the current ethereum protocol version. -func (api *netAPI) Version() string { +func (api *NetAPI) Version() string { return api.b.Version() } diff --git a/ethereum/rpc/api/personal.go b/ethereum/rpc/api/personal.go new file mode 100644 index 0000000..11e037a --- /dev/null +++ b/ethereum/rpc/api/personal.go @@ -0,0 +1,194 @@ +package api + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" +) + +// PersonalAccountAPI provides an API to access accounts managed by this node. +// It offers methods to create, (un)lock en list accounts. Some methods accept +// passwords and are therefore considered private by default. +type PersonalAccountAPI struct { + nonceLock *AddrLocker + logger log.Logger + b rpctypes.PersonalBackend +} + +// NewPersonalAccountAPI create a new PersonalAccountAPI. +func NewPersonalAccountAPI(b rpctypes.PersonalBackend, logger log.Logger, nonceLock *AddrLocker) *PersonalAccountAPI { + return &PersonalAccountAPI{ + nonceLock: nonceLock, + logger: logger, + b: b, + } +} + +// ListAccounts will return a list of addresses for accounts this node manages. +func (s *PersonalAccountAPI) ListAccounts() []common.Address { + return s.b.Accounts() +} + +// rawWallet is a JSON representation of an accounts.Wallet interface, with its +// data contents extracted into plain fields. +type rawWallet struct { + URL string `json:"url"` + Status string `json:"status"` + Failure string `json:"failure,omitempty"` + Accounts []accounts.Account `json:"accounts,omitempty"` +} + +// ListWallets will return a list of wallets this node manages. +func (s *PersonalAccountAPI) ListWallets() []rawWallet { + // not implemented + wallets := make([]rawWallet, 0) // return [] instead of nil if empty + return wallets +} + +// OpenWallet initiates a hardware wallet opening procedure, establishing a USB +// connection and attempting to authenticate via the provided passphrase. Note, +// the method may return an extra challenge requiring a second open (e.g. the +// Trezor PIN matrix challenge). +func (s *PersonalAccountAPI) OpenWallet(_ string, _ *string) error { + return errors.New("OpenWallet is not valid") +} + +// DeriveAccount requests an HD wallet to derive a new account, optionally pinning +// it for later reuse. +func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + return accounts.Account{}, errors.New("DeriveAccount is not valid") +} + +// NewAccount will create a new account and returns the address for the new account. +func (s *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { + return s.b.NewAccount(password) +} + +// ImportRawKey stores the given hex encoded ECDSA key into the key directory, +// encrypting it with the passphrase. +func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { + return s.b.ImportRawKey(privkey, password) +} + +// UnlockAccount will unlock the account associated with the given address with +// the given password for duration seconds. If duration is nil it will use a +// default of 300 seconds. It returns an indication if the account was unlocked. +func (s *PersonalAccountAPI) UnlockAccount(_ context.Context, _ common.Address, _ string, duration *uint64) (bool, error) { + // not implemented + return false, errors.New("UnlockAccount is not valid") +} + +// LockAccount will lock the account associated with the given address when it's unlocked. +func (s *PersonalAccountAPI) LockAccount(_ common.Address) bool { + // not implemented" + return false +} + +// signTransaction sets defaults and signs the given transaction +// NOTE: the caller needs to ensure that the nonceLock is held, if applicable, +// and release it after the transaction has been submitted to the tx pool +func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *rpctypes.TransactionArgs, _ string) (*types.Transaction, error) { + if err := args.SetDefaults(ctx, s.b); err != nil { + return nil, err + } + signed, err := s.b.SignTransaction(args) + if err != nil { + log.Warn("Failed transaction send attempt", "from", args.FromAddr(), "to", args.To, "value", args.Value.ToInt(), "err", err) + return nil, err + } + return signed, err +} + +// SendTransaction will create a transaction from the given arguments and +// tries to sign it with the key associated with args.From. If the given +// passwd isn't able to decrypt the key it fails. +func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args rpctypes.TransactionArgs, passwd string) (common.Hash, error) { + if args.Nonce == nil { + // Hold the mutex around signing to prevent concurrent assignment of + // the same nonce to multiple accounts. + s.nonceLock.LockAddr(args.FromAddr()) + defer s.nonceLock.UnlockAddr(args.FromAddr()) + } + + signed, err := s.signTransaction(ctx, &args, passwd) + if err != nil { + log.Warn("Failed transaction send attempt", "from", args.FromAddr(), "to", args.To, "value", args.Value.ToInt(), "err", err) + return common.Hash{}, err + } + return SubmitTransaction(ctx, s.logger, s.b, signed) +} + +// SignTransaction will create a transaction from the given arguments and +// tries to sign it with the key associated with args.From. If the given passwd isn't +// able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast +// to other nodes +func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args rpctypes.TransactionArgs, passwd string) (*SignTransactionResult, error) { + signed, err := s.signTransaction(ctx, &args, passwd) + if err != nil { + return nil, err + } + + data, err := signed.MarshalBinary() + if err != nil { + return nil, err + } + return &SignTransactionResult{data, signed}, nil +} + +// Sign calculates an Ethereum ECDSA signature for: +// keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)) +// +// Note, the produced signature conforms to the secp256k1 curve R, S and V values, +// where the V value will be 27 or 28 for legacy reasons. +// +// The key used to calculate the signature is decrypted with the given password. +// +// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign +func (s *PersonalAccountAPI) Sign(_ context.Context, data hexutil.Bytes, addr common.Address, _ string) (hexutil.Bytes, error) { + return s.b.Sign(addr, data) +} + +// EcRecover returns the address for the account that was used to create the signature. +// Note, this function is compatible with eth_sign and personal_sign. As such it recovers +// the address of: +// hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message}) +// addr = ecrecover(hash, signature) +// +// Note, the signature must conform to the secp256k1 curve R, S and V values, where +// the V value must be 27 or 28 for legacy reasons. +// +// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover +func (s *PersonalAccountAPI) EcRecover(_ context.Context, data, sig hexutil.Bytes) (common.Address, error) { + if len(sig) != crypto.SignatureLength { + return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength) + } + if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 { + return common.Address{}, errors.New("invalid Ethereum signature (V is not 27 or 28)") + } + sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1 + + rpk, err := crypto.SigToPub(accounts.TextHash(data), sig) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(*rpk), nil +} + +// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. +func (s *PersonalAccountAPI) InitializeWallet(_ context.Context, _ string) (string, error) { + return "", errors.New("InitializeWallet is not valid") +} + +// Unpair deletes a pairing between wallet and geth. +func (s *PersonalAccountAPI) Unpair(_ context.Context, _ string, _ string) error { + return errors.New("unpair is not valid") +} diff --git a/ethereum/rpc/api/txpool.go b/ethereum/rpc/api/txpool.go new file mode 100644 index 0000000..f32fa12 --- /dev/null +++ b/ethereum/rpc/api/txpool.go @@ -0,0 +1,121 @@ +package api + +import ( + "fmt" + "strconv" + + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" + + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" +) + +// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non-confidential. +type TxPoolAPI struct { + b rpctypes.TxPoolBackend + logger log.Logger +} + +// NewTxPoolAPI creates a new tx pool service that gives information about the transaction pool. +func NewTxPoolAPI(b rpctypes.TxPoolBackend, logger log.Logger) *TxPoolAPI { + return &TxPoolAPI{b, logger} +} + +// Content returns the transactions contained within the transaction pool. +func (s *TxPoolAPI) Content() map[string]map[string]map[string]*rpctypes.RPCTransaction { + content := map[string]map[string]map[string]*rpctypes.RPCTransaction{ + "pending": make(map[string]map[string]*rpctypes.RPCTransaction), + "queued": s.getPendingContent(common.Address{}), + } + + return content +} + +// ContentFrom returns the transactions contained within the transaction pool. +func (s *TxPoolAPI) ContentFrom(address common.Address) map[string]map[string]*rpctypes.RPCTransaction { + return s.getPendingContent(address) +} + +// Status returns the number of pending and queued transaction in the pool. +func (s *TxPoolAPI) Status() map[string]hexutil.Uint { + pending, err := s.b.PendingTransactionsCount() + if err != nil { + s.logger.Debug("get pending transaction count failed", "error", err.Error()) + } + return map[string]hexutil.Uint{ + "pending": hexutil.Uint(pending), + "queued": hexutil.Uint(0), + } +} + +// Inspect retrieves the content of the transaction pool and flattens it into an +// easily inspectable list. +func (s *TxPoolAPI) Inspect() map[string]map[string]map[string]string { + content := map[string]map[string]map[string]string{ + "pending": make(map[string]map[string]string), + "queued": make(map[string]map[string]string), + } + pending := s.getPendingContent(common.Address{}) + + // Define a formatter to flatten a transaction into a string + var format = func(tx *rpctypes.RPCTransaction) string { + if to := tx.To; to != nil { + return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To.Hex(), tx.Value, tx.Gas, tx.GasPrice) + } + return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value, tx.Gas, tx.GasPrice) + } + // Flatten the pending transactions + for account, txs := range pending { + dump := make(map[string]string) + for _, tx := range txs { + dump[fmt.Sprintf("%d", tx.Nonce)] = format(tx) + } + content["pending"][account] = dump + } + return content +} + +func (s *TxPoolAPI) getPendingContent(addr common.Address) map[string]map[string]*rpctypes.RPCTransaction { + pendingContent := make(map[string]map[string]*rpctypes.RPCTransaction) + pendingTxs, err := s.b.PendingTransactions() + if err != nil { + s.logger.Debug("txpool_context, get pending transactions failed", "err", err.Error()) + return pendingContent + } + + cfg := s.b.ChainConfig() + if cfg == nil { + s.logger.Debug("txpool_context, failed to get chain config") + return pendingContent + } + for _, tx := range pendingTxs { + for _, msg := range (*tx).GetMsgs() { + if ethMsg, ok := msg.(*evmtypes.MsgEthereumTx); ok { + sender, err := s.b.GetSender(ethMsg, cfg.ChainID) + if err != nil { + s.logger.Debug("txpool_context, get pending transaction sender", "err", err.Error()) + continue + } + + if (addr != common.Address{} && addr != sender) { + continue + } + + txData, err := evmtypes.UnpackTxData(ethMsg.Data) + if err != nil { + s.logger.Debug("txpool_context, unpack pending transaction failed", "err", err.Error()) + continue + } + + rpctx := rpctypes.NewTransactionFromMsg(ethMsg, common.Hash{}, uint64(0), uint64(0), nil, cfg) + if pendingContent[sender.String()] == nil { + pendingContent[sender.String()] = make(map[string]*rpctypes.RPCTransaction) + } + pendingContent[sender.String()][strconv.FormatUint(txData.GetNonce(), 10)] = rpctx + } + } + } + return pendingContent +} diff --git a/ethereum/rpc/api/web3.go b/ethereum/rpc/api/web3.go index 61b2179..d4db617 100644 --- a/ethereum/rpc/api/web3.go +++ b/ethereum/rpc/api/web3.go @@ -3,37 +3,27 @@ package api import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" -) - -// Web3Backend is the collection of methods required to satisfy the net -// RPC DebugAPI. -type Web3Backend interface { - ClientVersion() string -} -// Web3API is the collection of net RPC DebugAPI methods. -type Web3API interface { - ClientVersion() string - Sha3(input hexutil.Bytes) hexutil.Bytes -} + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" +) // web3Api offers network related RPC methods. -type web3API struct { - b Web3Backend +type Web3API struct { + b rpctypes.Web3Backend } // NewWeb3API creates a new web3 DebugAPI instance. -func NewWeb3API(b Web3Backend) Web3Backend { - return &web3API{b} +func NewWeb3API(b rpctypes.Web3Backend) rpctypes.Web3Backend { + return &Web3API{b} } // ClientVersion returns the node name. -func (api *web3API) ClientVersion() string { +func (api *Web3API) ClientVersion() string { return api.b.ClientVersion() } // Sha3 applies the ethereum sha3 implementation on the input. // It assumes the input is hex encoded. -func (*web3API) Sha3(input hexutil.Bytes) hexutil.Bytes { +func (*Web3API) Sha3(input hexutil.Bytes) hexutil.Bytes { return crypto.Keccak256(input) } diff --git a/ethereum/rpc/apis.go b/ethereum/rpc/apis.go index ab4acba..5376f2a 100644 --- a/ethereum/rpc/apis.go +++ b/ethereum/rpc/apis.go @@ -3,41 +3,38 @@ package rpc import ( rpcclient "github.com/cometbft/cometbft/rpc/jsonrpc/client" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/server" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/artela-network/artela-rollkit/ethereum/rpc/api" - "github.com/artela-network/artela-rollkit/ethereum/rpc/ethapi" "github.com/artela-network/artela-rollkit/ethereum/rpc/filters" ) -func GetAPIs(clientCtx client.Context, wsClient *rpcclient.WSClient, logger log.Logger, apiBackend *BackendImpl) []rpc.API { - nonceLock := new(ethapi.AddrLocker) +func GetAPIs(clientCtx client.Context, serverCtx *server.Context, wsClient *rpcclient.WSClient, logger log.Logger, apiBackend *BackendImpl) []rpc.API { + nonceLock := new(api.AddrLocker) return []rpc.API{ { Namespace: "eth", - Service: ethapi.NewEthereumAPI(apiBackend, logger), + Service: api.NewEthereumAPI(apiBackend, logger), }, { Namespace: "eth", - Service: ethapi.NewBlockChainAPI(apiBackend, logger), + Service: api.NewBlockChainAPI(apiBackend, logger), }, { Namespace: "eth", - Service: ethapi.NewTransactionAPI(apiBackend, logger, nonceLock), + Service: api.NewTransactionAPI(apiBackend, logger, nonceLock), }, { Namespace: "txpool", - Service: ethapi.NewTxPoolAPI(apiBackend), + Service: api.NewTxPoolAPI(apiBackend, logger), }, { Namespace: "debug", - Service: ethapi.NewDebugAPI(apiBackend), - }, { - Namespace: "debug", - Service: api.NewDebugAPI(apiBackend), + Service: api.NewDebugAPI(apiBackend, logger, serverCtx), }, { Namespace: "eth", - Service: ethapi.NewEthereumAccountAPI(apiBackend), + Service: api.NewEthereumAccountAPI(apiBackend), }, { Namespace: "personal", - Service: ethapi.NewPersonalAccountAPI(apiBackend, logger, nonceLock), + Service: api.NewPersonalAccountAPI(apiBackend, logger, nonceLock), }, { Namespace: "net", Service: api.NewNetAPI(apiBackend), diff --git a/ethereum/rpc/backend.go b/ethereum/rpc/backend.go index a511734..316f3bd 100644 --- a/ethereum/rpc/backend.go +++ b/ethereum/rpc/backend.go @@ -4,20 +4,15 @@ import ( "context" "errors" "fmt" - "math" "math/big" - "runtime" "strconv" "time" sdkmath "cosmossdk.io/math" - bftclient "github.com/cometbft/cometbft/rpc/client" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + db "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/server" - sdktypes "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/version" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -31,11 +26,8 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "github.com/artela-network/artela-rollkit/ethereum/rpc/api" - ethapi2 "github.com/artela-network/artela-rollkit/ethereum/rpc/ethapi" "github.com/artela-network/artela-rollkit/ethereum/rpc/filters" rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" - "github.com/artela-network/artela-rollkit/ethereum/rpc/utils" "github.com/artela-network/artela-rollkit/ethereum/server/config" ethereumtypes "github.com/artela-network/artela-rollkit/ethereum/types" evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" @@ -44,10 +36,17 @@ import ( var ( _ gasprice.OracleBackend = (*BackendImpl)(nil) - _ ethapi2.Backend = (*BackendImpl)(nil) _ filters.Backend = (*BackendImpl)(nil) - _ api.NetBackend = (*BackendImpl)(nil) - _ api.DebugBackend = (*BackendImpl)(nil) + + _ rpctypes.Backend = (*BackendImpl)(nil) + _ rpctypes.EthereumBackend = (*BackendImpl)(nil) + _ rpctypes.BlockChainBackend = (*BackendImpl)(nil) + _ rpctypes.TrancsactionBackend = (*BackendImpl)(nil) + _ rpctypes.DebugBackend = (*BackendImpl)(nil) + _ rpctypes.PersonalBackend = (*BackendImpl)(nil) + _ rpctypes.TxPoolBackend = (*BackendImpl)(nil) + _ rpctypes.NetBackend = (*BackendImpl)(nil) + _ rpctypes.Web3Backend = (*BackendImpl)(nil) ) // backend represents the backend for the JSON-RPC service. @@ -72,14 +71,11 @@ type BackendImpl struct { ctx context.Context clientCtx client.Context queryClient *rpctypes.QueryClient -} -func (b *BackendImpl) EthBlockByNumber(blockNum rpc.BlockNumber) (*ethtypes.Block, error) { - // TODO implement me - panic("implement me") + db db.DB } -// NewBackend create the backend instance +// NewBackend create the backend implements func NewBackend( ctx *server.Context, clientCtx client.Context, @@ -87,6 +83,7 @@ func NewBackend( extRPCEnabled bool, cfg *Config, logger log.Logger, + db db.DB, ) *BackendImpl { b := &BackendImpl{ ctx: context.Background(), @@ -98,6 +95,7 @@ func NewBackend( queryClient: rpctypes.NewQueryClient(clientCtx), scope: event.SubscriptionScope{}, + db: db, } var err error @@ -118,153 +116,137 @@ func NewBackend( return b } -// General Ethereum DebugAPI - -func (b *BackendImpl) SyncProgress() ethereum.SyncProgress { - return ethereum.SyncProgress{ - CurrentBlock: 0, - HighestBlock: 0, - } -} - -func (b *BackendImpl) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { - if baseFee == nil { - // london hardfork not enabled or feemarket not enabled - return big.NewInt(0), nil - } - - params, err := b.queryClient.FeeMarket.Params(b.ctx, &feetypes.QueryParamsRequest{}) +func (b *BackendImpl) CurrentHeader() (*ethtypes.Header, error) { + block, err := b.ArtBlockByNumber(context.Background(), rpc.LatestBlockNumber) if err != nil { return nil, err } - // calculate the maximum base fee delta in current block, assuming all block gas limit is consumed - // ``` - // GasTarget = GasLimit / ElasticityMultiplier - // Delta = BaseFee * (GasUsed - GasTarget) / GasTarget / Denominator - // ``` - // The delta is at maximum when `GasUsed` is equal to `GasLimit`, which is: - // ``` - // MaxDelta = BaseFee * (GasLimit - GasLimit / ElasticityMultiplier) / (GasLimit / ElasticityMultiplier) / Denominator - // = BaseFee * (ElasticityMultiplier - 1) / Denominator - // ```t - maxDelta := baseFee.Int64() * (int64(params.Params.ElasticityMultiplier) - 1) / int64(params.Params.BaseFeeChangeDenominator) // #nosec G701 - if maxDelta < 0 { - // impossible if the parameter validation passed. - maxDelta = 0 + if block == nil || block.Header() == nil { + return nil, errors.New("current block header not found") } - return big.NewInt(maxDelta), nil + return block.Header(), nil } -func (b *BackendImpl) ChainConfig() *params.ChainConfig { - cfg, err := b.chainConfig() +func (b *BackendImpl) Accounts() []common.Address { + addresses := make([]common.Address, 0) // return [] instead of nil if empty + + infos, err := b.clientCtx.Keyring.List() if err != nil { + b.logger.Info("keying list failed", "error", err) return nil } - return cfg + + for _, info := range infos { + pubKey, err := info.GetPubKey() + if err != nil { + b.logger.Info("getPubKey failed", "info", info, "error", err) + return nil + } + addressBytes := pubKey.Address().Bytes() + addresses = append(addresses, common.BytesToAddress(addressBytes)) + } + + return addresses } -func (b *BackendImpl) chainConfig() (*params.ChainConfig, error) { - params, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) +func (b *BackendImpl) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) if err != nil { - b.logger.Info("queryClient.Params failed", err) return nil, err } - currentHeader, err := b.CurrentHeader() + req := &evmtypes.QueryBalanceRequest{ + Address: address.String(), + } + + _, err = b.CosmosBlockByNumber(blockNum) if err != nil { return nil, err } - return params.Params.ChainConfig.EthereumConfig(currentHeader.Number.Int64(), b.chainID), nil -} + res, err := b.queryClient.Balance(rpctypes.ContextWithHeight(blockNum.Int64()), req) + if err != nil { + return nil, err + } -func (b *BackendImpl) FeeHistory(blockCount uint64, lastBlock rpc.BlockNumber, - rewardPercentiles []float64, -) (*rpctypes.FeeHistoryResult, error) { - blockEnd := int64(lastBlock) + val, ok := sdkmath.NewIntFromString(res.Balance) + if !ok { + return nil, errors.New("invalid balance") + } - if blockEnd < 0 { - blockNumber, err := b.BlockNumber() - if err != nil { - return nil, err - } - blockEnd = int64(blockNumber) + if val.IsNegative() { + return nil, errors.New("couldn't fetch balance. Node state is pruned") } - blocks := int64(blockCount) - maxBlockCount := int64(b.cfg.AppCfg.JSONRPC.FeeHistoryCap) - if blocks > maxBlockCount { - return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", blocks, maxBlockCount) + return (*hexutil.Big)(val.BigInt()), nil +} + +func (b *BackendImpl) ArtBlockByNumber(ctx context.Context, number rpc.BlockNumber) (*rpctypes.Block, error) { + resBlock, err := b.CosmosBlockByNumber(number) + if err != nil || resBlock == nil { + return nil, fmt.Errorf("query block failed, block number %d, %w", number, err) } - if blockEnd+1 < blocks { - blocks = blockEnd + 1 + blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + if err != nil { + // TODO remove this. This is a workaround. + // see https://github.com/rollkit/rollkit/issues/1935 + // https://github.com/artela-network/artela-rollkit/issues/9#issuecomment-2513769394 + if number == rpc.LatestBlockNumber && resBlock.Block.Height > 1 { + // try to fetch previous block + return b.ArtBlockByNumber(ctx, rpc.BlockNumber(resBlock.Block.Height-1)) + } + return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) } - blockStart := blockEnd + 1 - blocks - oldestBlock := (*hexutil.Big)(big.NewInt(blockStart)) + return b.BlockFromCosmosBlock(resBlock, blockRes) +} - reward := make([][]*hexutil.Big, blocks) - rewardCount := len(rewardPercentiles) - for i := 0; i < int(blocks); i++ { - reward[i] = make([]*hexutil.Big, rewardCount) +func (b *BackendImpl) BlockByHash(_ context.Context, hash common.Hash) (*rpctypes.Block, error) { + resBlock, err := b.CosmosBlockByHash(hash) + if err != nil || resBlock == nil { + return nil, fmt.Errorf("failed to get block by hash %s, %w", hash.Hex(), err) } - thisBaseFee := make([]*hexutil.Big, blocks+1) - thisGasUsedRatio := make([]float64, blocks) - calculateRewards := rewardCount != 0 - - for blockID := blockStart; blockID <= blockEnd; blockID++ { - index := int32(blockID - blockStart) // #nosec G701 - // tendermint block - tendermintblock, err := b.CosmosBlockByNumber(rpc.BlockNumber(blockID)) - if tendermintblock == nil { - return nil, err - } + blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + if err != nil { + return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) + } - // eth block - ethBlock, err := b.GetBlockByNumber(rpc.BlockNumber(blockID), true) - if ethBlock == nil { - return nil, err - } + return b.BlockFromCosmosBlock(resBlock, blockRes) +} - // tendermint block result - tendermintBlockResult, err := b.CosmosBlockResultByNumber(&tendermintblock.Block.Height) - if tendermintBlockResult == nil { - b.logger.Debug("block result not found", "height", tendermintblock.Block.Height, "error", err.Error()) - return nil, err - } +func (b *BackendImpl) ChainConfig() *params.ChainConfig { + cfg, err := b.chainConfig() + if err != nil { + panic(err) + } + return cfg +} - oneFeeHistory, err := b.processBlock(tendermintblock, ðBlock, rewardPercentiles, tendermintBlockResult) - if err != nil { - return nil, err - } +// General Ethereum DebugAPI - // copy - thisBaseFee[index] = (*hexutil.Big)(oneFeeHistory.BaseFee) - thisBaseFee[index+1] = (*hexutil.Big)(oneFeeHistory.NextBaseFee) - thisGasUsedRatio[index] = oneFeeHistory.GasUsedRatio - if calculateRewards { - for j := 0; j < rewardCount; j++ { - reward[index][j] = (*hexutil.Big)(oneFeeHistory.Reward[j]) - if reward[index][j] == nil { - reward[index][j] = (*hexutil.Big)(big.NewInt(0)) - } - } - } +func (b *BackendImpl) SyncProgress() ethereum.SyncProgress { + return ethereum.SyncProgress{ + CurrentBlock: 0, + HighestBlock: 0, } +} - feeHistory := rpctypes.FeeHistoryResult{ - OldestBlock: oldestBlock, - BaseFee: thisBaseFee, - GasUsedRatio: thisGasUsedRatio, +func (b *BackendImpl) chainConfig() (*params.ChainConfig, error) { + params, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) + if err != nil { + b.logger.Info("queryClient.Params failed", err) + return nil, err } - if calculateRewards { - feeHistory.Reward = reward + blockNum, err := b.BlockNumber() + if err != nil { + b.logger.Info("get BlockNumber failed", err) + return nil, err } - return &feeHistory, nil + return params.Params.ChainConfig.EthereumConfig(int64(blockNum), b.chainID), nil } func (b *BackendImpl) ChainDb() ethdb.Database { @@ -283,17 +265,6 @@ func (b *BackendImpl) RPCEVMTimeout() time.Duration { return b.cfg.RPCEVMTimeout } -func (b *BackendImpl) RPCTxFeeCap() float64 { - return b.cfg.RPCTxFeeCap -} - -func (b *BackendImpl) UnprotectedAllowed() bool { - if b.cfg.AppCfg == nil { - return false - } - return b.cfg.AppCfg.JSONRPC.AllowUnprotectedTxs -} - // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by // it must also be included here. @@ -331,45 +302,6 @@ func (b *BackendImpl) BloomStatus() (uint64, uint64) { func (b *BackendImpl) ServiceFilter(_ context.Context, _ *bloombits.MatcherSession) { } -// artela rpc DebugAPI - -// artela rpc DebugAPI - -func (b *BackendImpl) Listening() bool { - tmClient := b.clientCtx.Client.(bftclient.Client) - netInfo, err := tmClient.NetInfo(b.ctx) - if err != nil { - return false - } - return netInfo.Listening -} - -func (b *BackendImpl) PeerCount() hexutil.Uint { - tmClient := b.clientCtx.Client.(bftclient.Client) - netInfo, err := tmClient.NetInfo(b.ctx) - if err != nil { - return 0 - } - return hexutil.Uint(len(netInfo.Peers)) -} - -// ClientVersion returns the current client version. -func (b *BackendImpl) ClientVersion() string { - return fmt.Sprintf( - "%s/%s/%s/%s", - version.AppName, - version.Version, - runtime.GOOS+"-"+runtime.GOARCH, - runtime.Version(), - ) -} - -// func (b *BackendImpl) GetBlockContext( -// _ context.Context, header *ethtypes.Header, -// ) *vm.BlockContext { -// return nil -// } - func (b *BackendImpl) BaseFee(blockRes *tmrpctypes.ResultBlockResults) (*big.Int, error) { // return BaseFee if London hard fork is activated and feemarket is enabled res, err := b.queryClient.BaseFee(rpctypes.ContextWithHeight(blockRes.Height), &evmtypes.QueryBaseFeeRequest{}) @@ -398,38 +330,6 @@ func (b *BackendImpl) BaseFee(blockRes *tmrpctypes.ResultBlockResults) (*big.Int return res.BaseFee.BigInt(), nil } -func (b *BackendImpl) PendingTransactions() ([]*sdktypes.Tx, error) { - return nil, errors.New("PendingTransactions is not implemented") -} - -func (b *BackendImpl) GasPrice(ctx context.Context) (*hexutil.Big, error) { - var ( - result *big.Int - err error - ) - if head, err := b.CurrentHeader(); err == nil && head.BaseFee != nil { - result, err = b.SuggestGasTipCap(head.BaseFee) - if err != nil { - return nil, err - } - result = result.Add(result, head.BaseFee) - } else { - result = big.NewInt(b.RPCMinGasPrice()) - } - - // return at least GlobalMinGasPrice from FeeMarket module - minGasPrice, err := b.GlobalMinGasPrice() - if err != nil { - return nil, err - } - minGasPriceInt := minGasPrice.TruncateInt().BigInt() - if result.Cmp(minGasPriceInt) < 0 { - result = minGasPriceInt - } - - return (*hexutil.Big)(result), nil -} - func (b *BackendImpl) RPCMinGasPrice() int64 { evmParams, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) if err != nil { @@ -469,132 +369,3 @@ func (b *BackendImpl) RPCFilterCap() int32 { func (b *BackendImpl) RPCLogsCap() int32 { return b.appConf.JSONRPC.LogsCap } - -func (b *BackendImpl) Syncing() (interface{}, error) { - status, err := b.clientCtx.Client.Status(b.ctx) - if err != nil { - return false, err - } - - if !status.SyncInfo.CatchingUp { - return false, nil - } - - return map[string]interface{}{ - "startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight), - "currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight), - // "highestBlock": nil, // NA - // "pulledStates": nil, // NA - // "knownStates": nil, // NA - }, nil -} -func (b *BackendImpl) GetCoinbase() (sdktypes.AccAddress, error) { - node, err := b.clientCtx.GetNode() - if err != nil { - return nil, err - } - - status, err := node.Status(b.ctx) - if err != nil { - return nil, err - } - - req := &evmtypes.QueryValidatorAccountRequest{ - ConsAddress: sdktypes.ConsAddress(status.ValidatorInfo.Address).String(), - } - - res, err := b.queryClient.ValidatorAccount(b.ctx, req) - if err != nil { - return nil, err - } - - address, _ := sdktypes.AccAddressFromBech32(res.AccountAddress) // #nosec G703 - return address, nil -} - -// GetProof returns an account object with proof and any storage proofs -func (b *BackendImpl) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) { - numberOrHash := rpc.BlockNumberOrHash{ - BlockNumber: (*rpc.BlockNumber)(blockNrOrHash.BlockNumber), - BlockHash: blockNrOrHash.BlockHash, - RequireCanonical: false, - } - blockNum, err := b.blockNumberFromCosmos(numberOrHash) - if err != nil { - return nil, err - } - - height := blockNum.Int64() - - _, err = b.CosmosBlockByNumber(blockNum) - if err != nil { - // the error message imitates geth behavior - return nil, errors.New("header not found") - } - ctx := rpctypes.ContextWithHeight(height) - - // if the height is equal to zero, meaning the query condition of the block is either "pending" or "latest" - if height == 0 { - bn, err := b.BlockNumber() - if err != nil { - return nil, err - } - - if bn > math.MaxInt64 { - return nil, fmt.Errorf("not able to query block number greater than MaxInt64") - } - - height = int64(bn) // #nosec G701 -- checked for int overflow already - } - - clientCtx := b.clientCtx.WithHeight(height) - - // query storage proofs - storageProofs := make([]rpctypes.StorageResult, len(storageKeys)) - - for i, key := range storageKeys { - hexKey := common.HexToHash(key) - valueBz, proof, err := b.queryClient.GetProof(clientCtx, evmtypes.StoreKey, evmtypes.StateKey(address, hexKey.Bytes())) - if err != nil { - return nil, err - } - - storageProofs[i] = rpctypes.StorageResult{ - Key: key, - Value: (*hexutil.Big)(new(big.Int).SetBytes(valueBz)), - Proof: utils.GetHexProofs(proof), - } - } - - // query EVM account - req := &evmtypes.QueryAccountRequest{ - Address: address.String(), - } - - res, err := b.queryClient.Account(ctx, req) - if err != nil { - return nil, err - } - - // query account proofs - accountKey := append(authtypes.AddressStoreKeyPrefix, sdktypes.AccAddress(address.Bytes()).Bytes()...) - _, proof, err := b.queryClient.GetProof(clientCtx, authtypes.StoreKey, accountKey) - if err != nil { - return nil, err - } - - balance, ok := sdkmath.NewIntFromString(res.Balance) - if !ok { - return nil, errors.New("invalid balance") - } - - return &rpctypes.AccountResult{ - Address: address, - AccountProof: utils.GetHexProofs(proof), - Balance: (*hexutil.Big)(balance.BigInt()), - CodeHash: common.HexToHash(res.CodeHash), - Nonce: hexutil.Uint64(res.Nonce), - StorageHash: common.Hash{}, // NOTE: Evmos doesn't have a storage hash. TODO: implement? - StorageProof: storageProofs, - }, nil -} diff --git a/ethereum/rpc/blocks.go b/ethereum/rpc/blockchain.go similarity index 71% rename from ethereum/rpc/blocks.go rename to ethereum/rpc/blockchain.go index a6b4fa5..ab73400 100644 --- a/ethereum/rpc/blocks.go +++ b/ethereum/rpc/blockchain.go @@ -11,14 +11,15 @@ import ( "sort" "strconv" + sdkmath "cosmossdk.io/math" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdktypes "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" @@ -29,8 +30,7 @@ import ( "google.golang.org/grpc/status" "github.com/artela-network/artela-evm/vm" - - "github.com/artela-network/artela-rollkit/ethereum/rpc/ethapi" + "github.com/artela-network/artela-rollkit/ethereum/rpc/api" rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" "github.com/artela-network/artela-rollkit/ethereum/rpc/utils" evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" @@ -38,162 +38,250 @@ import ( // Blockchain API -func (b *BackendImpl) SetHead(_ uint64) { - b.logger.Error("SetHead is not implemented") -} - -func (b *BackendImpl) HeaderByNumber(_ context.Context, number rpc.BlockNumber) (*ethtypes.Header, error) { - resBlock, err := b.CosmosBlockByNumber(number) +// GetProof returns an account object with proof and any storage proofs +func (b *BackendImpl) GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) { + numberOrHash := rpc.BlockNumberOrHash{ + BlockNumber: (*rpc.BlockNumber)(blockNrOrHash.BlockNumber), + BlockHash: blockNrOrHash.BlockHash, + RequireCanonical: false, + } + blockNum, err := b.blockNumberFromCosmos(numberOrHash) if err != nil { return nil, err } - if resBlock == nil { - return nil, fmt.Errorf("block not found for height %d", number) - } + height := blockNum.Int64() - blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + _, err = b.CosmosBlockByNumber(blockNum) if err != nil { - return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) + // the error message imitates geth behavior + return nil, fmt.Errorf("block not valid, %v", err) } + ctx := rpctypes.ContextWithHeight(height) - bloom, err := b.blockBloom(blockRes) - if err != nil { - b.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) - } + // if the height is equal to zero, meaning the query condition of the block is either "pending" or "latest" + if height == 0 { + bn, err := b.BlockNumber() + if err != nil { + return nil, err + } - baseFee, err := b.BaseFee(blockRes) - if err != nil { - // handle the error for pruned node. - b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", resBlock.Block.Height, "error", err) + if bn > math.MaxInt64 { + return nil, fmt.Errorf("not able to query block number greater than MaxInt64") + } + + height = int64(bn) // #nosec G701 -- checked for int overflow already } - ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header, bloom, baseFee) - return ethHeader, nil -} + clientCtx := b.clientCtx.WithHeight(height) -func (b *BackendImpl) HeaderByHash(_ context.Context, hash common.Hash) (*ethtypes.Header, error) { - return nil, nil -} + // query storage proofs + storageProofs := make([]rpctypes.StorageResult, len(storageKeys)) -func (b *BackendImpl) HeaderByNumberOrHash(ctx context.Context, - blockNrOrHash rpc.BlockNumberOrHash, -) (*ethtypes.Header, error) { - return nil, errors.New("HeaderByNumberOrHash is not implemented") -} + for i, key := range storageKeys { + hexKey := common.HexToHash(key) + valueBz, proof, err := b.queryClient.GetProof(clientCtx, evmtypes.StoreKey, evmtypes.StateKey(address, hexKey.Bytes())) + if err != nil { + return nil, err + } + + storageProofs[i] = rpctypes.StorageResult{ + Key: key, + Value: (*hexutil.Big)(new(big.Int).SetBytes(valueBz)), + Proof: utils.GetHexProofs(proof), + } + } + + // query EVM account + req := &evmtypes.QueryAccountRequest{ + Address: address.String(), + } -func (b *BackendImpl) CurrentHeader() (*ethtypes.Header, error) { - block, err := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber) + res, err := b.queryClient.Account(ctx, req) if err != nil { return nil, err } - if block == nil || block.Header() == nil { - return nil, errors.New("current block header not found") + + // query account proofs + accountKey := append(authtypes.AddressStoreKeyPrefix, sdktypes.AccAddress(address.Bytes()).Bytes()...) + _, proof, err := b.queryClient.GetProof(clientCtx, authtypes.StoreKey, accountKey) + if err != nil { + return nil, err } - return block.Header(), nil -} -func (b *BackendImpl) CurrentBlock() *rpctypes.Block { - block, _ := b.currentBlock() - return block + balance, ok := sdkmath.NewIntFromString(res.Balance) + if !ok { + return nil, errors.New("invalid balance") + } + + return &rpctypes.AccountResult{ + Address: address, + AccountProof: utils.GetHexProofs(proof), + Balance: (*hexutil.Big)(balance.BigInt()), + CodeHash: common.HexToHash(res.CodeHash), + Nonce: hexutil.Uint64(res.Nonce), + StorageHash: common.Hash{}, // NOTE: Evmos doesn't have a storage hash. TODO: implement? + StorageProof: storageProofs, + }, nil } -func (b *BackendImpl) currentBlock() (*rpctypes.Block, error) { - block, err := b.ArtBlockByNumber(context.Background(), rpc.LatestBlockNumber) +func (b *BackendImpl) DoCall(args rpctypes.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash) (*evmtypes.MsgEthereumTxResponse, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) if err != nil { - b.logger.Error("get CurrentBlock failed", "error", err) return nil, err } - return block, nil -} -func (b *BackendImpl) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*ethtypes.Block, error) { - block, err := b.ArtBlockByNumber(ctx, number) + bz, err := json.Marshal(&args) if err != nil { return nil, err } - return block.EthBlock(), nil -} + header, err := b.CosmosBlockByNumber(blockNum) + if err != nil { + // the error message imitates geth behavior + return nil, errors.New("header not found") + } -func (b *BackendImpl) ArtBlockByNumber(_ context.Context, number rpc.BlockNumber) (*rpctypes.Block, error) { - resBlock, err := b.CosmosBlockByNumber(number) - if err != nil || resBlock == nil { - return nil, fmt.Errorf("query block failed, block number %d, %w", number, err) + req := evmtypes.EthCallRequest{ + Args: bz, + GasCap: b.RPCGasCap(), + ProposerAddress: sdktypes.ConsAddress(header.Block.ProposerAddress), + ChainId: b.chainID.Int64(), } - blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + // From ContextWithHeight: if the provided height is 0, + // it will return an empty context and the gRPC query will use + // the latest block height for querying. + ctx := rpctypes.ContextWithHeight(blockNum.Int64()) + timeout := b.RPCEVMTimeout() + + // Setup context so it may be canceled the call has completed + // or, in case of unmetered gas, setup a context with a timeout. + var cancel context.CancelFunc + if timeout > 0 { + ctx, cancel = context.WithTimeout(ctx, timeout) + } else { + ctx, cancel = context.WithCancel(ctx) + } + + // Make sure the context is canceled when the call has completed + // this makes sure resources are cleaned up. + defer cancel() + + res, err := b.queryClient.EthCall(ctx, &req) if err != nil { - return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) + return nil, err } - return b.BlockFromCosmosBlock(resBlock, blockRes) + if res.Failed() { + if res.VmError != vm.ErrExecutionReverted.Error() { + return nil, status.Error(codes.Internal, res.VmError) + } + return nil, evmtypes.NewExecErrorWithReason(res.Ret) + } + + return res, nil } -func (b *BackendImpl) BlockByHash(_ context.Context, hash common.Hash) (*rpctypes.Block, error) { - resBlock, err := b.CosmosBlockByHash(hash) - if err != nil || resBlock == nil { - return nil, fmt.Errorf("failed to get block by hash %s, %w", hash.Hex(), err) +func (b *BackendImpl) EstimateGas(ctx context.Context, args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { + blockNum := rpc.LatestBlockNumber + if blockNrOrHash != nil { + blockNum, _ = b.blockNumberFromCosmos(*blockNrOrHash) } - blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + bz, err := json.Marshal(&args) if err != nil { - return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) + return 0, err } - return b.BlockFromCosmosBlock(resBlock, blockRes) -} + header, err := b.CosmosBlockByNumber(blockNum) + if err != nil { + // the error message imitates geth behavior + return 0, errors.New("header not found") + } -func (b *BackendImpl) BlockByNumberOrHash(_ context.Context, _ rpc.BlockNumberOrHash) (*rpctypes.Block, error) { - return nil, errors.New("BlockByNumberOrHash is not implemented") -} + req := evmtypes.EthCallRequest{ + Args: bz, + GasCap: b.RPCGasCap(), + ProposerAddress: sdktypes.ConsAddress(header.Block.ProposerAddress), + ChainId: b.chainID.Int64(), + } -func (b *BackendImpl) StateAndHeaderByNumber( - _ context.Context, number rpc.BlockNumber, -) (*state.StateDB, *ethtypes.Header, error) { - return nil, nil, errors.New("StateAndHeaderByNumber is not implemented") + // From ContextWithHeight: if the provided height is 0, + // it will return an empty context and the gRPC query will use + // the latest block height for querying. + res, err := b.queryClient.EstimateGas(rpctypes.ContextWithHeight(blockNum.Int64()), &req) + if err != nil { + return 0, err + } + return hexutil.Uint64(res.Gas), nil } -func (b *BackendImpl) StateAndHeaderByNumberOrHash( - _ context.Context, _ rpc.BlockNumberOrHash, -) (*state.StateDB, *ethtypes.Header, error) { - return nil, nil, errors.New("invalid arguments; neither block nor hash specified") -} +func (b *BackendImpl) HeaderByNumber(_ context.Context, number rpc.BlockNumber) (*ethtypes.Header, error) { + resBlock, err := b.CosmosBlockByNumber(number) + if err != nil { + return nil, err + } -func (b *BackendImpl) PendingBlockAndReceipts() (*ethtypes.Block, ethtypes.Receipts) { - b.logger.Error("PendingBlockAndReceipts is not implemented") - return nil, nil -} + if resBlock == nil { + return nil, fmt.Errorf("block not found for height %d", number) + } -// GetReceipts get receipts by block hash -func (b *BackendImpl) GetReceipts(_ context.Context, _ common.Hash) (ethtypes.Receipts, error) { - return nil, errors.New("GetReceipts is not implemented") -} + blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + if err != nil { + return nil, fmt.Errorf("block result not found for height %d", resBlock.Block.Height) + } -func (b *BackendImpl) GetTd(_ context.Context, _ common.Hash) *big.Int { - b.logger.Error("GetTd is not implemented") - return nil + bloom, err := b.blockBloom(blockRes) + if err != nil { + b.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) + } + + baseFee, err := b.BaseFee(blockRes) + if err != nil { + // handle the error for pruned node. + b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", resBlock.Block.Height, "error", err) + } + + ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header, bloom, baseFee) + return ethHeader, nil } -func (b *BackendImpl) GetEVM(_ context.Context, _ *core.Message, _ *state.StateDB, - _ *ethtypes.Header, _ *vm.Config, _ *vm.BlockContext, -) (*vm.EVM, func() error) { - return nil, func() error { - return errors.New("GetEVM is not impelemted") +func (b *BackendImpl) HeaderByHash(ctx context.Context, hash common.Hash) (*ethtypes.Header, error) { + block, err := b.BlockByHash(ctx, hash) + if err != nil { + return nil, err } + if block == nil { + return nil, errors.New("block not found") + } + return block.Header(), nil } -func (b *BackendImpl) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { - return b.scope.Track(b.chainFeed.Subscribe(ch)) +func (b *BackendImpl) HeaderByNumberOrHash(ctx context.Context, + blockNrOrHash rpc.BlockNumberOrHash, +) (*ethtypes.Header, error) { + block, err := b.ArtBlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + if block == nil { + return nil, errors.New("block not found") + } + return block.Header(), nil } -func (b *BackendImpl) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { - b.logger.Debug("called eth.rpc.backend.SubscribeChainHeadEvent", "ch", ch) - return b.scope.Track(b.chainHeadFeed.Subscribe(ch)) +func (b *BackendImpl) CurrentBlock() *rpctypes.Block { + block, _ := b.currentBlock() + return block } -func (b *BackendImpl) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { - b.logger.Debug("called eth.rpc.backend.SubscribeChainSideEvent", "ch", ch) - return b.scope.Track(b.chainSideFeed.Subscribe(ch)) +func (b *BackendImpl) ArtBlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*rpctypes.Block, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return nil, err + } + + return b.ArtBlockByNumber(ctx, blockNum) } func (b *BackendImpl) CosmosBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) { @@ -235,6 +323,92 @@ func (b *BackendImpl) CosmosBlockByNumber(blockNum rpc.BlockNumber) (*tmrpctypes return resBlock, nil } +func (b *BackendImpl) GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return nil, err + } + + req := &evmtypes.QueryCodeRequest{ + Address: address.String(), + } + + res, err := b.queryClient.Code(rpctypes.ContextWithHeight(blockNum.Int64()), req) + if err != nil { + return nil, err + } + + return res.Code, nil +} + +// GetStorageAt returns the contract storage at the given address, block number, and key. +func (b *BackendImpl) GetStorageAt(address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return nil, err + } + + req := &evmtypes.QueryStorageRequest{ + Address: address.String(), + Key: key, + } + + res, err := b.queryClient.Storage(rpctypes.ContextWithHeight(blockNum.Int64()), req) + if err != nil { + return nil, err + } + + value := common.HexToHash(res.Value) + return value.Bytes(), nil +} + +func (b *BackendImpl) GetCoinbase() (sdktypes.AccAddress, error) { + node, err := b.clientCtx.GetNode() + if err != nil { + return nil, err + } + + status, err := node.Status(b.ctx) + if err != nil { + return nil, err + } + + req := &evmtypes.QueryValidatorAccountRequest{ + ConsAddress: sdktypes.ConsAddress(status.ValidatorInfo.Address).String(), + } + + res, err := b.queryClient.ValidatorAccount(b.ctx, req) + if err != nil { + return nil, err + } + + address, _ := sdktypes.AccAddressFromBech32(res.AccountAddress) // #nosec G703 + return address, nil +} + +func (b *BackendImpl) currentBlock() (*rpctypes.Block, error) { + block, err := b.ArtBlockByNumber(context.Background(), rpc.LatestBlockNumber) + if err != nil { + b.logger.Error("get CurrentBlock failed", "error", err) + return nil, err + } + return block, nil +} + +func (b *BackendImpl) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + return b.scope.Track(b.chainFeed.Subscribe(ch)) +} + +func (b *BackendImpl) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + b.logger.Debug("called eth.rpc.rpctypes.SubscribeChainHeadEvent", "ch", ch) + return b.scope.Track(b.chainHeadFeed.Subscribe(ch)) +} + +func (b *BackendImpl) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { + b.logger.Debug("called eth.rpc.rpctypes.SubscribeChainSideEvent", "ch", ch) + return b.scope.Track(b.chainSideFeed.Subscribe(ch)) +} + // BlockNumberFromTendermint returns the BlockNumber from BlockNumberOrHash func (b *BackendImpl) blockNumberFromCosmos(blockNrOrHash rpc.BlockNumberOrHash) (rpc.BlockNumber, error) { switch { @@ -297,45 +471,6 @@ func (b *BackendImpl) CosmosBlockResultByNumber(height *int64) (*tmrpctypes.Resu return b.clientCtx.Client.BlockResults(b.ctx, height) } -func (b *BackendImpl) GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) - if err != nil { - return nil, err - } - - req := &evmtypes.QueryCodeRequest{ - Address: address.String(), - } - - res, err := b.queryClient.Code(rpctypes.ContextWithHeight(blockNum.Int64()), req) - if err != nil { - return nil, err - } - - return res.Code, nil -} - -// GetStorageAt returns the contract storage at the given address, block number, and key. -func (b *BackendImpl) GetStorageAt(address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) - if err != nil { - return nil, err - } - - req := &evmtypes.QueryStorageRequest{ - Address: address.String(), - Key: key, - } - - res, err := b.queryClient.Storage(rpctypes.ContextWithHeight(blockNum.Int64()), req) - if err != nil { - return nil, err - } - - value := common.HexToHash(res.Value) - return value.Bytes(), nil -} - // BlockBloom query block bloom filter from block results func (b *BackendImpl) blockBloom(blockRes *tmrpctypes.ResultBlockResults) (ethtypes.Bloom, error) { for _, event := range blockRes.FinalizeBlockEvents { @@ -396,12 +531,8 @@ func (b *BackendImpl) BlockFromCosmosBlock(resBlock *tmrpctypes.ResultBlock, blo ethHeader.GasLimit = uint64(gasLimit) blockHash := common.BytesToHash(block.Hash().Bytes()) - receipts, err := b.GetReceipts(context.Background(), blockHash) - if err != nil { - b.logger.Debug(fmt.Sprintf("failed to fetch receipts, block hash %s, block number %d", blockHash.Hex(), height)) - } - ethBlock := ethtypes.NewBlock(ethHeader, txs, nil, receipts, trie.NewStackTrie(nil)) + ethBlock := ethtypes.NewBlock(ethHeader, txs, nil, nil, trie.NewStackTrie(nil)) res := rpctypes.EthBlockToBlock(ethBlock) res.SetHash(blockHash) return res, nil @@ -442,74 +573,17 @@ func (b *BackendImpl) EthMsgsFromCosmosBlock(resBlock *tmrpctypes.ResultBlock, b return result } -func (b *BackendImpl) DoCall(args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash) (*evmtypes.MsgEthereumTxResponse, error) { - blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) - if err != nil { - return nil, err - } - - bz, err := json.Marshal(&args) - if err != nil { - return nil, err - } - header, err := b.CosmosBlockByNumber(blockNum) - if err != nil { - // the error message imitates geth behavior - return nil, errors.New("header not found") - } - - req := evmtypes.EthCallRequest{ - Args: bz, - GasCap: b.RPCGasCap(), - ProposerAddress: sdktypes.ConsAddress(header.Block.ProposerAddress), - ChainId: b.chainID.Int64(), - } - - // From ContextWithHeight: if the provided height is 0, - // it will return an empty context and the gRPC query will use - // the latest block height for querying. - ctx := rpctypes.ContextWithHeight(blockNum.Int64()) - timeout := b.RPCEVMTimeout() - - // Setup context so it may be canceled the call has completed - // or, in case of unmetered gas, setup a context with a timeout. - var cancel context.CancelFunc - if timeout > 0 { - ctx, cancel = context.WithTimeout(ctx, timeout) - } else { - ctx, cancel = context.WithCancel(ctx) - } - - // Make sure the context is canceled when the call has completed - // this makes sure resources are cleaned up. - defer cancel() - - res, err := b.queryClient.EthCall(ctx, &req) - if err != nil { - return nil, err - } - - if res.Failed() { - if res.VmError != vm.ErrExecutionReverted.Error() { - return nil, status.Error(codes.Internal, res.VmError) - } - return nil, evmtypes.NewExecErrorWithReason(res.Ret) - } - - return res, nil -} - func (b *BackendImpl) BlockBloom(blockRes *tmrpctypes.ResultBlockResults) (ethtypes.Bloom, error) { return b.blockBloom(blockRes) } func (b *BackendImpl) GetBlockByNumber(blockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { - block, err := b.BlockByNumber(context.Background(), blockNum) + block, err := b.ArtBlockByNumber(context.Background(), blockNum) if err != nil { return nil, err } - return ethapi.RPCMarshalHeader(block.Header(), block.Hash()), nil + return api.RPCMarshalHeader(block.Header(), block.Hash()), nil } func (b *BackendImpl) processBlock( @@ -618,6 +692,46 @@ func (b *BackendImpl) processBlock( return targetOneFeeHistory, nil } +func (b *BackendImpl) GetDenomByAddress(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (string, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return "", err + } + + req := evmtypes.DenomByAddressRequest{ + Address: address.String(), + } + + // From ContextWithHeight: if the provided height is 0, + // it will return an empty context and the gRPC query will use + // the latest block height for querying. + res, err := b.queryClient.DenomByAddress(rpctypes.ContextWithHeight(blockNum.Int64()), &req) + if err != nil { + return "", err + } + return res.Denom, nil +} + +func (b *BackendImpl) GetAddressByDenom(ctx context.Context, denom string, blockNrOrHash rpc.BlockNumberOrHash) ([]string, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return nil, err + } + + req := evmtypes.AddressByDenomRequest{ + Denom: denom, + } + + // From ContextWithHeight: if the provided height is 0, + // it will return an empty context and the gRPC query will use + // the latest block height for querying. + res, err := b.queryClient.AddressByDenom(rpctypes.ContextWithHeight(blockNum.Int64()), &req) + if err != nil { + return nil, err + } + return res.Address, nil +} + type txGasAndReward struct { gasUsed uint64 reward *big.Int diff --git a/ethereum/rpc/tracing.go b/ethereum/rpc/debug.go similarity index 70% rename from ethereum/rpc/tracing.go rename to ethereum/rpc/debug.go index bfa9014..4bb04b7 100644 --- a/ethereum/rpc/tracing.go +++ b/ethereum/rpc/debug.go @@ -1,9 +1,12 @@ package rpc import ( + "context" "encoding/json" "fmt" "math" + "math/big" + "strings" "github.com/pkg/errors" @@ -11,6 +14,8 @@ import ( tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" @@ -210,3 +215,73 @@ func (b *BackendImpl) TraceBlock(height rpc.BlockNumber, return decodedResults, nil } + +// GetReceipts get receipts by block hash +func (b *BackendImpl) GetReceipts(ctx context.Context, hash common.Hash) (ethtypes.Receipts, error) { + resBlock, err := b.CosmosBlockByHash(hash) + if err != nil || resBlock == nil || resBlock.Block == nil { + return nil, fmt.Errorf("query block failed, block hash %s, %w", hash.String(), err) + } + + blockRes, err := b.CosmosBlockResultByNumber(&resBlock.Block.Height) + if err != nil { + b.logger.Debug("GetTransactionReceipt failed", "error", err) + return nil, nil + } + + msgs := b.EthMsgsFromCosmosBlock(resBlock, blockRes) + + receipts := make([]*ethtypes.Receipt, 0, len(msgs)) + for _, msg := range msgs { + receipt, err := b.GetTransactionReceipt(ctx, common.HexToHash(msg.Hash)) + if err != nil || receipt == nil { + errMsg := "" + if err != nil { + errMsg = err.Error() + } + b.logger.Error("eth_getReceipts failed", "error", errMsg, "txHash", msg.Hash) + continue + } + var contractAddress common.Address + if receipt["contractAddress"] != nil { + contractAddress = receipt["contractAddress"].(common.Address) + } + var effectiveGasPrice big.Int + if receipt["effectiveGasPrice"] != nil { + effectiveGasPrice = big.Int(receipt["effectiveGasPrice"].(hexutil.Big)) + } + receipts = append(receipts, ðtypes.Receipt{ + Type: uint8(receipt["type"].(hexutil.Uint)), + PostState: []byte{}, + Status: uint64(receipt["status"].(hexutil.Uint)), + CumulativeGasUsed: uint64(receipt["cumulativeGasUsed"].(hexutil.Uint64)), + Bloom: receipt["logsBloom"].(ethtypes.Bloom), + Logs: receipt["logs"].([]*ethtypes.Log), + TxHash: receipt["transactionHash"].(common.Hash), + ContractAddress: contractAddress, + GasUsed: uint64(receipt["gasUsed"].(hexutil.Uint64)), + EffectiveGasPrice: &effectiveGasPrice, + BlockHash: common.BytesToHash(resBlock.BlockID.Hash.Bytes()), + BlockNumber: big.NewInt(resBlock.Block.Height), + TransactionIndex: uint(receipt["transactionIndex"].(hexutil.Uint64)), + }) + } + return receipts, nil +} + +func (b *BackendImpl) DBProperty(property string) (string, error) { + if b.db == nil || b.db.Stats() == nil { + return "", errors.New("property is not valid") + } + if property == "" { + property = "leveldb.stats" + } else if !strings.HasPrefix(property, "leveldb.") { + property = "leveldb." + property + } + + return (b.db.Stats())[property], nil +} + +func (b *BackendImpl) DBCompact(start []byte, limit []byte) error { + return errors.New("compact is not valid") +} diff --git a/ethereum/rpc/eth.go b/ethereum/rpc/eth.go new file mode 100644 index 0000000..5214152 --- /dev/null +++ b/ethereum/rpc/eth.go @@ -0,0 +1,184 @@ +package rpc + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/rpc" + + rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" + feetypes "github.com/artela-network/artela-rollkit/x/fee/types" +) + +func (b *BackendImpl) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { + if baseFee == nil { + // london hardfork not enabled or feemarket not enabled + return big.NewInt(0), nil + } + + params, err := b.queryClient.FeeMarket.Params(b.ctx, &feetypes.QueryParamsRequest{}) + if err != nil { + return nil, err + } + // calculate the maximum base fee delta in current block, assuming all block gas limit is consumed + // ``` + // GasTarget = GasLimit / ElasticityMultiplier + // Delta = BaseFee * (GasUsed - GasTarget) / GasTarget / Denominator + // ``` + // The delta is at maximum when `GasUsed` is equal to `GasLimit`, which is: + // ``` + // MaxDelta = BaseFee * (GasLimit - GasLimit / ElasticityMultiplier) / (GasLimit / ElasticityMultiplier) / Denominator + // = BaseFee * (ElasticityMultiplier - 1) / Denominator + // ```t + maxDelta := baseFee.Int64() * (int64(params.Params.ElasticityMultiplier) - 1) / int64(params.Params.BaseFeeChangeDenominator) // #nosec G701 + if maxDelta < 0 { + // impossible if the parameter validation passed. + maxDelta = 0 + } + return big.NewInt(maxDelta), nil +} + +func (b *BackendImpl) GasPrice(ctx context.Context) (*hexutil.Big, error) { + var ( + result *big.Int + err error + ) + if head, err := b.CurrentHeader(); err == nil && head.BaseFee != nil { + result, err = b.SuggestGasTipCap(head.BaseFee) + if err != nil { + return nil, err + } + result = result.Add(result, head.BaseFee) + } else { + result = big.NewInt(b.RPCMinGasPrice()) + } + + // return at least GlobalMinGasPrice from FeeMarket module + minGasPrice, err := b.GlobalMinGasPrice() + if err != nil { + return nil, err + } + minGasPriceInt := minGasPrice.TruncateInt().BigInt() + if result.Cmp(minGasPriceInt) < 0 { + result = minGasPriceInt + } + + return (*hexutil.Big)(result), nil +} + +func (b *BackendImpl) FeeHistory(blockCount uint64, lastBlock rpc.BlockNumber, + rewardPercentiles []float64, +) (*rpctypes.FeeHistoryResult, error) { + blockEnd := int64(lastBlock) + + if blockEnd < 0 { + blockNumber, err := b.BlockNumber() + if err != nil { + return nil, err + } + blockEnd = int64(blockNumber) + } + + blocks := int64(blockCount) + maxBlockCount := int64(b.cfg.AppCfg.JSONRPC.FeeHistoryCap) + if blocks > maxBlockCount { + return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", blocks, maxBlockCount) + } + + if blockEnd+1 < blocks { + blocks = blockEnd + 1 + } + + blockStart := blockEnd + 1 - blocks + oldestBlock := (*hexutil.Big)(big.NewInt(blockStart)) + + reward := make([][]*hexutil.Big, blocks) + rewardCount := len(rewardPercentiles) + for i := 0; i < int(blocks); i++ { + reward[i] = make([]*hexutil.Big, rewardCount) + } + + thisBaseFee := make([]*hexutil.Big, blocks+1) + thisGasUsedRatio := make([]float64, blocks) + calculateRewards := rewardCount != 0 + + for blockID := blockStart; blockID <= blockEnd; blockID++ { + index := int32(blockID - blockStart) // #nosec G701 + // tendermint block + tendermintblock, err := b.CosmosBlockByNumber(rpc.BlockNumber(blockID)) + if tendermintblock == nil { + return nil, err + } + + // eth block + ethBlock, err := b.GetBlockByNumber(rpc.BlockNumber(blockID), true) + if ethBlock == nil { + return nil, err + } + + // tendermint block result + tendermintBlockResult, err := b.CosmosBlockResultByNumber(&tendermintblock.Block.Height) + if tendermintBlockResult == nil { + b.logger.Debug("block result not found", "height", tendermintblock.Block.Height, "error", err.Error()) + return nil, err + } + + oneFeeHistory, err := b.processBlock(tendermintblock, ðBlock, rewardPercentiles, tendermintBlockResult) + if err != nil { + return nil, err + } + + // copy + thisBaseFee[index] = (*hexutil.Big)(oneFeeHistory.BaseFee) + thisBaseFee[index+1] = (*hexutil.Big)(oneFeeHistory.NextBaseFee) + thisGasUsedRatio[index] = oneFeeHistory.GasUsedRatio + if calculateRewards { + for j := 0; j < rewardCount; j++ { + reward[index][j] = (*hexutil.Big)(oneFeeHistory.Reward[j]) + if reward[index][j] == nil { + reward[index][j] = (*hexutil.Big)(big.NewInt(0)) + } + } + } + } + + feeHistory := rpctypes.FeeHistoryResult{ + OldestBlock: oldestBlock, + BaseFee: thisBaseFee, + GasUsedRatio: thisGasUsedRatio, + } + + if calculateRewards { + feeHistory.Reward = reward + } + + return &feeHistory, nil +} + +func (b *BackendImpl) Engine() consensus.Engine { + // only for ethereum, pow -> pos + b.logger.Error("Engine is not valid") + return nil +} + +func (b *BackendImpl) Syncing() (interface{}, error) { + status, err := b.clientCtx.Client.Status(b.ctx) + if err != nil { + return false, err + } + + if !status.SyncInfo.CatchingUp { + return false, nil + } + + return map[string]interface{}{ + "startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight), + "currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight), + // "highestBlock": nil, // NA + // "pulledStates": nil, // NA + // "knownStates": nil, // NA + }, nil +} diff --git a/ethereum/rpc/ethapi/backend.go b/ethereum/rpc/ethapi/backend.go deleted file mode 100644 index 2a7b431..0000000 --- a/ethereum/rpc/ethapi/backend.go +++ /dev/null @@ -1,74 +0,0 @@ -package ethapi - -import ( - "context" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/artela-network/artela-evm/vm" - - rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" - evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" -) - -// Backend interface provides the common API services (that are provided by -// both full and light clients) with access to necessary functions. -type Backend interface { - // General Ethereum API - SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) - GasPrice(ctx context.Context) (*hexutil.Big, error) - - // Account releated - Accounts() []common.Address - NewAccount(password string) (common.AddressEIP55, error) - ImportRawKey(privkey, password string) (common.Address, error) - GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) - GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) - - // Blockchain API - HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) - HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) - HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) - CurrentHeader() (*types.Header, error) - CurrentBlock() *rpctypes.Block - BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) - ArtBlockByNumber(ctx context.Context, number rpc.BlockNumber) (*rpctypes.Block, error) - BlockByHash(ctx context.Context, hash common.Hash) (*rpctypes.Block, error) - BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*rpctypes.Block, error) - StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) - StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) - GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) - GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) - GetStorageAt(address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) - FeeHistory(blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error) - - // Transaction pool API - SendTx(ctx context.Context, signedTx *types.Transaction) error - GetTransaction(ctx context.Context, txHash common.Hash) (*RPCTransaction, error) - SignTransaction(args *TransactionArgs) (*types.Transaction, error) - GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) - RPCTxFeeCap() float64 - UnprotectedAllowed() bool - EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) - DoCall(args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash) (*evmtypes.MsgEthereumTxResponse, error) - - ChainConfig() *params.ChainConfig - Engine() consensus.Engine - - Syncing() (interface{}, error) - // This is copied from filters.Backend - Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) - - GetCoinbase() (sdk.AccAddress, error) - - GetProof(address common.Address, storageKeys []string, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccountResult, error) -} diff --git a/ethereum/rpc/gas_oracle.go b/ethereum/rpc/gas_oracle.go new file mode 100644 index 0000000..631f78c --- /dev/null +++ b/ethereum/rpc/gas_oracle.go @@ -0,0 +1,37 @@ +package rpc + +import ( + "context" + + "github.com/ethereum/go-ethereum/core/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" +) + +// BlockByNumber for OracleBackend, should not use it anywhere, unless you know about the block hash diffs. +// Use ArtBlockByNumber instead. +func (b *BackendImpl) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*ethtypes.Block, error) { + // DO NOT USE THIS METHOD, THIS JUST FOR OracleBackend + block, err := b.ArtBlockByNumber(ctx, number) + if err != nil { + return nil, err + } + // BEWARE THE HASH OF THIS BLOCK IS NOT MATCH TO WHAT WAS STORED IN COSMOS DB + return block.EthBlock(), nil +} + +// BlockByNumberOrHash for OracleBackend, should not use it anywhere, unless you know about the block hash diffs. +// Use ArtBlockByNumberOrHash instead. +func (b *BackendImpl) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*ethtypes.Block, error) { + blockNum, err := b.blockNumberFromCosmos(blockNrOrHash) + if err != nil { + return nil, err + } + + // BEWARE THE HASH OF THIS BLOCK IS NOT MATCH TO WHAT WAS STORED IN COSMOS DB + return b.BlockByNumber(ctx, blockNum) +} + +func (b *BackendImpl) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + return nil, nil +} diff --git a/ethereum/rpc/net.go b/ethereum/rpc/net.go new file mode 100644 index 0000000..863340b --- /dev/null +++ b/ethereum/rpc/net.go @@ -0,0 +1,30 @@ +package rpc + +import ( + "github.com/cometbft/cometbft/rpc/client" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func (b *BackendImpl) Listening() bool { + tmClient := b.clientCtx.Client.(client.Client) + netInfo, err := tmClient.NetInfo(b.ctx) + if err != nil { + return false + } + return netInfo.Listening +} + +func (b *BackendImpl) PeerCount() hexutil.Uint { + tmClient := b.clientCtx.Client.(client.Client) + netInfo, err := tmClient.NetInfo(b.ctx) + if err != nil { + return 0 + } + return hexutil.Uint(len(netInfo.Peers)) +} + +// Version returns the current ethereum protocol version. +func (b *BackendImpl) Version() string { + v, _ := b.version() + return v +} diff --git a/ethereum/rpc/node.go b/ethereum/rpc/node.go index 9ad5bdc..0d4437c 100644 --- a/ethereum/rpc/node.go +++ b/ethereum/rpc/node.go @@ -51,5 +51,6 @@ func DefaultGethNodeConfig() *node.Config { nodeCfg.HTTPVirtualHosts = []string{"*"} nodeCfg.GraphQLCors = []string{"*"} nodeCfg.GraphQLVirtualHosts = []string{"*"} + nodeCfg.EnablePersonal = true return &nodeCfg } diff --git a/ethereum/rpc/personal.go b/ethereum/rpc/personal.go new file mode 100644 index 0000000..9c13f3b --- /dev/null +++ b/ethereum/rpc/personal.go @@ -0,0 +1,74 @@ +package rpc + +import ( + "fmt" + "time" + + sdkcrypto "github.com/cosmos/cosmos-sdk/crypto" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/artela-network/artela-rollkit/ethereum/crypto/ethsecp256k1" + "github.com/artela-network/artela-rollkit/ethereum/crypto/hd" + types2 "github.com/artela-network/artela-rollkit/ethereum/types" +) + +func (b *BackendImpl) NewAccount(password string) (common.AddressEIP55, error) { + name := "key_" + time.Now().UTC().Format(time.RFC3339) + + cfg := sdktypes.GetConfig() + basePath := cfg.GetFullBIP44Path() + + hdPathIter, err := types2.NewHDPathIterator(basePath, true) + if err != nil { + b.logger.Info("NewHDPathIterator failed", "error", err) + return common.AddressEIP55{}, err + } + // create the mnemonic and save the account + hdPath := hdPathIter() + + info, _, err := b.clientCtx.Keyring.NewMnemonic(name, keyring.English, hdPath.String(), password, hd.EthSecp256k1) + if err != nil { + b.logger.Info("NewMnemonic failed", "error", err) + return common.AddressEIP55{}, err + } + + pubKey, err := info.GetPubKey() + if err != nil { + b.logger.Info("GetPubKey failed", "error", err) + return common.AddressEIP55{}, err + } + addr := common.BytesToAddress(pubKey.Address().Bytes()) + return common.AddressEIP55(addr), nil +} + +func (b *BackendImpl) ImportRawKey(privkey, password string) (common.Address, error) { + priv, err := crypto.HexToECDSA(privkey) + if err != nil { + return common.Address{}, err + } + + privKey := ðsecp256k1.PrivKey{Key: crypto.FromECDSA(priv)} + + addr := sdktypes.AccAddress(privKey.PubKey().Address().Bytes()) + ethereumAddr := common.BytesToAddress(addr) + + // return if the key has already been imported + if _, err := b.clientCtx.Keyring.KeyByAddress(addr); err == nil { + return ethereumAddr, nil + } + + // ignore error as we only care about the length of the list + list, _ := b.clientCtx.Keyring.List() // #nosec G703 + privKeyName := fmt.Sprintf("personal_%d", len(list)) + + armor := sdkcrypto.EncryptArmorPrivKey(privKey, password, ethsecp256k1.KeyType) + + if err := b.clientCtx.Keyring.ImportPrivKey(privKeyName, armor, password); err != nil { + return common.Address{}, err + } + + return ethereumAddr, nil +} diff --git a/ethereum/rpc/service.go b/ethereum/rpc/service.go index 1610718..27afa84 100644 --- a/ethereum/rpc/service.go +++ b/ethereum/rpc/service.go @@ -2,6 +2,7 @@ package rpc import ( rpcclient "github.com/cometbft/cometbft/rpc/jsonrpc/client" + db "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/server" "github.com/ethereum/go-ethereum/log" @@ -12,6 +13,7 @@ import ( type ArtelaService struct { clientCtx client.Context + serverCtx *server.Context wsClient *rpcclient.WSClient cfg *Config stack types.NetworkingStack @@ -26,21 +28,23 @@ func NewArtelaService( cfg *Config, stack types.NetworkingStack, logger log.Logger, + db db.DB, ) *ArtelaService { art := &ArtelaService{ cfg: cfg, stack: stack, clientCtx: clientCtx, + serverCtx: ctx, wsClient: wsClient, logger: logger, } - art.backend = NewBackend(ctx, clientCtx, art, stack.ExtRPCEnabled(), cfg, logger) + art.backend = NewBackend(ctx, clientCtx, art, stack.ExtRPCEnabled(), cfg, logger, db) return art } func (art *ArtelaService) APIs() []rpc.API { - return GetAPIs(art.clientCtx, art.wsClient, art.logger, art.backend) + return GetAPIs(art.clientCtx, art.serverCtx, art.wsClient, art.logger, art.backend) } // Start start the ethereum JsonRPC service diff --git a/ethereum/rpc/tx.go b/ethereum/rpc/tx.go index 3a0ebcd..c61bd47 100644 --- a/ethereum/rpc/tx.go +++ b/ethereum/rpc/tx.go @@ -2,31 +2,36 @@ package rpc import ( "context" - "encoding/json" "errors" "fmt" + "math/big" errorsmod "cosmossdk.io/errors" + rpcclient "github.com/cometbft/cometbft/rpc/client" "github.com/cosmos/cosmos-sdk/client/flags" sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/artela-network/artela-rollkit/common/aspect" - "github.com/artela-network/artela-rollkit/ethereum/rpc/ethapi" rpctypes "github.com/artela-network/artela-rollkit/ethereum/rpc/types" - "github.com/artela-network/artela-rollkit/ethereum/rpc/utils" + rpcutils "github.com/artela-network/artela-rollkit/ethereum/rpc/utils" "github.com/artela-network/artela-rollkit/ethereum/types" + "github.com/artela-network/artela-rollkit/ethereum/utils" evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" ) -// Transaction pool API +// Transaction API func (b *BackendImpl) SendTx(ctx context.Context, signedTx *ethtypes.Transaction) error { // verify the ethereum tx @@ -84,148 +89,83 @@ func (b *BackendImpl) SendTx(ctx context.Context, signedTx *ethtypes.Transaction return nil } -func (b *BackendImpl) GetTransaction(ctx context.Context, txHash common.Hash) (*ethapi.RPCTransaction, error) { - res, err := b.GetTxByEthHash(txHash) - hexTx := txHash.Hex() +func (b *BackendImpl) GetTransaction(ctx context.Context, txHash common.Hash) (*rpctypes.RPCTransaction, error) { + _, tx, err := b.getTransaction(ctx, txHash) + return tx, err +} +func (b *BackendImpl) GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { + n := hexutil.Uint64(0) + height, err := b.blockNumberFromCosmos(blockNrOrHash) if err != nil { - b.logger.Debug("GetTxByEthHash failed, try to getTransactionByHashPending", "error", err) - return b.getTransactionByHashPending(txHash) + return &n, err } - - block, err := b.CosmosBlockByNumber(rpc.BlockNumber(res.Height)) + header, err := b.CurrentHeader() if err != nil { - return nil, err + return &n, err + } + if height.Int64() > header.Number.Int64() { + return &n, fmt.Errorf( + "cannot query with height in the future (current: %d, queried: %d); please provide a valid height", + header.Number, height) } + // Get nonce (sequence) from account + from := sdktypes.AccAddress(address.Bytes()) + accRet := b.clientCtx.AccountRetriever - tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) + if err = accRet.EnsureExists(b.clientCtx, from); err != nil { + // account doesn't exist yet, return 0 + b.logger.Info("GetTransactionCount faild, return 0. Account doesn't exist yet", "account", address.Hex(), "error", err) + return &n, nil + } + + includePending := height == rpc.PendingBlockNumber + nonce, err := b.getAccountNonce(address, includePending, height.Int64()) if err != nil { return nil, err } - // the `res.MsgIndex` is inferred from tx index, should be within the bound. - msg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - return nil, errors.New("invalid ethereum tx") - } - msg.From = res.Sender + n = hexutil.Uint64(nonce) + return &n, nil +} - blockRes, err := b.CosmosBlockResultByNumber(&block.Block.Height) +func (b *BackendImpl) GetTxMsg(ctx context.Context, txHash common.Hash) (*evmtypes.MsgEthereumTx, error) { + msg, _, err := b.getTransaction(ctx, txHash) + return msg, err +} + +func (b *BackendImpl) SignTransaction(args *rpctypes.TransactionArgs) (*ethtypes.Transaction, error) { + _, err := b.clientCtx.Keyring.KeyByAddress(sdktypes.AccAddress(args.From.Bytes())) if err != nil { - b.logger.Debug("block result not found", "height", block.Block.Height, "error", err.Error()) - return nil, nil + return nil, fmt.Errorf("failed to find key in the node's keyring; %s; %s", keystore.ErrNoMatch, err.Error()) } - if res.EthTxIndex == -1 { - // Fallback to find tx index by iterating all valid eth transactions - msgs := b.EthMsgsFromCosmosBlock(block, blockRes) - for i := range msgs { - if msgs[i].Hash == hexTx { - res.EthTxIndex = int32(i) - break - } - } - } - // if we still unable to find the eth tx index, return error, shouldn't happen. - if res.EthTxIndex == -1 { - return nil, errors.New("can't find index of ethereum tx") + if args.ChainID != nil && (b.chainID).Cmp((*big.Int)(args.ChainID)) != 0 { + return nil, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", args.ChainID, (*hexutil.Big)(b.chainID)) } - baseFee, err := b.BaseFee(blockRes) + bn, err := b.BlockNumber() if err != nil { - // handle the error for pruned node. - b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", blockRes.Height, "error", err) + return nil, err } - cfg, err := b.chainConfig() + bt, err := b.BlockTimeByNumber(int64(bn)) if err != nil { return nil, err } - return ethapi.NewTransactionFromMsg( - msg, - common.BytesToHash(block.BlockID.Hash.Bytes()), - uint64(res.Height), - uint64(res.EthTxIndex), - baseFee, - cfg, - ), nil -} - -func (b *BackendImpl) GetPoolTransactions() (ethtypes.Transactions, error) { - b.logger.Debug("called eth.rpc.backend.GetPoolTransactions") - return nil, errors.New("GetPoolTransactions is not implemented") -} - -func (b *BackendImpl) GetPoolTransaction(txHash common.Hash) *ethtypes.Transaction { - b.logger.Error("GetPoolTransaction is not implemented") - return nil -} - -func (b *BackendImpl) GetPoolNonce(_ context.Context, addr common.Address) (uint64, error) { - return 0, errors.New("GetPoolNonce is not implemented") -} - -func (b *BackendImpl) Stats() (int, int) { - b.logger.Error("Stats is not implemented") - return 0, 0 -} - -func (b *BackendImpl) TxPoolContent() ( - map[common.Address]ethtypes.Transactions, map[common.Address]ethtypes.Transactions, -) { - b.logger.Error("TxPoolContent is not implemented") - return nil, nil -} - -func (b *BackendImpl) TxPoolContentFrom(addr common.Address) ( - ethtypes.Transactions, ethtypes.Transactions, -) { - return nil, nil -} - -func (b *BackendImpl) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { - return b.scope.Track(b.newTxsFeed.Subscribe(ch)) -} - -// Version returns the current ethereum protocol version. -func (b *BackendImpl) Version() string { - v, _ := b.version() - return v -} - -func (b *BackendImpl) version() (string, error) { cfg, err := b.chainConfig() if err != nil { - return "", err - } - - if cfg.ChainID == nil { - b.logger.Error("eth.rpc.backend.Version", "ChainID is nil") - return "", errors.New("chain id is not valid") + return nil, err } - return cfg.ChainID.String(), nil -} - -func (b *BackendImpl) Engine() consensus.Engine { - b.logger.Error("Engine is not implemented") - return nil -} + signer := ethtypes.MakeSigner(cfg, new(big.Int).SetUint64(uint64(bn)), bt) -func (b *BackendImpl) GetTxByEthHash(hash common.Hash) (*types.TxResult, error) { - // if b.indexer != nil { - // return b.indexer.GetByTxHash(hash) - // } + // LegacyTx derives chainID from the signature. To make sure the msg.ValidateBasic makes + // the corresponding chainID validation, we need to sign the transaction before calling it - // fallback to tendermint tx indexer - query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, hash.Hex()) - txResult, err := b.queryCosmosTxIndexer(query, func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx { - return txs.GetTxByHash(hash) - }) - if err != nil { - return nil, fmt.Errorf("GetTxByEthHash %s, %w", hash.Hex(), err) - } - return txResult, nil + // Sign transaction + msg := args.ToEVMTransaction() + return msg.SignEthereumTx(signer, b.clientCtx.Keyring) } // GetTransactionReceipt get receipt by transaction hash @@ -271,7 +211,7 @@ func (b *BackendImpl) GetTransactionReceipt(ctx context.Context, hash common.Has // parse tx logs from events msgIndex := int(res.MsgIndex) - logs, _ := utils.TxLogsFromEvents(blockRes.TxsResults[res.TxIndex].Events, msgIndex) + logs, _ := rpcutils.TxLogsFromEvents(blockRes.TxsResults[res.TxIndex].Events, msgIndex) if res.EthTxIndex == -1 { // Fallback to find tx index by iterating all valid eth transactions @@ -299,7 +239,7 @@ func (b *BackendImpl) GetTransactionReceipt(ctx context.Context, hash common.Has // They are stored in the chain database. "transactionHash": hash, "contractAddress": nil, - "gasUsed": hexutil.Uint64(txData.GetGas()), + "gasUsed": hexutil.Uint64(res.GasUsed), // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. @@ -314,7 +254,7 @@ func (b *BackendImpl) GetTransactionReceipt(ctx context.Context, hash common.Has } if logs == nil { - receipt["logs"] = [][]*ethtypes.Log{} + receipt["logs"] = []*ethtypes.Log{} } // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation @@ -332,6 +272,263 @@ func (b *BackendImpl) GetTransactionReceipt(ctx context.Context, hash common.Has return receipt, nil } +func (b *BackendImpl) RPCTxFeeCap() float64 { + return b.cfg.RPCTxFeeCap +} + +func (b *BackendImpl) UnprotectedAllowed() bool { + if b.cfg.AppCfg == nil { + return false + } + return b.cfg.AppCfg.JSONRPC.AllowUnprotectedTxs +} + +func (b *BackendImpl) PendingTransactions() ([]*sdktypes.Tx, error) { + client, ok := b.clientCtx.Client.(rpcclient.MempoolClient) + if !ok { + return nil, errors.New("failed to assert MempoolClient") + } + + res, err := client.UnconfirmedTxs(b.ctx, nil) + if err != nil { + return nil, err + } + + result := make([]*sdktypes.Tx, 0, res.Count) + for _, txBz := range res.Txs { + tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) + if err != nil { + return nil, err + } + result = append(result, &tx) + } + + return result, nil +} + +func (b *BackendImpl) GetResendArgs(args rpctypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (rpctypes.TransactionArgs, error) { + chainID, err := types.ParseChainID(b.clientCtx.ChainID) + if err != nil { + return rpctypes.TransactionArgs{}, err + } + + cfg := b.ChainConfig() + if cfg == nil { + header, err := b.CurrentHeader() + if err != nil { + return rpctypes.TransactionArgs{}, err + } + cfg = evmtypes.DefaultChainConfig().EthereumConfig(header.Number.Int64(), chainID) + } + + // use the latest signer for the new tx + signer := ethtypes.LatestSigner(cfg) + + matchTx := args.ToTransaction() + + // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. + price := matchTx.GasPrice() + if gasPrice != nil { + price = gasPrice.ToInt() + } + gas := matchTx.Gas() + if gasLimit != nil { + gas = uint64(*gasLimit) + } + if err := rpctypes.CheckTxFee(price, gas, b.RPCTxFeeCap()); err != nil { + return rpctypes.TransactionArgs{}, err + } + + pending, err := b.PendingTransactions() + if err != nil { + return rpctypes.TransactionArgs{}, err + } + + for _, tx := range pending { + wantSigHash := signer.Hash(matchTx) + + // TODO, wantSigHash? + msg, err := evmtypes.UnwrapEthereumMsg(tx, wantSigHash) + if err != nil { + // not ethereum tx + continue + } + + pendingTx := msg.AsTransaction() + pFrom, err := ethtypes.Sender(signer, pendingTx) + if err != nil { + continue + } + + if pFrom == *args.From && signer.Hash(pendingTx) == wantSigHash { + // Match. Re-sign and send the transaction. + if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 { + args.GasPrice = gasPrice + } + if gasLimit != nil && *gasLimit != 0 { + args.Gas = gasLimit + } + + return args, nil + } + } + + return rpctypes.TransactionArgs{}, fmt.Errorf("transaction %s not found", matchTx.Hash().String()) +} + +// Sign signs the provided data using the private key of address via Geth's signature standard. +func (b *BackendImpl) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { + from := sdktypes.AccAddress(address.Bytes()) + + _, err := b.clientCtx.Keyring.KeyByAddress(from) + if err != nil { + return nil, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error()) + } + + // Sign the requested hash with the wallet + signature, _, err := b.clientCtx.Keyring.SignByAddress(from, data, signing.SignMode_SIGN_MODE_DIRECT) + if err != nil { + return nil, err + } + + signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper + return signature, nil +} + +// GetSender extracts the sender address from the signature values using the latest signer for the given chainID. +func (b *BackendImpl) GetSender(msg *evmtypes.MsgEthereumTx, chainID *big.Int) (from common.Address, err error) { + if msg.From != "" { + return common.HexToAddress(msg.From), nil + } + + tx := msg.AsTransaction() + // retrieve sender info from aspect if tx is not signed + if utils.IsCustomizedVerification(tx) { + bn, err := b.BlockNumber() + if err != nil { + return common.Address{}, err + } + ctx := rpctypes.ContextWithHeight(int64(bn)) + + res, err := b.queryClient.GetSender(ctx, msg) + if err != nil { + return common.Address{}, err + } + + from = common.HexToAddress(res.Sender) + } else { + signer := ethtypes.LatestSignerForChainID(chainID) + from, err = signer.Sender(tx) + if err != nil { + return common.Address{}, err + } + } + + msg.From = from.Hex() + return from, nil +} + +func (b *BackendImpl) getTransaction(_ context.Context, txHash common.Hash) (*evmtypes.MsgEthereumTx, *rpctypes.RPCTransaction, error) { + res, err := b.GetTxByEthHash(txHash) + hexTx := txHash.Hex() + + if err != nil { + b.logger.Debug("GetTxByEthHash failed, try to getTransactionByHashPending", "error", err) + return b.getTransactionByHashPending(txHash) + } + + block, err := b.CosmosBlockByNumber(rpc.BlockNumber(res.Height)) + if err != nil { + return nil, nil, err + } + + tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) + if err != nil { + return nil, nil, err + } + + // the `res.MsgIndex` is inferred from tx index, should be within the bound. + msg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + if !ok { + return nil, nil, errors.New("invalid ethereum tx") + } + msg.From = res.Sender + + blockRes, err := b.CosmosBlockResultByNumber(&block.Block.Height) + if err != nil { + b.logger.Debug("block result not found", "height", block.Block.Height, "error", err.Error()) + return nil, nil, nil + } + + if res.EthTxIndex == -1 { + // Fallback to find tx index by iterating all valid eth transactions + msgs := b.EthMsgsFromCosmosBlock(block, blockRes) + for i := range msgs { + if msgs[i].Hash == hexTx { + res.EthTxIndex = int32(i) + break + } + } + } + // if we still unable to find the eth tx index, return error, shouldn't happen. + if res.EthTxIndex == -1 { + return msg, nil, errors.New("can't find index of ethereum tx") + } + + baseFee, err := b.BaseFee(blockRes) + if err != nil { + // handle the error for pruned node. + b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", blockRes.Height, "error", err) + } + + cfg, err := b.chainConfig() + if err != nil { + return msg, nil, err + } + + return msg, rpctypes.NewTransactionFromMsg( + msg, + common.BytesToHash(block.BlockID.Hash.Bytes()), + uint64(res.Height), + uint64(res.EthTxIndex), + baseFee, + cfg, + ), nil +} + +func (b *BackendImpl) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return b.scope.Track(b.newTxsFeed.Subscribe(ch)) +} + +func (b *BackendImpl) version() (string, error) { + cfg, err := b.chainConfig() + if err != nil { + return "", err + } + + if cfg.ChainID == nil { + b.logger.Error("eth.rpc.rpctypes.Version", "ChainID is nil") + return "", errors.New("chain id is not valid") + } + return cfg.ChainID.String(), nil +} + +func (b *BackendImpl) GetTxByEthHash(hash common.Hash) (*types.TxResult, error) { + // if b.indexer != nil { + // return b.indexer.GetByTxHash(hash) + // } + + // fallback to tendermint tx indexer + query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, hash.Hex()) + txResult, err := b.queryCosmosTxIndexer(query, func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx { + return txs.GetTxByHash(hash) + }) + if err != nil { + return nil, fmt.Errorf("GetTxByEthHash %s, %w", hash.Hex(), err) + } + return txResult, nil +} + func (b *BackendImpl) queryCosmosTxIndexer(query string, txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx) (*types.TxResult, error) { resTxs, err := b.clientCtx.Client.TxSearch(b.ctx, query, false, nil, nil, "") if err != nil { @@ -358,13 +555,13 @@ func (b *BackendImpl) queryCosmosTxIndexer(query string, txGetter func(*rpctypes } // getTransactionByHashPending find pending tx from mempool -func (b *BackendImpl) getTransactionByHashPending(txHash common.Hash) (*ethapi.RPCTransaction, error) { +func (b *BackendImpl) getTransactionByHashPending(txHash common.Hash) (*evmtypes.MsgEthereumTx, *rpctypes.RPCTransaction, error) { hexTx := txHash.Hex() // try to find tx in mempool ptxs, err := b.PendingTransactions() if err != nil { - b.logger.Debug("tx not found", "hash", hexTx, "error", err.Error()) - return nil, nil + b.logger.Debug("pending tx not found", "hash", hexTx, "error", err.Error()) + return nil, nil, nil } for _, tx := range ptxs { @@ -376,11 +573,11 @@ func (b *BackendImpl) getTransactionByHashPending(txHash common.Hash) (*ethapi.R cfg, err := b.chainConfig() if err != nil { - return nil, err + return msg, nil, err } if msg.Hash == hexTx { // use zero block values since it's not included in a block yet - rpctx := ethapi.NewTransactionFromMsg( + rpctx := rpctypes.NewTransactionFromMsg( msg, common.Hash{}, uint64(0), @@ -388,44 +585,65 @@ func (b *BackendImpl) getTransactionByHashPending(txHash common.Hash) (*ethapi.R nil, cfg, ) - return rpctx, nil + return msg, rpctx, nil } } b.logger.Debug("tx not found", "hash", hexTx) - return nil, nil + return nil, nil, nil } -func (b *BackendImpl) EstimateGas(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { - blockNum := rpc.LatestBlockNumber - if blockNrOrHash != nil { - blockNum, _ = b.blockNumberFromCosmos(*blockNrOrHash) - } - - bz, err := json.Marshal(&args) +func (b *BackendImpl) getAccountNonce(accAddr common.Address, pending bool, height int64) (uint64, error) { + queryClient := authtypes.NewQueryClient(b.clientCtx) + adr := sdktypes.AccAddress(accAddr.Bytes()).String() + ctx := rpctypes.ContextWithHeight(height) + res, err := queryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: adr}) if err != nil { + st, ok := status.FromError(err) + // treat as account doesn't exist yet + if ok && st.Code() == codes.NotFound { + b.logger.Info("getAccountNonce faild, account not found", "error", err) + return 0, nil + } return 0, err } - - header, err := b.CosmosBlockByNumber(blockNum) - if err != nil { - // the error message imitates geth behavior - return 0, errors.New("header not found") + var acc authtypes.AccountI + if err := b.clientCtx.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { + return 0, err } - req := evmtypes.EthCallRequest{ - Args: bz, - GasCap: b.RPCGasCap(), - ProposerAddress: sdktypes.ConsAddress(header.Block.ProposerAddress), - ChainId: b.chainID.Int64(), + nonce := acc.GetSequence() + + if !pending { + return nonce, nil } - // From ContextWithHeight: if the provided height is 0, - // it will return an empty context and the gRPC query will use - // the latest block height for querying. - res, err := b.queryClient.EstimateGas(rpctypes.ContextWithHeight(blockNum.Int64()), &req) + // the account retriever doesn't include the uncommitted transactions on the nonce so we need to + // to manually add them. + pendingTxs, err := b.PendingTransactions() if err != nil { - return 0, err + return nonce, nil } - return hexutil.Uint64(res.Gas), nil + + // add the uncommitted txs to the nonce counter + // only supports `MsgEthereumTx` style tx + for _, tx := range pendingTxs { + for _, msg := range (*tx).GetMsgs() { + ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) + if !ok { + // not ethereum tx + break + } + + sender, err := b.GetSender(ethMsg, b.chainID) + if err != nil { + continue + } + if sender == accAddr { + nonce++ + } + } + } + + return nonce, nil } diff --git a/ethereum/rpc/tx_pool.go b/ethereum/rpc/tx_pool.go new file mode 100644 index 0000000..a1a5bba --- /dev/null +++ b/ethereum/rpc/tx_pool.go @@ -0,0 +1,20 @@ +package rpc + +import ( + "errors" + + rpcclient "github.com/cometbft/cometbft/rpc/client" +) + +func (b *BackendImpl) PendingTransactionsCount() (int, error) { + client, ok := b.clientCtx.Client.(rpcclient.MempoolClient) + if !ok { + return 0, errors.New("failed to assert MempoolClient") + } + + res, err := client.UnconfirmedTxs(b.ctx, nil) + if err != nil { + return 0, err + } + return res.Count, nil +} diff --git a/ethereum/rpc/types/backend.go b/ethereum/rpc/types/backend.go new file mode 100644 index 0000000..a107308 --- /dev/null +++ b/ethereum/rpc/types/backend.go @@ -0,0 +1,130 @@ +package types + +import ( + "context" + "math/big" + + tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/artela-network/artela-rollkit/x/evm/txs" + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" +) + +type ( + // Backend defines the common interfaces + Backend interface { + CurrentHeader() (*types.Header, error) + + Accounts() []common.Address + GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) + ArtBlockByNumber(ctx context.Context, number rpc.BlockNumber) (*Block, error) + BlockByHash(ctx context.Context, hash common.Hash) (*Block, error) + ChainConfig() *params.ChainConfig + } + + // EthereumBackend defines the chain related interfaces + EthereumBackend interface { + Backend + + SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) + GasPrice(ctx context.Context) (*hexutil.Big, error) + FeeHistory(blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*FeeHistoryResult, error) + + Engine() consensus.Engine + Syncing() (interface{}, error) + } + + // BlockChainBackend defines the block chain interfaces + BlockChainBackend interface { + Backend + + GetProof(address common.Address, storageKeys []string, blockNrOrHash BlockNumberOrHash) (*AccountResult, error) + DoCall(args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash) (*evmtypes.MsgEthereumTxResponse, error) + EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) + + BlockNumber() (hexutil.Uint64, error) + BlockTimeByNumber(blockNum int64) (uint64, error) + HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) + HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) + HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) + CurrentBlock() *Block + ArtBlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*Block, error) + CosmosBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) + CosmosBlockByNumber(blockNum rpc.BlockNumber) (*tmrpctypes.ResultBlock, error) + GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) + GetStorageAt(address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) + GetCoinbase() (sdk.AccAddress, error) + + GetDenomByAddress(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (string, error) + GetAddressByDenom(ctx context.Context, denom string, blockNrOrHash rpc.BlockNumberOrHash) ([]string, error) + } + + // TrancsactionBackend defines the block chain interfaces + TrancsactionBackend interface { + BlockChainBackend + EthereumBackend + + SendTx(ctx context.Context, signedTx *types.Transaction) error + GetTransaction(ctx context.Context, txHash common.Hash) (*RPCTransaction, error) + GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) + GetTxMsg(ctx context.Context, txHash common.Hash) (*evmtypes.MsgEthereumTx, error) + SignTransaction(args *TransactionArgs) (*types.Transaction, error) + GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) + RPCTxFeeCap() float64 + UnprotectedAllowed() bool + + PendingTransactions() ([]*sdk.Tx, error) + GetResendArgs(args TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (TransactionArgs, error) + Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) + GetSender(msg *evmtypes.MsgEthereumTx, chainID *big.Int) (from common.Address, err error) + } + + DebugBackend interface { + BlockChainBackend + TrancsactionBackend + + TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error) + TraceBlock(height rpc.BlockNumber, + config *evmtypes.TraceConfig, + block *tmrpctypes.ResultBlock, + ) ([]*txs.TxTraceResult, error) + GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) + + DBProperty(property string) (string, error) + DBCompact(start []byte, limit []byte) error + } + + PersonalBackend interface { + TrancsactionBackend + + NewAccount(password string) (common.AddressEIP55, error) + ImportRawKey(privkey, password string) (common.Address, error) + } + + TxPoolBackend interface { + TrancsactionBackend + + PendingTransactionsCount() (int, error) + } + + // NetBackend is the collection of methods required to satisfy the net + // RPC DebugAPI. + NetBackend interface { + PeerCount() hexutil.Uint + Listening() bool + Version() string + } + + // Web3Backend is the collection of methods required to satisfy the net + // RPC DebugAPI. + Web3Backend interface { + ClientVersion() string + } +) diff --git a/ethereum/rpc/types/block.go b/ethereum/rpc/types/block.go index 0c08141..737058f 100644 --- a/ethereum/rpc/types/block.go +++ b/ethereum/rpc/types/block.go @@ -77,8 +77,11 @@ func EthBlockToBlock(block *ethtypes.Block) *Block { type BlockNumber int64 const ( - EthPendingBlockNumber = BlockNumber(-2) - EthLatestBlockNumber = BlockNumber(-1) + // adjust the order to match ethereum + // the order was changed in ethereum at: + // https://github.com/ethereum/go-ethereum/pull/27219/files#diff-064c12cf00b0f549b40fa9dff4231b1d1d3c143a2e47cd051a87f5b04d429949R68 + EthLatestBlockNumber = BlockNumber(-2) + EthPendingBlockNumber = BlockNumber(-1) EthEarliestBlockNumber = BlockNumber(0) ) diff --git a/ethereum/rpc/types/rpc_transacction.go b/ethereum/rpc/types/rpc_transacction.go new file mode 100644 index 0000000..ea09b30 --- /dev/null +++ b/ethereum/rpc/types/rpc_transacction.go @@ -0,0 +1,146 @@ +package types + +import ( + "math/big" + "time" + + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` +} + +// newRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { + signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) + from, _ := types.Sender(signer, tx) + + return newRPCTransactionWithFrom(tx, blockHash, blockNumber, index, baseFee, from) +} + +func newRPCTransactionWithFrom(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, from common.Address) *RPCTransaction { + v, r, s := tx.RawSignatureValues() + result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + switch tx.Type() { + case types.LegacyTxType: + // if a legacy transaction has an EIP-155 chain id, include it explicitly + if id := tx.ChainId(); id.Sign() != 0 { + result.ChainID = (*hexutil.Big)(id) + } + case types.AccessListTxType: + al := tx.AccessList() + result.Accesses = &al + result.ChainID = (*hexutil.Big)(tx.ChainId()) + case types.DynamicFeeTxType: + al := tx.AccessList() + result.Accesses = &al + result.ChainID = (*hexutil.Big)(tx.ChainId()) + result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) + result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) + // if the transaction has been mined, compute the effective gas price + if baseFee != nil && blockHash != (common.Hash{}) { + // price = min(tip, gasFeeCap - baseFee) + baseFee + price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) + result.GasPrice = (*hexutil.Big)(price) + } else { + result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) + } + } + return result +} + +// NewTransactionFromMsg returns a txs that will serialize to the RPC +// representation, with the given location metadata set (if available). +func NewTransactionFromMsg( + msg *evmtypes.MsgEthereumTx, + blockHash common.Hash, + blockNumber, index uint64, + baseFee *big.Int, + cfg *params.ChainConfig, +) *RPCTransaction { + tx := msg.AsTransaction() + // use latest singer, so use time.now as block time. + if msg.From != "" { + return newRPCTransactionWithFrom(tx, blockHash, blockNumber, index, baseFee, common.HexToAddress(msg.From)) + } + return newRPCTransaction(tx, blockHash, blockNumber, uint64(time.Now().Unix()), index, baseFee, cfg) +} + +// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { + var ( + baseFee *big.Int + blockNumber = uint64(0) + blockTime = uint64(0) + ) + if current != nil { + baseFee = misc.CalcBaseFee(config, current) + blockNumber = current.Number.Uint64() + blockTime = current.Time + } + return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config) +} + +// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func NewRPCTransactionFromBlockIndex(b *types.Block, blockHash common.Hash, index uint64, config *params.ChainConfig) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return newRPCTransaction(txs[index], blockHash, b.NumberU64(), b.Time(), index, b.BaseFee(), config) +} + +// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. +func NewRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + blob, _ := txs[index].MarshalBinary() + return blob +} diff --git a/ethereum/rpc/ethapi/transaction_args.go b/ethereum/rpc/types/transaction_args.go similarity index 95% rename from ethereum/rpc/ethapi/transaction_args.go rename to ethereum/rpc/types/transaction_args.go index 610b6c3..68c128a 100644 --- a/ethereum/rpc/ethapi/transaction_args.go +++ b/ethereum/rpc/types/transaction_args.go @@ -1,4 +1,4 @@ -package ethapi +package types import ( "bytes" @@ -43,7 +43,7 @@ type TransactionArgs struct { } // from retrieves the transaction sender address. -func (args *TransactionArgs) from() common.Address { +func (args *TransactionArgs) FromAddr() common.Address { if args.From == nil { return common.Address{} } @@ -62,7 +62,7 @@ func (args *TransactionArgs) data() []byte { } // setDefaults fills in default values for unspecified tx fields. -func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { +func (args *TransactionArgs) SetDefaults(ctx context.Context, b TrancsactionBackend) error { if err := args.setFeeDefaults(ctx, b); err != nil { return err } @@ -70,7 +70,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { args.Value = new(hexutil.Big) } if args.Nonce == nil { - nonce, err := b.GetTransactionCount(args.from(), rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) + nonce, err := b.GetTransactionCount(args.FromAddr(), rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) if err != nil { return err } @@ -98,15 +98,15 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { Data: (*hexutil.Bytes)(&data), AccessList: args.AccessList, } - pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - // estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap()) - // if err != nil { - // return err - // } - // args.Gas = &estimated - // TODO set gas - _ = callArgs - _ = pendingBlockNr + + latestBlockNumber := rpc.LatestBlockNumber + estimated, err := b.EstimateGas(ctx, callArgs, &rpc.BlockNumberOrHash{ + BlockNumber: &latestBlockNumber, + }) + if err != nil { + return err + } + args.Gas = &estimated log.Trace("Estimate gas usage automatically", "gas", args.Gas) } @@ -124,7 +124,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { } // setFeeDefaults fills in default fee values for unspecified tx fields. -func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error { +func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b TrancsactionBackend) error { // If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error. if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -166,7 +166,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro } // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. -func (args *TransactionArgs) setLondonFeeDefaults(_ context.Context, head *types.Header, b Backend) error { +func (args *TransactionArgs) setLondonFeeDefaults(_ context.Context, head *types.Header, b TrancsactionBackend) error { // Set maxPriorityFeePerGas if it is missing. if args.MaxPriorityFeePerGas == nil { tip, err := b.SuggestGasTipCap(head.BaseFee) @@ -202,7 +202,7 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (* return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } // Set sender address or use zero address if none specified. - addr := args.from() + addr := args.FromAddr() // Set default gas & gas price if none were set gas := globalGasCap diff --git a/ethereum/rpc/types/types.go b/ethereum/rpc/types/types.go index 9df3626..ccb093a 100644 --- a/ethereum/rpc/types/types.go +++ b/ethereum/rpc/types/types.go @@ -29,29 +29,6 @@ type StorageResult struct { Proof []string `json:"proof"` } -// RPCTransaction represents a txs that will serialize to the RPC representation of a txs -type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *ethtypes.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` -} - // StateOverride is the collection of overridden accounts. type StateOverride map[common.Address]OverrideAccount diff --git a/ethereum/rpc/types/utils.go b/ethereum/rpc/types/utils.go index ab295ef..a3014f2 100644 --- a/ethereum/rpc/types/utils.go +++ b/ethereum/rpc/types/utils.go @@ -14,7 +14,6 @@ import ( errortypes "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -139,80 +138,6 @@ func FormatBlock( return result } -// NewTransactionFromMsg returns a txs that will serialize to the RPC -// representation, with the given location metadata set (if available). -func NewTransactionFromMsg( - msg *evmtypes.MsgEthereumTx, - blockHash common.Hash, - blockNumber, index uint64, - baseFee *big.Int, - chainID *big.Int, -) (*RPCTransaction, error) { - tx := msg.AsTransaction() - return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee, chainID) -} - -// NewTransactionFromData returns a txs that will serialize to the RPC -// representation, with the given location metadata set (if available). -func NewRPCTransaction( - tx *ethtypes.Transaction, blockHash common.Hash, blockNumber, index uint64, baseFee *big.Int, - chainID *big.Int, -) (*RPCTransaction, error) { - // Determine the signer. For replay-protected transactions, use the most permissive - // signer, because we assume that signers are backwards-compatible with old - // transactions. For non-protected transactions, the homestead signer signer is used - // because the return value of ChainId is zero for those transactions. - var signer ethtypes.Signer - if tx.Protected() { - signer = ethtypes.LatestSignerForChainID(tx.ChainId()) - } else { - signer = ethtypes.HomesteadSigner{} - } - from, _ := ethtypes.Sender(signer, tx) // #nosec G703 - v, r, s := tx.RawSignatureValues() - result := &RPCTransaction{ - Type: hexutil.Uint64(tx.Type()), - From: from, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - Hash: tx.Hash(), - Input: hexutil.Bytes(tx.Data()), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - V: (*hexutil.Big)(v), - R: (*hexutil.Big)(r), - S: (*hexutil.Big)(s), - ChainID: (*hexutil.Big)(chainID), - } - if blockHash != (common.Hash{}) { - result.BlockHash = &blockHash - result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) - result.TransactionIndex = (*hexutil.Uint64)(&index) - } - switch tx.Type() { - case ethtypes.AccessListTxType: - al := tx.AccessList() - result.Accesses = &al - result.ChainID = (*hexutil.Big)(tx.ChainId()) - case ethtypes.DynamicFeeTxType: - al := tx.AccessList() - result.Accesses = &al - result.ChainID = (*hexutil.Big)(tx.ChainId()) - result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) - result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) - // if the txs has been mined, compute the effective gas price - if baseFee != nil && blockHash != (common.Hash{}) { - // price = min(tip, gasFeeCap - baseFee) + baseFee - price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) - result.GasPrice = (*hexutil.Big)(price) - } else { - result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) - } - } - return result, nil -} - // BaseFeeFromEvents parses the fee basefee from cosmos events func BaseFeeFromEvents(events []abci.Event) *big.Int { for _, event := range events { diff --git a/ethereum/rpc/web3.go b/ethereum/rpc/web3.go new file mode 100644 index 0000000..ec89f3a --- /dev/null +++ b/ethereum/rpc/web3.go @@ -0,0 +1,19 @@ +package rpc + +import ( + "fmt" + "runtime" + + "github.com/cosmos/cosmos-sdk/version" +) + +// ClientVersion returns the current client version. +func (b *BackendImpl) ClientVersion() string { + return fmt.Sprintf( + "%s/%s/%s/%s", + version.Name, + version.Version, + runtime.GOOS+"-"+runtime.GOARCH, + runtime.Version(), + ) +} diff --git a/ethereum/rpc/websockets.go b/ethereum/rpc/websockets.go index 2289542..f1ae67f 100644 --- a/ethereum/rpc/websockets.go +++ b/ethereum/rpc/websockets.go @@ -443,7 +443,6 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn, subID rpc.ID) (pubsub.Un } } - // TODO: Eth TransactionsRoot unable to obtain ,now remove transactionsRoot, result := map[string]interface{}{ "parentHash": header.ParentHash, "sha3Uncles": header.UncleHash, @@ -453,8 +452,8 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn, subID rpc.ID) (pubsub.Un "logsBloom": bloom, "difficulty": header.Difficulty, "number": header.Number, - "gasLimit": header.GasLimit, - "gasUsed": header.GasUsed, + "gasLimit": data.ResultFinalizeBlock.ConsensusParamUpdates.Block.MaxGas, + "gasUsed": header.GasUsed, // TODO emit the txs and calculte it. "timestamp": header.Time, "extraData": header.Extra, "mixHash": header.MixDigest, @@ -463,7 +462,8 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn, subID rpc.ID) (pubsub.Un "withdrawalsRoot": header.WithdrawalsHash, "excessDataGas": header.ExcessDataGas, "hash": hexutil.Encode(cosmosHash.Bytes()), - "size": 0, + "size": 0, // TODO calculted with total block, emit the txs and calculte it. + // "transactionRoot" // TODO emit the txs and calculte it. } // write to ws conn diff --git a/ethereum/server/start.go b/ethereum/server/start.go index 19e4623..5e2ac46 100644 --- a/ethereum/server/start.go +++ b/ethereum/server/start.go @@ -12,6 +12,7 @@ import ( pvm "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/proxy" cmttypes "github.com/cometbft/cometbft/types" + dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" @@ -54,7 +55,13 @@ func StartHandler[T sdktypes.Application](svrCtx *server.Context, clientCtx clie return err } - app, appCleanupFn, err := startApp[T](svrCtx, appCreator, opts) + home := svrCtx.Config.RootDir + db, err := opts.DBOpener(home, server.GetAppDBBackend(svrCtx.Viper)) + if err != nil { + return err + } + + app, appCleanupFn, err := startApp[T](svrCtx, db, appCreator, opts) if err != nil { return err } @@ -67,21 +74,15 @@ func StartHandler[T sdktypes.Application](svrCtx *server.Context, clientCtx clie emitServerInfoMetrics() - return startInProcess[T](svrCtx, svrCfg, clientCtx, app, metrics, opts) + return startInProcess[T](svrCtx, db, svrCfg, clientCtx, app, metrics, opts) } -func startApp[T sdktypes.Application](svrCtx *server.Context, appCreator sdktypes.AppCreator, opts server.StartCmdOptions) (app sdktypes.Application, cleanupFn func(), err error) { +func startApp[T sdktypes.Application](svrCtx *server.Context, db dbm.DB, appCreator sdktypes.AppCreator, opts server.StartCmdOptions) (app sdktypes.Application, cleanupFn func(), err error) { traceWriter, traceCleanupFn, err := setupTraceWriter(svrCtx) if err != nil { return app, traceCleanupFn, err } - home := svrCtx.Config.RootDir - db, err := opts.DBOpener(home, server.GetAppDBBackend(svrCtx.Viper)) - if err != nil { - return app, traceCleanupFn, err - } - app = appCreator(svrCtx.Logger, db, traceWriter, svrCtx.Viper) cleanupFn = func() { @@ -93,7 +94,7 @@ func startApp[T sdktypes.Application](svrCtx *server.Context, appCreator sdktype return app, cleanupFn, nil } -func startInProcess[T sdktypes.Application](svrCtx *server.Context, svrCfg serverconfig.Config, clientCtx client.Context, app sdktypes.Application, +func startInProcess[T sdktypes.Application](svrCtx *server.Context, db dbm.DB, svrCfg serverconfig.Config, clientCtx client.Context, app sdktypes.Application, metrics *telemetry.Metrics, opts server.StartCmdOptions, ) error { cmtCfg := svrCtx.Config @@ -152,7 +153,7 @@ func startInProcess[T sdktypes.Application](svrCtx *server.Context, svrCfg serve if appcfg.JSONRPC.Enable { tmEndpoint := "/websocket" tmRPCAddr := cmtCfg.RPC.ListenAddress - jsonrpcSrv, err = CreateJSONRPC(svrCtx, clientCtx, tmRPCAddr, tmEndpoint, &appcfg) + jsonrpcSrv, err = CreateJSONRPC(svrCtx, clientCtx, tmRPCAddr, tmEndpoint, &appcfg, db) if err != nil { return err } diff --git a/ethereum/server/util.go b/ethereum/server/util.go index 0779090..e48c177 100644 --- a/ethereum/server/util.go +++ b/ethereum/server/util.go @@ -15,6 +15,7 @@ import ( ethrpc "github.com/artela-network/artela-rollkit/ethereum/rpc" "github.com/artela-network/artela-rollkit/ethereum/server/config" + ethNode "github.com/ethereum/go-ethereum/node" ) // CreateJSONRPC starts the JSON-RPC server @@ -23,14 +24,38 @@ func CreateJSONRPC(ctx *sdkserver.Context, tmRPCAddr, tmEndpoint string, config *config.Config, + db dbm.DB, ) (*ethrpc.ArtelaService, error) { - cfg := ethrpc.DefaultConfig() - cfg.RPCGasCap = config.JSONRPC.GasCap - cfg.RPCEVMTimeout = config.JSONRPC.EVMTimeout - cfg.RPCTxFeeCap = config.JSONRPC.TxFeeCap - cfg.AppCfg = config + cfg := getRpcConfig(config) + + nodeCfg, err := getNodeConfig(ctx, config) + if err != nil { + return nil, err + } + stack, err := ethrpc.NewNode(nodeCfg) + if err != nil { + return nil, err + } + + wsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, nodeCfg.Logger) + + serv := ethrpc.NewArtelaService(ctx, clientCtx, wsClient, cfg, stack, nodeCfg.Logger, db) + + // allocate separate WS connection to Tendermint + tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, nodeCfg.Logger) + wsSrv := ethrpc.NewWebsocketsServer(clientCtx, tmWsClient, config, nodeCfg.Logger) + wsSrv.Start() + + return serv, nil +} + +func getNodeConfig(ctx *sdkserver.Context, config *config.Config) (*ethNode.Config, error) { nodeCfg := ethrpc.DefaultGethNodeConfig() + // if not define, use default value + if len(config.JSONRPC.API) > 0 { + nodeCfg.HTTPModules = config.JSONRPC.API + } address := strings.Split(config.JSONRPC.Address, ":") if len(address) > 0 { nodeCfg.HTTPHost = address[0] @@ -58,21 +83,16 @@ func CreateJSONRPC(ctx *sdkserver.Context, })) // do not start websocket nodeCfg.WSHost = "" - stack, err := ethrpc.NewNode(nodeCfg) - if err != nil { - return nil, err - } - - wsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, nodeCfg.Logger) - - serv := ethrpc.NewArtelaService(ctx, clientCtx, wsClient, cfg, stack, nodeCfg.Logger) - - // allocate separate WS connection to Tendermint - tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, nodeCfg.Logger) - wsSrv := ethrpc.NewWebsocketsServer(clientCtx, tmWsClient, config, nodeCfg.Logger) - wsSrv.Start() + return nodeCfg, nil +} - return serv, nil +func getRpcConfig(config *config.Config) *ethrpc.Config { + cfg := ethrpc.DefaultConfig() + cfg.RPCGasCap = config.JSONRPC.GasCap + cfg.RPCEVMTimeout = config.JSONRPC.EVMTimeout + cfg.RPCTxFeeCap = config.JSONRPC.TxFeeCap + cfg.AppCfg = config + return cfg } func openDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) { diff --git a/ethereum/types/protocol.go b/ethereum/types/protocol.go index 580c344..e43107a 100644 --- a/ethereum/types/protocol.go +++ b/ethereum/types/protocol.go @@ -2,8 +2,9 @@ package types // Constants to match up protocol versions and messages const ( - eth65 = 65 + eth68 = 68 // ProtocolVersion is the latest supported version of the eth protocol. - ProtocolVersion = eth65 + // ethereum 1.12 match to 68 + ProtocolVersion = eth68 ) diff --git a/go.mod b/go.mod index 1c447a2..5575ec7 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/BurntSushi/toml v1.4.0 github.com/andybalholm/brotli v1.1.0 github.com/artela-network/artela-evm v0.4.8-rc8 - github.com/artela-network/aspect-core v0.4.8-rc8 + github.com/artela-network/aspect-core v0.4.9-rc9 github.com/artela-network/aspect-runtime v0.4.8-rc8 github.com/btcsuite/btcd v0.23.0 github.com/btcsuite/btcd/btcutil v1.1.3 @@ -47,6 +47,7 @@ require ( github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ibc-go/v8 v8.2.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 github.com/dvsekhvalnov/jose2go v1.6.0 github.com/emirpasic/gods v1.18.1 github.com/ethereum/go-ethereum v1.12.0 @@ -69,7 +70,6 @@ require ( github.com/tidwall/gjson v1.14.2 github.com/tidwall/sjson v1.2.5 github.com/tyler-smith/go-bip39 v1.1.0 - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 golang.org/x/sync v0.7.0 golang.org/x/text v0.16.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d @@ -145,12 +145,14 @@ require ( github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/distribution/reference v0.5.0 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect github.com/docker/cli v25.0.4+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v25.0.4+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/emicklei/dot v1.6.1 // indirect @@ -172,6 +174,7 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect @@ -376,6 +379,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect diff --git a/go.sum b/go.sum index 5e34d2e..4ae426c 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/artela-network/artela-evm v0.4.8-rc8 h1:4saDqBKnVmaEvSBEveVwRi/vnXVERz5YvRXr3gAzB3E= github.com/artela-network/artela-evm v0.4.8-rc8/go.mod h1:eYeoqd8pOAX/HcKVKnqxqwJki0qyIoQwSGgYTyFZQ/M= -github.com/artela-network/aspect-core v0.4.8-rc8 h1:7KSb/NcD3HhOTirVg7mVPmknxSO1xQooNjPHe4bryZc= -github.com/artela-network/aspect-core v0.4.8-rc8/go.mod h1:hve/4ibuIgt0HaAQrBYez1O8BQGceK8O8rGeyHoMAwg= +github.com/artela-network/aspect-core v0.4.9-rc9 h1:TC27Al1l/e0yjPTZ2F1b9VhoGw/8cCD9uxCimRBHq4k= +github.com/artela-network/aspect-core v0.4.9-rc9/go.mod h1:hve/4ibuIgt0HaAQrBYez1O8BQGceK8O8rGeyHoMAwg= github.com/artela-network/aspect-runtime v0.4.8-rc8 h1:48dbWs+4wUAL52U6JUN+hPQ7u7lDTkajoI0EcZYtwL4= github.com/artela-network/aspect-runtime v0.4.8-rc8/go.mod h1:GiDB2+LUbl2b2Z8+v/83LFbUKs5DqQ3ACxLUWY8zMdU= github.com/artela-network/wasmtime-go/v20 v20.0.3 h1:A4/KrrCQiXhDibc3bUlvD7vzohV4saWiAA3MIFz11Yo= @@ -588,8 +588,13 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= +github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -609,6 +614,11 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -746,6 +756,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= diff --git a/proto/artela/aspect/genesis.proto b/proto/artela/aspect/genesis.proto new file mode 100644 index 0000000..2727a4b --- /dev/null +++ b/proto/artela/aspect/genesis.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package artela.aspect; + +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; +import "artela/aspect/params.proto"; + +option go_package = "github.com/artela-network/artela-rollkit/x/aspect/types"; + +// GenesisState defines the aspect module's genesis state. +message GenesisState { + // params defines all the parameters of the module. + Params params = 1 [ + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; +} diff --git a/proto/artela/aspect/module/module.proto b/proto/artela/aspect/module/module.proto new file mode 100644 index 0000000..bc57235 --- /dev/null +++ b/proto/artela/aspect/module/module.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package artela.aspect.module; + +import "cosmos/app/v1alpha1/module.proto"; + +// Module is the config object for the module. +message Module { + option (cosmos.app.v1alpha1.module) = { + go_import: "github.com/artela-network/artela-rollkit/x/aspect" + }; + + // authority defines the custom module authority. If not set, defaults to the governance module. + string authority = 1; +} \ No newline at end of file diff --git a/proto/artela/aspect/params.proto b/proto/artela/aspect/params.proto new file mode 100644 index 0000000..a3498a8 --- /dev/null +++ b/proto/artela/aspect/params.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package artela.aspect; + +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/artela-network/artela-rollkit/x/aspect/types"; + +// Params defines the parameters for the module. +message Params { + option (amino.name) = "artela/x/aspect/Params"; + option (gogoproto.equal) = true; + + +} \ No newline at end of file diff --git a/proto/artela/aspect/query.proto b/proto/artela/aspect/query.proto new file mode 100644 index 0000000..1bcb36a --- /dev/null +++ b/proto/artela/aspect/query.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; +package artela.aspect; + +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "artela/aspect/params.proto"; + +option go_package = "github.com/artela-network/artela-rollkit/x/aspect/types"; + +// Query defines the gRPC querier service. +service Query { + // Parameters queries the parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/artela-network/artela/aspect/params"; + } +} + +// QueryParamsRequest is request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is response type for the Query/Params RPC method. +message QueryParamsResponse { + // params holds all the parameters of this module. + Params params = 1 [ + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; +} \ No newline at end of file diff --git a/proto/artela/aspect/tx.proto b/proto/artela/aspect/tx.proto new file mode 100644 index 0000000..5338a56 --- /dev/null +++ b/proto/artela/aspect/tx.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; +package artela.aspect; + +import "amino/amino.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "artela/aspect/params.proto"; + +option go_package = "github.com/artela-network/artela-rollkit/x/aspect/types"; + +// Msg defines the Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // UpdateParams defines a (governance) operation for updating the module + // parameters. The authority defaults to the x/gov module account. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgUpdateParams is the Msg/UpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "artela/x/aspect/MsgUpdateParams"; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // params defines the module parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [ + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/proto/artela/evm/erc20.proto b/proto/artela/evm/erc20.proto new file mode 100644 index 0000000..d3cef63 --- /dev/null +++ b/proto/artela/evm/erc20.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package artela.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/artela-network/artela-rollkit/x/evm/types"; + +message TokenPair { + string address = 1; + string denom = 2; +} + +message TokenPairs { + repeated TokenPair token_pairs = 1; +} \ No newline at end of file diff --git a/proto/artela/evm/query.proto b/proto/artela/evm/query.proto index 28f530b..c99d6ca 100644 --- a/proto/artela/evm/query.proto +++ b/proto/artela/evm/query.proto @@ -81,6 +81,16 @@ service Query { rpc GetSender(MsgEthereumTx) returns (GetSenderResponse) { option (google.api.http).get = "/artela/evm/get_sender"; } + + // DenomByAddress returns the denom mapping to address + rpc DenomByAddress(DenomByAddressRequest) returns (DenomByAddressResponse) { + option (google.api.http).get = "/artela/evm/v1/denom_by_address/{address}"; + } + + // DenomByAddress returns the denom mapping to address + rpc AddressByDenom(AddressByDenomRequest) returns (AddressByDenomResponse) { + option (google.api.http).get = "/artela/evm/v1/address_by_denom/{denom}"; + } } // QueryAccountRequest is the request type for the Query/Account RPC method. @@ -309,4 +319,20 @@ message QueryBaseFeeResponse { message GetSenderResponse { // sender defines the from address of the tx. string sender = 1; +} + +message DenomByAddressRequest { + string address = 1; +} + +message DenomByAddressResponse { + string denom = 1; +} + +message AddressByDenomRequest { + string denom = 1; +} + +message AddressByDenomResponse { + repeated string address = 1; } \ No newline at end of file diff --git a/testutil/keeper/aspect.go b/testutil/keeper/aspect.go new file mode 100644 index 0000000..17e8379 --- /dev/null +++ b/testutil/keeper/aspect.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/store" + "cosmossdk.io/store/metrics" + storetypes "cosmossdk.io/store/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + + "github.com/artela-network/artela-rollkit/x/aspect/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func AspectKeeper(t testing.TB) (keeper.Keeper, sdk.Context) { + storeKey := storetypes.NewKVStoreKey(types.StoreKey) + + db := dbm.NewMemDB() + stateStore := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + + k := keeper.NewKeeper( + cdc, + runtime.NewKVStoreService(storeKey), + log.NewNopLogger(), + authority.String(), + ) + + ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) + + // Initialize params + if err := k.SetParams(ctx, types.DefaultParams()); err != nil { + panic(err) + } + + return k, ctx +} diff --git a/testutil/keeper/evm.go b/testutil/keeper/evm.go index 3772742..d176f38 100644 --- a/testutil/keeper/evm.go +++ b/testutil/keeper/evm.go @@ -23,6 +23,7 @@ import ( func EvmKeeper(t testing.TB) (keeper.Keeper, sdk.Context) { storeKey := storetypes.NewKVStoreKey(types.StoreKey) + transientStoreKey := storetypes.NewTransientStoreKey(types.StoreKey) db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) @@ -33,9 +34,21 @@ func EvmKeeper(t testing.TB) (keeper.Keeper, sdk.Context) { cdc := codec.NewProtoCodec(registry) authority := authtypes.NewModuleAddress(govtypes.ModuleName) + var mockBlockGetter = func() int64 { + return 0 + } + + var mockChainIDGetter = func() string { + return "11820" + } + k := keeper.NewKeeper( cdc, runtime.NewKVStoreService(storeKey), + mockTransientStoreService{transientStoreKey}, + nil, nil, nil, nil, nil, + mockBlockGetter, + mockChainIDGetter, log.NewNopLogger(), authority.String(), ) diff --git a/testutil/keeper/fee.go b/testutil/keeper/fee.go index ee552da..e0f7c32 100644 --- a/testutil/keeper/fee.go +++ b/testutil/keeper/fee.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "testing" "cosmossdk.io/log" @@ -17,12 +18,22 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + coreStore "cosmossdk.io/core/store" "github.com/artela-network/artela-rollkit/x/fee/keeper" "github.com/artela-network/artela-rollkit/x/fee/types" ) +type mockTransientStoreService struct { + key *storetypes.TransientStoreKey +} + +func (t mockTransientStoreService) OpenTransientStore(ctx context.Context) coreStore.KVStore { + return nil +} + func FeeKeeper(t testing.TB) (keeper.Keeper, sdk.Context) { storeKey := storetypes.NewKVStoreKey(types.StoreKey) + transientStoreKey := storetypes.NewTransientStoreKey(types.StoreKey) db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) @@ -36,6 +47,7 @@ func FeeKeeper(t testing.TB) (keeper.Keeper, sdk.Context) { k := keeper.NewKeeper( cdc, runtime.NewKVStoreService(storeKey), + mockTransientStoreService{transientStoreKey}, log.NewNopLogger(), authority.String(), ) diff --git a/x/evm/artela/contract/utils.go b/x/aspect/common/utils.go similarity index 99% rename from x/evm/artela/contract/utils.go rename to x/aspect/common/utils.go index 7afa03b..fd3ac0a 100644 --- a/x/evm/artela/contract/utils.go +++ b/x/aspect/common/utils.go @@ -1,4 +1,4 @@ -package contract +package common import ( "bytes" diff --git a/x/aspect/cuckoofilter/bucket.go b/x/aspect/cuckoofilter/bucket.go new file mode 100644 index 0000000..4a83fc5 --- /dev/null +++ b/x/aspect/cuckoofilter/bucket.go @@ -0,0 +1,45 @@ +package cuckoo + +type fingerprint byte + +type bucket [bucketSize]fingerprint + +const ( + nullFp = 0 + bucketSize = 4 +) + +func (b *bucket) insert(fp fingerprint) bool { + for i, tfp := range b { + if tfp == nullFp { + b[i] = fp + return true + } + } + return false +} + +func (b *bucket) delete(fp fingerprint) bool { + for i, tfp := range b { + if tfp == fp { + b[i] = nullFp + return true + } + } + return false +} + +func (b *bucket) getFingerprintIndex(fp fingerprint) int { + for i, tfp := range b { + if tfp == fp { + return i + } + } + return -1 +} + +func (b *bucket) reset() { + for i := range b { + b[i] = nullFp + } +} diff --git a/x/aspect/cuckoofilter/cuckoofilter.go b/x/aspect/cuckoofilter/cuckoofilter.go new file mode 100644 index 0000000..c6ce79e --- /dev/null +++ b/x/aspect/cuckoofilter/cuckoofilter.go @@ -0,0 +1,164 @@ +package cuckoo + +import ( + "fmt" + "math/bits" +) + +const maxCuckooCount = 500 + +// Filter is a probabilistic counter +type Filter struct { + buckets []bucket + count uint + bucketPow uint +} + +// NewFilter returns a new cuckoofilter with a given capacity. +// A capacity of 1000000 is a normal default, which allocates +// about ~1MB on 64-bit machines. +func NewFilter(capacity uint) *Filter { + capacity = getNextPow2(uint64(capacity)) / bucketSize + if capacity == 0 { + capacity = 1 + } + buckets := make([]bucket, capacity) + return &Filter{ + buckets: buckets, + count: 0, + bucketPow: uint(bits.TrailingZeros(capacity)), + } +} + +// Lookup returns true if data is in the counter +func (cf *Filter) Lookup(data []byte) bool { + i1, fp := getIndexAndFingerprint(data, cf.bucketPow) + if cf.buckets[i1].getFingerprintIndex(fp) > -1 { + return true + } + i2 := getAltIndex(fp, i1, cf.bucketPow) + return cf.buckets[i2].getFingerprintIndex(fp) > -1 +} + +// Reset ... +func (cf *Filter) Reset() { + for i := range cf.buckets { + cf.buckets[i].reset() + } + cf.count = 0 +} + +func (cf *Filter) decide(i1, i2 uint) uint { + if cf.count%2 == 0 { + return i1 + } + return i2 +} + +// Insert inserts data into the counter and returns true upon success +func (cf *Filter) Insert(data []byte) bool { + i1, fp := getIndexAndFingerprint(data, cf.bucketPow) + if cf.insert(fp, i1) { + return true + } + i2 := getAltIndex(fp, i1, cf.bucketPow) + if cf.insert(fp, i2) { + return true + } + return cf.reinsert(fp, cf.decide(i1, i2)) +} + +// InsertUnique inserts data into the counter if not exists and returns true upon success +func (cf *Filter) InsertUnique(data []byte) bool { + if cf.Lookup(data) { + return false + } + return cf.Insert(data) +} + +func (cf *Filter) insert(fp fingerprint, i uint) bool { + if cf.buckets[i].insert(fp) { + cf.count++ + return true + } + return false +} + +func (cf *Filter) reinsert(fp fingerprint, i uint) bool { + for k := 0; k < maxCuckooCount; k++ { + j := (cf.count + uint(k)) % bucketSize + oldfp := fp + fp = cf.buckets[i][j] + cf.buckets[i][j] = oldfp + + // look in the alternate location for that random element + i = getAltIndex(fp, i, cf.bucketPow) + if cf.insert(fp, i) { + return true + } + } + return false +} + +// Delete data from counter if exists and return if deleted or not +func (cf *Filter) Delete(data []byte) bool { + i1, fp := getIndexAndFingerprint(data, cf.bucketPow) + if cf.delete(fp, i1) { + return true + } + i2 := getAltIndex(fp, i1, cf.bucketPow) + return cf.delete(fp, i2) +} + +func (cf *Filter) delete(fp fingerprint, i uint) bool { + if cf.buckets[i].delete(fp) { + if cf.count > 0 { + cf.count-- + } + return true + } + return false +} + +// Count returns the number of items in the counter +func (cf *Filter) Count() uint { + return cf.count +} + +// Encode returns a byte slice representing a Cuckoofilter +func (cf *Filter) Encode() []byte { + bytes := make([]byte, len(cf.buckets)*bucketSize) + for i, b := range cf.buckets { + for j, f := range b { + index := (i * len(b)) + j + bytes[index] = byte(f) + } + } + return bytes +} + +// Decode returns a Cuckoofilter from a byte slice +func Decode(bytes []byte) (*Filter, error) { + var count uint + if len(bytes)%bucketSize != 0 { + return nil, fmt.Errorf("expected bytes to be multiple of %d, got %d", bucketSize, len(bytes)) + } + if len(bytes) == 0 { + return nil, fmt.Errorf("bytes can not be empty") + } + buckets := make([]bucket, len(bytes)/4) + for i, b := range buckets { + for j := range b { + index := (i * len(b)) + j + if bytes[index] != 0 { + buckets[i][j] = fingerprint(bytes[index]) + count++ + } + } + } + return &Filter{ + buckets: buckets, + count: count, + bucketPow: uint(bits.TrailingZeros(uint(len(buckets)))), + }, nil +} diff --git a/x/aspect/cuckoofilter/util.go b/x/aspect/cuckoofilter/util.go new file mode 100644 index 0000000..840932e --- /dev/null +++ b/x/aspect/cuckoofilter/util.go @@ -0,0 +1,71 @@ +package cuckoo + +import ( + metro "github.com/dgryski/go-metro" +) + +var ( + altHash = [256]uint{} + masks = [65]uint{} +) + +func init() { + for i := 0; i < 256; i++ { + altHash[i] = (uint(metro.Hash64([]byte{byte(i)}, 1337))) + } + for i := uint(0); i <= 64; i++ { + masks[i] = (1 << i) - 1 + } +} + +func getAltIndex(fp fingerprint, i uint, bucketPow uint) uint { + mask := masks[bucketPow] + hash := altHash[fp] & mask + return (i & mask) ^ hash +} + +func getFingerprint(hash uint64) byte { + // Use least significant bits for fingerprint. + fp := byte(hash%255 + 1) + return fp +} + +// getIndicesAndFingerprint returns the 2 bucket indices and fingerprint to be used +func getIndexAndFingerprint(data []byte, bucketPow uint) (uint, fingerprint) { + hash := defaultHasher.Hash64(data) + fp := getFingerprint(hash) + // Use most significant bits for deriving index. + i1 := uint(hash>>32) & masks[bucketPow] + return i1, fingerprint(fp) +} + +func getNextPow2(n uint64) uint { + n-- + n |= n >> 1 + n |= n >> 2 + n |= n >> 4 + n |= n >> 8 + n |= n >> 16 + n |= n >> 32 + n++ + return uint(n) +} + +var defaultHasher Hasher = new(metrotHasher) + +func SetDefaultHasher(hasher Hasher) { + defaultHasher = hasher +} + +type Hasher interface { + Hash64([]byte) uint64 +} + +var _ Hasher = new(metrotHasher) + +type metrotHasher struct{} + +func (h *metrotHasher) Hash64(data []byte) uint64 { + hash := metro.Hash64(data, 1337) + return hash +} diff --git a/x/aspect/keeper/keeper.go b/x/aspect/keeper/keeper.go new file mode 100644 index 0000000..cbb9517 --- /dev/null +++ b/x/aspect/keeper/keeper.go @@ -0,0 +1,57 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/core/store" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +type ( + Keeper struct { + cdc codec.BinaryCodec + storeService store.KVStoreService + logger log.Logger + + // the address capable of executing a MsgUpdateParams message. Typically, this + // should be the x/gov module account. + authority string + } +) + +func NewKeeper( + cdc codec.BinaryCodec, + storeService store.KVStoreService, + logger log.Logger, + authority string, + +) Keeper { + if _, err := sdk.AccAddressFromBech32(authority); err != nil { + panic(fmt.Sprintf("invalid authority address: %s", authority)) + } + + return Keeper{ + cdc: cdc, + storeService: storeService, + authority: authority, + logger: logger, + } +} + +// GetAuthority returns the module's authority. +func (k Keeper) GetAuthority() string { + return k.authority +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger() log.Logger { + return k.logger.With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +func (k Keeper) GetStoreService() store.KVStoreService { + return k.storeService +} diff --git a/x/aspect/keeper/msg_server.go b/x/aspect/keeper/msg_server.go new file mode 100644 index 0000000..abe9763 --- /dev/null +++ b/x/aspect/keeper/msg_server.go @@ -0,0 +1,17 @@ +package keeper + +import ( + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} diff --git a/x/aspect/keeper/msg_server_test.go b/x/aspect/keeper/msg_server_test.go new file mode 100644 index 0000000..22b986a --- /dev/null +++ b/x/aspect/keeper/msg_server_test.go @@ -0,0 +1,24 @@ +package keeper_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + keepertest "github.com/artela-network/artela-rollkit/testutil/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func setupMsgServer(t testing.TB) (keeper.Keeper, types.MsgServer, context.Context) { + k, ctx := keepertest.AspectKeeper(t) + return k, keeper.NewMsgServerImpl(k), ctx +} + +func TestMsgServer(t *testing.T) { + k, ms, ctx := setupMsgServer(t) + require.NotNil(t, ms) + require.NotNil(t, ctx) + require.NotEmpty(t, k) +} diff --git a/x/aspect/keeper/msg_update_params.go b/x/aspect/keeper/msg_update_params.go new file mode 100644 index 0000000..39294ef --- /dev/null +++ b/x/aspect/keeper/msg_update_params.go @@ -0,0 +1,23 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if k.GetAuthority() != req.Authority { + return nil, errorsmod.Wrapf(types.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.GetAuthority(), req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.SetParams(ctx, req.Params); err != nil { + return nil, err + } + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/aspect/keeper/msg_update_params_test.go b/x/aspect/keeper/msg_update_params_test.go new file mode 100644 index 0000000..daab8e8 --- /dev/null +++ b/x/aspect/keeper/msg_update_params_test.go @@ -0,0 +1,64 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func TestMsgUpdateParams(t *testing.T) { + k, ms, ctx := setupMsgServer(t) + params := types.DefaultParams() + require.NoError(t, k.SetParams(ctx, params)) + wctx := sdk.UnwrapSDKContext(ctx) + + // default params + testCases := []struct { + name string + input *types.MsgUpdateParams + expErr bool + expErrMsg string + }{ + { + name: "invalid authority", + input: &types.MsgUpdateParams{ + Authority: "invalid", + Params: params, + }, + expErr: true, + expErrMsg: "invalid authority", + }, + { + name: "send enabled param", + input: &types.MsgUpdateParams{ + Authority: k.GetAuthority(), + Params: types.Params{}, + }, + expErr: false, + }, + { + name: "all good", + input: &types.MsgUpdateParams{ + Authority: k.GetAuthority(), + Params: params, + }, + expErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + _, err := ms.UpdateParams(wctx, tc.input) + + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/aspect/keeper/params.go b/x/aspect/keeper/params.go new file mode 100644 index 0000000..5e288fb --- /dev/null +++ b/x/aspect/keeper/params.go @@ -0,0 +1,33 @@ +package keeper + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/runtime" + + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +// GetParams get all parameters as types.Params +func (k Keeper) GetParams(ctx context.Context) (params types.Params) { + store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + bz := store.Get(types.ParamsKey) + if bz == nil { + return params + } + + k.cdc.MustUnmarshal(bz, ¶ms) + return params +} + +// SetParams set the params +func (k Keeper) SetParams(ctx context.Context, params types.Params) error { + store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + bz, err := k.cdc.Marshal(¶ms) + if err != nil { + return err + } + store.Set(types.ParamsKey, bz) + + return nil +} diff --git a/x/aspect/keeper/params_test.go b/x/aspect/keeper/params_test.go new file mode 100644 index 0000000..c446795 --- /dev/null +++ b/x/aspect/keeper/params_test.go @@ -0,0 +1,18 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + keepertest "github.com/artela-network/artela-rollkit/testutil/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func TestGetParams(t *testing.T) { + k, ctx := keepertest.AspectKeeper(t) + params := types.DefaultParams() + + require.NoError(t, k.SetParams(ctx, params)) + require.EqualValues(t, params, k.GetParams(ctx)) +} diff --git a/x/aspect/keeper/query.go b/x/aspect/keeper/query.go new file mode 100644 index 0000000..fe9c5c6 --- /dev/null +++ b/x/aspect/keeper/query.go @@ -0,0 +1,7 @@ +package keeper + +import ( + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +var _ types.QueryServer = Keeper{} diff --git a/x/aspect/keeper/query_params.go b/x/aspect/keeper/query_params.go new file mode 100644 index 0000000..9d08e2b --- /dev/null +++ b/x/aspect/keeper/query_params.go @@ -0,0 +1,20 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func (k Keeper) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil +} diff --git a/x/aspect/keeper/query_params_test.go b/x/aspect/keeper/query_params_test.go new file mode 100644 index 0000000..719d7a3 --- /dev/null +++ b/x/aspect/keeper/query_params_test.go @@ -0,0 +1,20 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + keepertest "github.com/artela-network/artela-rollkit/testutil/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +func TestParamsQuery(t *testing.T) { + keeper, ctx := keepertest.AspectKeeper(t) + params := types.DefaultParams() + require.NoError(t, keeper.SetParams(ctx, params)) + + response, err := keeper.Params(ctx, &types.QueryParamsRequest{}) + require.NoError(t, err) + require.Equal(t, &types.QueryParamsResponse{Params: params}, response) +} diff --git a/x/aspect/module/autocli.go b/x/aspect/module/autocli.go new file mode 100644 index 0000000..2debd8c --- /dev/null +++ b/x/aspect/module/autocli.go @@ -0,0 +1,35 @@ +package aspect + +import ( + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + + modulev1 "github.com/artela-network/artela-rollkit/api/artela/aspect" +) + +// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. +func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { + return &autocliv1.ModuleOptions{ + Query: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Params", + Use: "params", + Short: "Shows the parameters of the module", + }, + // this line is used by ignite scaffolding # autocli/query + }, + }, + Tx: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Msg_ServiceDesc.ServiceName, + EnhanceCustomCommand: true, // only required if you want to use the custom command + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "UpdateParams", + Skip: true, // skipped because authority gated + }, + // this line is used by ignite scaffolding # autocli/tx + }, + }, + } +} diff --git a/x/aspect/module/genesis.go b/x/aspect/module/genesis.go new file mode 100644 index 0000000..80ab2a0 --- /dev/null +++ b/x/aspect/module/genesis.go @@ -0,0 +1,26 @@ +package aspect + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/artela-network/artela-rollkit/x/aspect/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + // this line is used by starport scaffolding # genesis/module/init + if err := k.SetParams(ctx, genState.Params); err != nil { + panic(err) + } +} + +// ExportGenesis returns the module's exported genesis. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetParams(ctx) + + // this line is used by starport scaffolding # genesis/module/export + + return genesis +} diff --git a/x/aspect/module/genesis_test.go b/x/aspect/module/genesis_test.go new file mode 100644 index 0000000..53886c4 --- /dev/null +++ b/x/aspect/module/genesis_test.go @@ -0,0 +1,29 @@ +package aspect_test + +import ( + "testing" + + keepertest "github.com/artela-network/artela-rollkit/testutil/keeper" + "github.com/artela-network/artela-rollkit/testutil/nullify" + aspect "github.com/artela-network/artela-rollkit/x/aspect/module" + "github.com/artela-network/artela-rollkit/x/aspect/types" + "github.com/stretchr/testify/require" +) + +func TestGenesis(t *testing.T) { + genesisState := types.GenesisState{ + Params: types.DefaultParams(), + + // this line is used by starport scaffolding # genesis/test/state + } + + k, ctx := keepertest.AspectKeeper(t) + aspect.InitGenesis(ctx, k, genesisState) + got := aspect.ExportGenesis(ctx, k) + require.NotNil(t, got) + + nullify.Fill(&genesisState) + nullify.Fill(got) + + // this line is used by starport scaffolding # genesis/test/assert +} diff --git a/x/aspect/module/module.go b/x/aspect/module/module.go new file mode 100644 index 0000000..17b60a0 --- /dev/null +++ b/x/aspect/module/module.go @@ -0,0 +1,214 @@ +package aspect + +import ( + "context" + "encoding/json" + "fmt" + + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/store" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + + // this line is used by starport scaffolding # 1 + + modulev1 "github.com/artela-network/artela-rollkit/api/artela/aspect/module" + "github.com/artela-network/artela-rollkit/x/aspect/keeper" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +var ( + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasGenesis = (*AppModule)(nil) + _ module.HasInvariants = (*AppModule)(nil) + _ module.HasConsensusVersion = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasBeginBlocker = (*AppModule)(nil) + _ appmodule.HasEndBlocker = (*AppModule)(nil) +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface that defines the +// independent methods a Cosmos SDK module needs to implement. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the name of the module as a string. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the amino codec for the module, which is used +// to marshal and unmarshal structs to/from []byte in order to persist them in the module's KVStore. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} + +// RegisterInterfaces registers a module's interface types and their concrete implementations as proto.Message. +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns a default GenesisState for the module, marshalled to json.RawMessage. +// The default GenesisState need to be defined by the module developer and is primarily used for testing. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface that defines the inter-dependent methods that modules need to implement +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + 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) +} + +// 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) +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the module's genesis initialization. It returns no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, 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) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion is a sequence number for state-breaking change of the module. +// It should be incremented on each consensus-breaking change introduced by the module. +// To avoid wrong/empty versions, the initial version should be set to 1. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock contains the logic that is automatically triggered at the beginning of each block. +// The begin block implementation is optional. +func (am AppModule) BeginBlock(_ context.Context) error { + return nil +} + +// 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 +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} + +// ---------------------------------------------------------------------------- +// App Wiring Setup +// ---------------------------------------------------------------------------- + +func init() { + appmodule.Register( + &modulev1.Module{}, + appmodule.Provide(ProvideModule), + ) +} + +type ModuleInputs struct { + depinject.In + + StoreService store.KVStoreService + Cdc codec.Codec + Config *modulev1.Module + Logger log.Logger + + AccountKeeper types.AccountKeeper + BankKeeper types.BankKeeper +} + +type ModuleOutputs struct { + depinject.Out + + AspectKeeper keeper.Keeper + Module appmodule.AppModule +} + +func ProvideModule(in ModuleInputs) ModuleOutputs { + // default to governance authority if not provided + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + if in.Config.Authority != "" { + authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority) + } + k := keeper.NewKeeper( + in.Cdc, + in.StoreService, + in.Logger, + authority.String(), + ) + m := NewAppModule( + in.Cdc, + k, + in.AccountKeeper, + in.BankKeeper, + ) + + return ModuleOutputs{AspectKeeper: k, Module: m} +} diff --git a/x/aspect/module/simulation.go b/x/aspect/module/simulation.go new file mode 100644 index 0000000..96e90d0 --- /dev/null +++ b/x/aspect/module/simulation.go @@ -0,0 +1,59 @@ +package aspect + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/artela-network/artela-rollkit/testutil/sample" + aspectsimulation "github.com/artela-network/artela-rollkit/x/aspect/simulation" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +// avoid unused import issue +var ( + _ = aspectsimulation.FindAccount + _ = rand.Rand{} + _ = sample.AccAddress + _ = sdk.AccAddress{} + _ = simulation.MsgEntryKind +) + +const ( +// this line is used by starport scaffolding # simapp/module/const +) + +// GenerateGenesisState creates a randomized GenState of the module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + accs := make([]string, len(simState.Accounts)) + for i, acc := range simState.Accounts { + accs[i] = acc.Address.String() + } + aspectGenesis := types.GenesisState{ + Params: types.DefaultParams(), + // this line is used by starport scaffolding # simapp/module/genesisState + } + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&aspectGenesis) +} + +// RegisterStoreDecoder registers a decoder. +func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + operations := make([]simtypes.WeightedOperation, 0) + + // this line is used by starport scaffolding # simapp/module/operation + + return operations +} + +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (am AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + // this line is used by starport scaffolding # simapp/module/OpMsg + } +} diff --git a/x/aspect/provider/artela.go b/x/aspect/provider/artela.go new file mode 100644 index 0000000..9d58185 --- /dev/null +++ b/x/aspect/provider/artela.go @@ -0,0 +1,129 @@ +package provider + +import ( + "context" + "errors" + "slices" + + cstore "cosmossdk.io/core/store" + "github.com/ethereum/go-ethereum/common" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + aspectmoduletypes "github.com/artela-network/artela-rollkit/x/aspect/types" + "github.com/artela-network/artela-rollkit/x/evm/artela/types" + asptypes "github.com/artela-network/aspect-core/types" +) + +var _ asptypes.AspectProvider = (*ArtelaProvider)(nil) + +type ArtelaProvider struct { + getBlockHeight types.GetLastBlockHeight + + evmStoreService cstore.KVStoreService + storeService cstore.KVStoreService +} + +func NewArtelaProvider( + evmStoreService, storeService cstore.KVStoreService, + getBlockHeight types.GetLastBlockHeight, +) *ArtelaProvider { + return &ArtelaProvider{ + evmStoreService: evmStoreService, + storeService: storeService, + getBlockHeight: getBlockHeight, + } +} + +func (j *ArtelaProvider) GetTxBondAspects(ctx context.Context, address common.Address, point asptypes.PointCut) ([]*asptypes.AspectCode, error) { + return j.getCodes(ctx, address, point) +} + +func (j *ArtelaProvider) GetAccountVerifiers(ctx context.Context, address common.Address) ([]*asptypes.AspectCode, error) { + return j.getCodes(ctx, address, asptypes.VERIFY_TX) +} + +func (j *ArtelaProvider) GetLatestBlock() int64 { + return j.getBlockHeight() +} + +func (j *ArtelaProvider) getCodes(ctx context.Context, address common.Address, point asptypes.PointCut) ([]*asptypes.AspectCode, error) { + if ctx == nil { + return nil, errors.New("invalid Context") + } + aspectCtx, ok := ctx.(*types.AspectRuntimeContext) + if !ok { + return nil, errors.New("failed to unwrap AspectRuntimeContext from context.Context") + } + + accountStore, _, err := store.GetAccountStore(j.buildAccountStoreCtx(aspectCtx, address)) + if err != nil { + return nil, err + } + + bindings, err := accountStore.LoadAccountBoundAspects(aspectmoduletypes.NewJoinPointFilter(point)) + if err != nil { + return nil, err + } + + codes := make([]*asptypes.AspectCode, 0, len(bindings)) + for _, binding := range bindings { + metaStore, _, err := store.GetAspectMetaStore(j.buildAspectStoreCtx(aspectCtx, binding.Account)) + if err != nil { + return nil, err + } + code, err := metaStore.GetCode(binding.Version) + if err != nil { + return nil, err + } + + var isExpectedJP bool + if binding.JoinPoint == 0 { + meta, err := metaStore.GetVersionMeta(binding.Version) + if err != nil { + return nil, err + } + isExpectedJP = asptypes.CanExecPoint(int64(meta.JoinPoint), point) + } else { + isExpectedJP = asptypes.CanExecPoint(int64(binding.JoinPoint), point) + } + + // filter matched aspect with given join point + if !isExpectedJP { + continue + } + + codes = append(codes, &asptypes.AspectCode{ + AspectId: binding.Account.Hex(), + Version: binding.Version, + Priority: binding.Priority, + Code: code, + }) + } + + // sort the codes by priority + slices.SortFunc(codes, func(a, b *asptypes.AspectCode) int { + if a.Priority == b.Priority { + return 0 + } else if a.Priority < b.Priority { + return -1 + } else { + return 1 + } + }) + + return codes, nil +} + +func (j *ArtelaProvider) buildAspectStoreCtx(ctx *types.AspectRuntimeContext, aspectID common.Address) *aspectmoduletypes.AspectStoreContext { + return &aspectmoduletypes.AspectStoreContext{ + StoreContext: aspectmoduletypes.NewGasFreeStoreContext(ctx.CosmosContext(), j.evmStoreService, j.storeService), + AspectID: aspectID, + } +} + +func (j *ArtelaProvider) buildAccountStoreCtx(ctx *types.AspectRuntimeContext, account common.Address) *aspectmoduletypes.AccountStoreContext { + return &aspectmoduletypes.AccountStoreContext{ + StoreContext: aspectmoduletypes.NewGasFreeStoreContext(ctx.CosmosContext(), j.evmStoreService, j.storeService), + Account: account, + } +} diff --git a/x/evm/artela/provider/jit_call.go b/x/aspect/provider/jit_call.go similarity index 100% rename from x/evm/artela/provider/jit_call.go rename to x/aspect/provider/jit_call.go diff --git a/x/aspect/simulation/helpers.go b/x/aspect/simulation/helpers.go new file mode 100644 index 0000000..92c437c --- /dev/null +++ b/x/aspect/simulation/helpers.go @@ -0,0 +1,15 @@ +package simulation + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" +) + +// FindAccount find a specific address from an account list +func FindAccount(accs []simtypes.Account, address string) (simtypes.Account, bool) { + creator, err := sdk.AccAddressFromBech32(address) + if err != nil { + panic(err) + } + return simtypes.FindAccount(accs, creator) +} diff --git a/x/aspect/store/errors.go b/x/aspect/store/errors.go new file mode 100644 index 0000000..d5a15e8 --- /dev/null +++ b/x/aspect/store/errors.go @@ -0,0 +1,23 @@ +package store + +import "errors" + +var ( + ErrInvalidProtocolInfo = errors.New("invalid protocol info") + ErrUnknownProtocolVersion = errors.New("unknown protocol version") + ErrCodeNotFound = errors.New("code not found") + ErrInvalidStorageKey = errors.New("invalid storage key") + ErrTooManyProperties = errors.New("aspect property limit exceeds") + ErrInvalidBinding = errors.New("invalid binding") + ErrStorageCorrupted = errors.New("storage corrupted") + ErrNoJoinPoint = errors.New("cannot bind with no-joinpoint aspect") + ErrBindingLimitExceeded = errors.New("binding limit exceeded") + ErrAlreadyBound = errors.New("aspect already bound") + ErrInvalidStoreContext = errors.New("invalid store context") + ErrPropertyReserved = errors.New("property key reserved") + ErrInvalidExtension = errors.New("invalid extension") + ErrInvalidVersionMeta = errors.New("invalid version meta") + ErrSerdeFail = errors.New("serialize or deserialize fail") + ErrBoundNonVerifierWithEOA = errors.New("binding non-verifier aspect with EOA") + ErrInvalidJoinPoint = errors.New("invalid join point") +) diff --git a/x/aspect/store/keys.go b/x/aspect/store/keys.go new file mode 100644 index 0000000..76840b6 --- /dev/null +++ b/x/aspect/store/keys.go @@ -0,0 +1,58 @@ +package store + +import ( + "encoding/binary" + "encoding/hex" +) + +// scope prefixes +var ( + GlobalScope = byte(0xff) + AccountScope = byte(0xee) + AspectScope = byte(0xdd) +) + +// global keys, shouldn't be changed in the future +var ( + AspectProtocolInfoKeyPrefix = []byte{GlobalScope, 0x01} +) + +type KeyBuilder struct { + key []byte +} + +func NewKeyBuilder(prefix []byte) *KeyBuilder { + buffer := make([]byte, len(prefix)) + copy(buffer, prefix) + return &KeyBuilder{key: buffer} +} + +func (k *KeyBuilder) AppendBytes(key []byte) *KeyBuilder { + return NewKeyBuilder(append(k.key, key...)) +} + +func (k *KeyBuilder) AppendUint64(key uint64) *KeyBuilder { + buffer := make([]byte, 8) + binary.BigEndian.PutUint64(buffer, key) + return NewKeyBuilder(append(k.key, buffer...)) +} + +func (k *KeyBuilder) AppendString(key string) *KeyBuilder { + return NewKeyBuilder(append(k.key, key...)) +} + +func (k *KeyBuilder) AppendByte(key byte) *KeyBuilder { + return NewKeyBuilder(append(k.key, key)) +} + +func (k *KeyBuilder) AppendUint8(key uint8) *KeyBuilder { + return NewKeyBuilder(append(k.key, key)) +} + +func (k *KeyBuilder) Build() []byte { + return k.key +} + +func (k *KeyBuilder) String() string { + return hex.EncodeToString(k.key) +} diff --git a/x/aspect/store/store.go b/x/aspect/store/store.go new file mode 100644 index 0000000..4596252 --- /dev/null +++ b/x/aspect/store/store.go @@ -0,0 +1,376 @@ +package store + +import ( + "encoding/binary" + "encoding/hex" + + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/ethereum/go-ethereum/common" + + aspectmoduletypes "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +const ( + ProtocolVersionLen = 2 + ProtocolInfoLen = 4 +) + +type ProtocolVersion uint16 + +func (p ProtocolVersion) MarshalText() ([]byte, error) { + bytes := make([]byte, 2) + binary.BigEndian.PutUint16(bytes, uint16(p)) + return bytes, nil +} + +func (p *ProtocolVersion) UnmarshalText(text []byte) error { + if len(text) < 2 { + *p = 0 + } else { + *p = ProtocolVersion(binary.BigEndian.Uint16(text[:2])) + } + + return nil +} + +func (p ProtocolVersion) Offset() uint64 { + if p == 0 { + return 0 + } else { + return ProtocolVersionLen + } +} + +type AspectInfo struct { + MetaVersion ProtocolVersion + StateVersion ProtocolVersion + + offset uint64 +} + +func (a *AspectInfo) Offset() uint64 { + return a.offset +} + +func (a AspectInfo) MarshalText() ([]byte, error) { + bytes := make([]byte, ProtocolInfoLen) + // next 2 bytes saves meta version + binary.BigEndian.PutUint16(bytes[0:2], uint16(a.MetaVersion)) + // next 2 bytes saves state version + binary.BigEndian.PutUint16(bytes[2:4], uint16(a.StateVersion)) + return bytes, nil +} + +func (a *AspectInfo) UnmarshalText(text []byte) error { + if len(text) == 0 { + // v0 store does not have aspect info, so we just return nil here + // so that all versions of aspect info is 0, which is compatible with v0 store + a.offset = 0 + return nil + } + + if len(text) < ProtocolInfoLen { + return ErrInvalidProtocolInfo + } + + a.MetaVersion = ProtocolVersion(binary.BigEndian.Uint16(text[0:2])) + a.StateVersion = ProtocolVersion(binary.BigEndian.Uint16(text[2:4])) + a.offset = ProtocolInfoLen + + return nil +} + +type ( + AspectStateStoreConstructor = func(ctx *aspectmoduletypes.AspectStoreContext) AspectStateStore + AspectMetaStoreConstructor = func(ctx *aspectmoduletypes.AspectStoreContext, protocolExtension []byte) AspectMetaStore + AccountStoreConstructor = func(ctx *aspectmoduletypes.AccountStoreContext) AccountStore +) + +// aspect initializer registry +var ( + aspectStateStoreRegistry = make(map[ProtocolVersion]AspectStateStoreConstructor) + aspectMetaStoreRegistry = make(map[ProtocolVersion]AspectMetaStoreConstructor) + accountStoreRegistry = make(map[ProtocolVersion]AccountStoreConstructor) +) + +func RegisterAspectStateStore(version ProtocolVersion, constructor AspectStateStoreConstructor) { + aspectStateStoreRegistry[version] = constructor +} + +func RegisterAspectMetaStore(version ProtocolVersion, constructor AspectMetaStoreConstructor) { + aspectMetaStoreRegistry[version] = constructor +} + +func RegisterAccountStore(version ProtocolVersion, constructor AccountStoreConstructor) { + accountStoreRegistry[version] = constructor +} + +type GasMeteredStore interface { + // Gas returns the gas remains in the store + Gas() uint64 + // TransferGasFrom transfers the gas from another store + TransferGasFrom(store GasMeteredStore) +} + +// AccountStore is the store for each account that using aspect +type AccountStore interface { + // LoadAccountBoundAspects returns the aspects bound to the account, + LoadAccountBoundAspects(filter aspectmoduletypes.BindingFilter) ([]aspectmoduletypes.Binding, error) + // StoreBinding adds the binding of the given aspect to the account + StoreBinding(aspectID common.Address, version uint64, joinPoint uint64, priority int8, isCA bool) error + // RemoveBinding removes the binding of the given aspect from the account + RemoveBinding(aspectID common.Address, joinPoint uint64, isCA bool) error + + // Used returns true if this given version of store has been used before + Used() (bool, error) + // MigrateFrom migrates the data from the old store to the new store + MigrateFrom(old AccountStore) error + // Init initializes the store + Init() error + // Version returns the version of the store + Version() ProtocolVersion + + GasMeteredStore +} + +// AspectStateStore is the store for aspect state related info +type AspectStateStore interface { + // GetState returns the value for the given key + GetState(key []byte) []byte + // SetState sets the value for the given key + SetState(key []byte, value []byte) + // Version returns the version of the store + Version() ProtocolVersion +} + +// AspectMetaStore is the store for aspect metadata +type AspectMetaStore interface { + // GetCode returns the code for the given version + GetCode(version uint64) ([]byte, error) + // GetVersionMeta returns the meta for the given version + GetVersionMeta(version uint64) (*aspectmoduletypes.VersionMeta, error) + // GetMeta returns the meta for the aspect + GetMeta() (*aspectmoduletypes.AspectMeta, error) + // GetLatestVersion returns the latest version of the aspect + GetLatestVersion() (uint64, error) + // GetProperty returns the properties for the given version + GetProperty(version uint64, key string) ([]byte, error) + // LoadAspectBoundAccounts returns the accounts bound to the aspect + LoadAspectBoundAccounts() ([]aspectmoduletypes.Binding, error) + + // BumpVersion bumps the version of the aspect + BumpVersion() (uint64, error) + // StoreVersionMeta stores the meta for the given version + StoreVersionMeta(version uint64, meta *aspectmoduletypes.VersionMeta) error + // StoreMeta stores the meta for the aspect + StoreMeta(meta *aspectmoduletypes.AspectMeta) error + // StoreCode stores the code for the given version + StoreCode(version uint64, code []byte) error + // StoreProperties stores the properties for the given version + StoreProperties(version uint64, properties []aspectmoduletypes.Property) error + // StoreBinding stores the binding for the given account + StoreBinding(account common.Address, version uint64, joinPoint uint64, priority int8) error + // RemoveBinding removes the binding for the given account + RemoveBinding(account common.Address) error + + // Version returns the version of the store + Version() ProtocolVersion + // MigrateFrom migrates the data from the old store to the new store + MigrateFrom(old AspectMetaStore) error + // Used returns true if this given version of store has been used before + Used() (bool, error) + // Init initializes the store + Init() error + + GasMeteredStore +} + +// loadProtocolInfo loads the protocol info for the given address +func loadProtocolInfo(ctx aspectmoduletypes.StoreContext) (ProtocolVersion, []byte, error) { + store := runtime.KVStoreAdapter(ctx.StoreService().OpenKVStore(ctx.CosmosContext())) + + var address common.Address + switch ctx := ctx.(type) { + case *aspectmoduletypes.AccountStoreContext: + address = ctx.Account + case *aspectmoduletypes.AspectStoreContext: + address = ctx.AspectID + default: + return 0, nil, ErrInvalidStoreContext + } + + key := NewKeyBuilder(AspectProtocolInfoKeyPrefix).AppendBytes(address.Bytes()).Build() + protoInfo := store.Get(key) + + var protocolVersion ProtocolVersion + if err := protocolVersion.UnmarshalText(protoInfo); err != nil { + ctx.Logger().Error("unmarshal aspect protocol info failed", + "address", address.Hex(), "data", hex.EncodeToString(protoInfo)) + return 0, protoInfo, err + } + + return protocolVersion, protoInfo[protocolVersion.Offset():], nil +} + +// parseAspectInfo parses +func parseAspectInfo(raw []byte) (*AspectInfo, error) { + aspectInfo := &AspectInfo{} + if err := aspectInfo.UnmarshalText(raw); err != nil { + return nil, err + } + + return aspectInfo, nil +} + +// GetAccountStore returns the account store for the given account, +// account store is used to store account related info like bound aspects. +// This function will return 2 stores, the current store and the new store. +// New store will be nil if no migration needed, otherwise it will be the instance of the new version store. +func GetAccountStore(ctx *aspectmoduletypes.AccountStoreContext) (current AccountStore, new AccountStore, err error) { + // load protocol version + protocolVersion, _, err := loadProtocolInfo(ctx) + if err != nil { + return nil, nil, err + } + + // load protocol storage constructor + constructor, ok := accountStoreRegistry[protocolVersion] + if !ok { + ctx.Logger().Error("unsupported protocol version", "version", protocolVersion) + return nil, nil, ErrUnknownProtocolVersion + } + + // if latest version is greater than the used version, + // we also init an instance of the latest version of store to let the caller func + // decides whether to migrate the data or not + var latestStore AccountStore + latestVersion := latestStoreVersion(accountStoreRegistry) + if latestVersion > protocolVersion { + // init the latest store version + latestStore = accountStoreRegistry[latestVersion](ctx) + } + + // if this protocol version is 0, we have 2 cases here: + // 1. the account has never used aspect before + // 2. the account was using aspect at protocol version 0, but not migrated to the new version + // the following is just the special case for processing v0 store + if protocolVersion == 0 { + // init v0 store first + v0Store := constructor(ctx) + // so first we need to check whether this account has used aspect before + if used, err := v0Store.Used(); err != nil { + return nil, nil, err + } else if used { + // if v0 store used, we need to migrate the data to the latest version + return v0Store, latestStore, nil + } else { + // otherwise, we just return the latest store + if latestStore == nil { + // set the latest store to v0 store if no migration needed + latestStore = v0Store + } + + return latestStore, nil, nil + } + } + + // build the aspect store + return constructor(ctx), latestStore, nil +} + +// GetAspectMetaStore returns the aspect meta store for the given aspect id +func GetAspectMetaStore(ctx *aspectmoduletypes.AspectStoreContext) (current AspectMetaStore, new AspectMetaStore, err error) { + // load protocol version + protocolVersion, rawAspectInfo, err := loadProtocolInfo(ctx) + if err != nil { + return nil, nil, err + } + + return getAspectMetaStore(ctx, protocolVersion, rawAspectInfo) +} + +func getAspectMetaStore(ctx *aspectmoduletypes.AspectStoreContext, protocolVersion ProtocolVersion, rawAspectInfo []byte) (current AspectMetaStore, new AspectMetaStore, err error) { + // load aspect info if protocol version is not 0 + aspectInfo, err := parseAspectInfo(rawAspectInfo) + if err != nil { + ctx.Logger().Error("parse aspect info failed", "aspectId", ctx.AspectID.Hex()) + return nil, nil, err + } + protocolExtension := rawAspectInfo[aspectInfo.Offset():] + metaVersion := aspectInfo.MetaVersion + + // load protocol storage constructor + constructor, ok := aspectMetaStoreRegistry[metaVersion] + if !ok { + ctx.Logger().Error("unsupported meta version", "version", metaVersion) + return nil, nil, ErrUnknownProtocolVersion + } + + // if latest version is greater than the used version, + // we also init an instance of the latest version of store to let the caller func + // decides whether to migrate the data or not + var latestStore AspectMetaStore + latestVersion := latestStoreVersion(aspectMetaStoreRegistry) + if latestVersion > protocolVersion { + // init the latest store version + latestStore = aspectMetaStoreRegistry[latestVersion](ctx, protocolExtension) + } + + // if this protocol version is 0, we have 2 cases here: + // 1. the aspect has not been deployed yet + // 2. the aspect is deployed at protocol version 0, but not migrated to the new version + if protocolVersion == 0 { + // init v0 store first + v0Store := constructor(ctx, protocolExtension) + // so first we need to check whether this account has used aspect before + if used, err := v0Store.Used(); err != nil { + // check fail + return nil, nil, err + } else if used { + // if v0 store used, we need to migrate the data to the latest version + return v0Store, latestStore, nil + } else { + // otherwise, we just return the latest store + if latestStore == nil { + // set the latest store to v0 store if no migration needed + latestStore = v0Store + } + + return latestStore, nil, nil + } + } + + // build the aspect store + return constructor(ctx, protocolExtension), latestStore, nil +} + +func GetAspectStateStore(ctx *aspectmoduletypes.AspectStoreContext) (AspectStateStore, error) { + // load protocol version + _, rawAspectInfo, err := loadProtocolInfo(ctx) + if err != nil { + return nil, err + } + + // aspect info must have been initialized before the state store initialized, + // if rawAspectInfo is empty, we just go with init v0 store + aspectInfo, err := parseAspectInfo(rawAspectInfo) + if err != nil { + ctx.Logger().Error("parse aspect info failed", "aspectId", ctx.AspectID.Hex()) + return nil, err + } + + stateVersion := aspectInfo.StateVersion + + // load protocol state constructor + constructor, ok := aspectStateStoreRegistry[stateVersion] + if !ok { + ctx.Logger().Error("unsupported state version", "version", stateVersion) + return nil, ErrUnknownProtocolVersion + } + + return constructor(ctx), nil +} + +func latestStoreVersion[T any](registry map[ProtocolVersion]T) ProtocolVersion { + return ProtocolVersion(len(registry) - 1) +} diff --git a/x/aspect/store/v0/account.go b/x/aspect/store/v0/account.go new file mode 100644 index 0000000..4706ecc --- /dev/null +++ b/x/aspect/store/v0/account.go @@ -0,0 +1,278 @@ +package v0 + +import ( + "encoding/json" + "slices" + "sort" + + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + "github.com/artela-network/artela-rollkit/x/aspect/types" + evmtypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" + artelasdkType "github.com/artela-network/aspect-core/types" +) + +var _ store.AccountStore = (*accountStore)(nil) + +// accountStore is the version 0 account Store, this is no longer maintained. +// Deprecated. +type accountStore struct { + BaseStore + + ctx *types.AccountStoreContext +} + +// NewAccountStore creates a new instance of account Store. +// Deprecated +func NewAccountStore(ctx *types.AccountStoreContext) store.AccountStore { + var meter GasMeter + if ctx.ChargeGas() { + meter = NewGasMeter(ctx) + } else { + meter = NewNoOpGasMeter(ctx) + } + + store := runtime.KVStoreAdapter(ctx.EVMStoreService().OpenKVStore(ctx.CosmosContext())) + + return &accountStore{ + BaseStore: NewBaseStore(meter, store), + ctx: ctx, + } +} + +func (s *accountStore) Used() (bool, error) { + // check all binding keys, if any of them is not empty, then the account Store is used + bindingKeys := []string{V0VerifierBindingKeyPrefix, V0ContractBindKeyPrefix} + account := s.ctx.Account + for _, bindingKey := range bindingKeys { + prefixStore := s.NewPrefixStore(bindingKey) + storeKey := AccountKey(account.Bytes()) + rawJSON, err := s.Load(prefixStore, storeKey) + if err != nil { + return false, err + } + if len(rawJSON) > 0 { + return true, nil + } + } + + return false, nil +} + +func (s *accountStore) MigrateFrom(old store.AccountStore) error { + panic("cannot migrate to v0 Store") +} + +func (s *accountStore) Init() error { + return nil +} + +func (s *accountStore) getBindingKeyAndLimit(joinPoint uint64, isCA bool) ([]struct { + key string + limit uint8 +}, error) { + joinPointI64 := int64(joinPoint) + isTxLevel := artelasdkType.CheckIsTransactionLevel(joinPointI64) + isVerifier := artelasdkType.CheckIsTxVerifier(joinPointI64) + + // for EoA account we can only bind verifier aspect + if !isCA && !isVerifier { + return nil, store.ErrInvalidBinding + } + + // only allow 1 verifier for each contract + verifierLimit := maxContractVerifierBoundLimit + if isCA { + verifierLimit = 1 + } + + bindingKeysAndLimit := make([]struct { + key string + limit uint8 + }, 0) + if isTxLevel { + bindingKeysAndLimit = append(bindingKeysAndLimit, struct { + key string + limit uint8 + }{key: V0ContractBindKeyPrefix, limit: maxAspectBoundLimit}) + } + if isVerifier { + bindingKeysAndLimit = append(bindingKeysAndLimit, struct { + key string + limit uint8 + }{key: V0VerifierBindingKeyPrefix, limit: verifierLimit}) + } + + return bindingKeysAndLimit, nil +} + +// StoreBinding stores the binding of the aspect with the given ID to the account. +func (s *accountStore) StoreBinding(aspectID common.Address, version uint64, joinPoint uint64, priority int8, isCA bool) error { + bindingKeysAndLimit, err := s.getBindingKeyAndLimit(joinPoint, isCA) + if err != nil { + return err + } + + account := s.ctx.Account + for _, bindingKeyAndLimit := range bindingKeysAndLimit { + prefixStore := s.NewPrefixStore(bindingKeyAndLimit.key) + storeKey := AccountKey(account.Bytes()) + rawJSON, err := s.Load(prefixStore, storeKey) + if err != nil { + return err + } + + bindings := make([]*evmtypes.AspectMeta, 0) + if len(rawJSON) > 0 { + if err := json.Unmarshal(rawJSON, &bindings); err != nil { + return store.ErrStorageCorrupted + } + } + + if len(bindings) >= int(bindingKeyAndLimit.limit) { + return store.ErrBindingLimitExceeded + } + + // check duplicates + for _, binding := range bindings { + if binding.Id == aspectID { + return store.ErrAlreadyBound + } + } + + newAspect := &evmtypes.AspectMeta{ + Id: aspectID, + Version: uint256.NewInt(version), + Priority: int64(priority), + } + + bindings = append(bindings, newAspect) + + // re-sort aspects by priority + if len(bindings) > 1 { + sort.Slice(bindings, evmtypes.NewBindingPriorityComparator(bindings)) + } + + bindingJSON, err := json.Marshal(bindings) + if err != nil { + return err + } + + if err := s.Store(prefixStore, storeKey, bindingJSON); err != nil { + return err + } + + s.ctx.Logger().Debug("aspect binding added", + "aspect", aspectID.Hex(), + "account", account.Hex(), + "storekey", bindingKeyAndLimit.key) + } + + return nil +} + +// RemoveBinding removes the binding of the aspect with the given ID from the account. +func (s *accountStore) RemoveBinding(aspectID common.Address, joinPoint uint64, isCA bool) error { + bindingKeysAndLimit, err := s.getBindingKeyAndLimit(joinPoint, isCA) + if err != nil { + return err + } + + account := s.ctx.Account + for _, bindingKeyAndLimit := range bindingKeysAndLimit { + prefixStore := s.NewPrefixStore(bindingKeyAndLimit.key) + storeKey := AccountKey(account.Bytes()) + rawJSON, err := s.Load(prefixStore, storeKey) + if err != nil { + return err + } + + bindings := make([]*evmtypes.AspectMeta, 0) + if len(rawJSON) > 0 { + if err := json.Unmarshal(rawJSON, &bindings); err != nil { + return store.ErrStorageCorrupted + } + } + + toDelete := slices.IndexFunc(bindings, func(meta *evmtypes.AspectMeta) bool { + return meta.Id == aspectID + }) + + if toDelete < 0 { + // not found + return nil + } + + bindings = slices.Delete(bindings, toDelete, toDelete+1) + bindingJSON, err := json.Marshal(bindings) + if err != nil { + return err + } + + if err := s.Store(prefixStore, storeKey, bindingJSON); err != nil { + return err + } + + s.ctx.Logger().Debug("aspect binding removed", + "aspect", aspectID.Hex(), + "account", account.Hex(), + "storekey", bindingKeyAndLimit.key) + } + + return nil +} + +// LoadAccountBoundAspects loads all aspects bound to the given account. +func (s *accountStore) LoadAccountBoundAspects(filter types.BindingFilter) ([]types.Binding, error) { + bindingKeys := make([]string, 0, 1) + if filter.JoinPoint != nil { + joinPoint := *filter.JoinPoint + if string(joinPoint) == artelasdkType.JoinPointRunType_VerifyTx.String() { + bindingKeys = append(bindingKeys, V0VerifierBindingKeyPrefix) + } else { + bindingKeys = append(bindingKeys, V0ContractBindKeyPrefix) + } + } else if filter.VerifierOnly { + bindingKeys = append(bindingKeys, V0VerifierBindingKeyPrefix) + } else if filter.TxLevelOnly { + bindingKeys = append(bindingKeys, V0ContractBindKeyPrefix) + } else { + bindingKeys = append(bindingKeys, V0VerifierBindingKeyPrefix, V0ContractBindKeyPrefix) + } + + account := s.ctx.Account + bindingSet := make(map[common.Address]struct{}) + bindings := make([]types.Binding, 0) + for _, bindingKey := range bindingKeys { + prefixStore := s.NewPrefixStore(bindingKey) + storeKey := AccountKey(account.Bytes()) + rawJSON, err := s.Load(prefixStore, storeKey) + if err != nil { + return nil, err + } + + aspectMetas := make([]*evmtypes.AspectMeta, 0) + if len(rawJSON) > 0 { + if err := json.Unmarshal(rawJSON, &aspectMetas); err != nil { + return nil, store.ErrStorageCorrupted + } + } + + for _, aspectMeta := range aspectMetas { + if _, ok := bindingSet[aspectMeta.Id]; ok { + continue + } + bindings = append(bindings, types.Binding{ + Account: aspectMeta.Id, + Version: aspectMeta.Version.Uint64(), + Priority: int8(aspectMeta.Priority), + }) + bindingSet[aspectMeta.Id] = struct{}{} + } + } + + return bindings, nil +} diff --git a/x/aspect/store/v0/base.go b/x/aspect/store/v0/base.go new file mode 100644 index 0000000..02c8c7c --- /dev/null +++ b/x/aspect/store/v0/base.go @@ -0,0 +1,90 @@ +package v0 + +import ( + "math" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" +) + +var emptyAddress common.Address + +const ( + maxAspectBoundLimit = math.MaxUint8 + maxContractVerifierBoundLimit = uint8(1) + protocolVersion = store.ProtocolVersion(0) +) + +// BaseStore defines a shared base store which can be implemented by all other stores +type BaseStore interface { + NewPrefixStore(prefixKey string) prefix.Store + Load(prefixStore prefix.Store, key []byte) ([]byte, error) + Store(prefixStore prefix.Store, key, value []byte) error + Version() store.ProtocolVersion + + store.GasMeteredStore +} + +type baseStore struct { + gasMeter GasMeter + kvStore storetypes.KVStore +} + +func NewBaseStore(gasMeter GasMeter, kvStore storetypes.KVStore) BaseStore { + return &baseStore{ + gasMeter: gasMeter, + kvStore: kvStore, + } +} + +// Version returns the protocol version of the Store. +func (s *baseStore) Version() store.ProtocolVersion { + return protocolVersion +} + +// NewPrefixStore creates an instance of prefix Store, +func (s *baseStore) NewPrefixStore(prefixKey string) prefix.Store { + return prefix.NewStore(s.kvStore, evmtypes.KeyPrefix(prefixKey)) +} + +// Load loads the value from the given Store and do gas metering for the given operation +func (s *baseStore) Load(prefixStore prefix.Store, key []byte) ([]byte, error) { + if key == nil { + return nil, store.ErrInvalidStorageKey + } + + value := prefixStore.Get(key) + + // gas metering after Load, since we are not like EVM, the data length is not known before Load + if err := s.gasMeter.MeasureStorageLoad(len(key) + len(value)); err != nil { + return nil, err + } + + return value, nil +} + +// Store stores the value to the given store and do gas metering for the given operation +func (s *baseStore) Store(prefixStore prefix.Store, key, value []byte) error { + if key == nil { + return store.ErrInvalidStorageKey + } + + if err := s.gasMeter.MeasureStorageStore(len(key) + len(value)); err != nil { + return err + } + + prefixStore.Set(key, value) + return nil +} + +func (s *baseStore) TransferGasFrom(store store.GasMeteredStore) { + s.gasMeter.UpdateGas(store.Gas()) +} + +func (s *baseStore) Gas() uint64 { + return s.gasMeter.RemainingGas() +} diff --git a/x/aspect/store/v0/gas.go b/x/aspect/store/v0/gas.go new file mode 100644 index 0000000..524b3c9 --- /dev/null +++ b/x/aspect/store/v0/gas.go @@ -0,0 +1,100 @@ +package v0 + +import ( + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +const ( + storageLoadCost = 10 + storageStoreCost = 1000 + storageSaveCodeCost = 1000 + storageUpdateCost = 1000 +) + +type GasMeter interface { + MeasureStorageUpdate(dataLen int) error + MeasureStorageCodeSave(dataLen int) error + MeasureStorageStore(dataLen int) error + MeasureStorageLoad(dataLen int) error + RemainingGas() uint64 + UpdateGas(newGas uint64) + Consume(dataLen int, gasCostPer32Bytes uint64) error +} + +type noopGasMeter struct { + ctx types.StoreContext +} + +func NewNoOpGasMeter(ctx types.StoreContext) GasMeter { + return &noopGasMeter{ + ctx: ctx, + } +} + +func (n *noopGasMeter) UpdateGas(_ uint64) { + return +} + +func (n *noopGasMeter) MeasureStorageUpdate(_ int) error { + return nil +} + +func (n *noopGasMeter) MeasureStorageCodeSave(_ int) error { + return nil +} + +func (n *noopGasMeter) MeasureStorageStore(_ int) error { + return nil +} + +func (n *noopGasMeter) MeasureStorageLoad(_ int) error { + return nil +} + +func (n *noopGasMeter) RemainingGas() uint64 { + return n.ctx.Gas() +} + +func (n *noopGasMeter) Consume(_ int, _ uint64) error { + return nil +} + +// gasMeter is a simple gas metering implementation for aspect storage v0. +type gasMeter struct { + ctx types.StoreContext +} + +func NewGasMeter(ctx types.StoreContext) GasMeter { + return &gasMeter{ + ctx: ctx, + } +} + +func (m *gasMeter) MeasureStorageUpdate(dataLen int) error { + return m.Consume(dataLen, storageUpdateCost) +} + +func (m *gasMeter) MeasureStorageCodeSave(dataLen int) error { + return m.Consume(dataLen, storageSaveCodeCost) +} + +func (m *gasMeter) MeasureStorageStore(dataLen int) error { + return m.Consume(dataLen, storageStoreCost) +} + +func (m *gasMeter) MeasureStorageLoad(dataLen int) error { + return m.Consume(dataLen, storageLoadCost) +} + +func (m *gasMeter) RemainingGas() uint64 { + return m.ctx.Gas() +} + +func (m *gasMeter) Consume(dataLen int, gasCostPer32Bytes uint64) error { + gas := ((uint64(dataLen) + 32) >> 5) * gasCostPer32Bytes + return m.ctx.ConsumeGas(gas) +} + +func (m *gasMeter) UpdateGas(gas uint64) { + m.ctx.UpdateGas(gas) +} diff --git a/x/aspect/store/v0/init.go b/x/aspect/store/v0/init.go new file mode 100644 index 0000000..ea93a8f --- /dev/null +++ b/x/aspect/store/v0/init.go @@ -0,0 +1,9 @@ +package v0 + +import "github.com/artela-network/artela-rollkit/x/aspect/store" + +func init() { + store.RegisterAccountStore(0, NewAccountStore) + store.RegisterAspectMetaStore(0, NewAspectMetaStore) + store.RegisterAspectStateStore(0, NewStateStore) +} diff --git a/x/aspect/store/v0/keys.go b/x/aspect/store/v0/keys.go new file mode 100644 index 0000000..69d9c6e --- /dev/null +++ b/x/aspect/store/v0/keys.go @@ -0,0 +1,94 @@ +package v0 + +// v0 keys +const ( + // AspectCodeKeyPrefix is the prefix to retrieve all AspectCodeStore + V0AspectCodeKeyPrefix = "AspectStore/Code/" + V0AspectCodeVersionKeyPrefix = "AspectStore/Version/" + V0AspectPropertyKeyPrefix = "AspectStore/Property/" + V0ContractBindKeyPrefix = "AspectStore/ContractBind/" + V0VerifierBindingKeyPrefix = "AspectStore/VerifierBind/" + V0AspectRefKeyPrefix = "AspectStore/AspectRef/" + V0AspectStateKeyPrefix = "AspectStore/State/" + + V0AspectJoinPointRunKeyPrefix = "AspectStore/JoinPointRun/" + + V0AspectIDMapKey = "aspectId" + V0VersionMapKey = "version" + V0PriorityMapKey = "priority" + + V0AspectAccountKey = "Aspect_@Acount@_" + V0AspectProofKey = "Aspect_@Proof@_" + V0AspectRunJoinPointKey = "Aspect_@Run@JoinPoint@_" + V0AspectPropertyAllKeyPrefix = "Aspect_@Property@AllKey@_" + V0AspectPropertyAllKeySplit = "^^^" +) + +var ( + PathSeparator = []byte("/") + PathSeparatorLen = len(PathSeparator) +) + +func AspectArrayKey(keys ...[]byte) []byte { + var key []byte + for _, b := range keys { + key = append(key, b...) + key = append(key, PathSeparator...) + } + return key +} + +// AspectCodeStoreKey returns the Store key to retrieve a AspectCodeStore from the index fields +func AspectPropertyKey( + aspectID []byte, + propertyKey []byte, +) []byte { + key := make([]byte, 0, len(aspectID)+PathSeparatorLen*2+len(propertyKey)) + + key = append(key, aspectID...) + key = append(key, PathSeparator...) + key = append(key, propertyKey...) + key = append(key, PathSeparator...) + + return key +} + +func AspectVersionKey( + aspectID []byte, + version []byte, +) []byte { + key := make([]byte, 0, len(aspectID)+PathSeparatorLen*2+len(version)) + + key = append(key, aspectID...) + key = append(key, PathSeparator...) + key = append(key, version...) + key = append(key, PathSeparator...) + + return key +} + +func AspectIDKey( + aspectID []byte, +) []byte { + key := make([]byte, 0, len(aspectID)+PathSeparatorLen) + key = append(key, aspectID...) + key = append(key, PathSeparator...) + + return key +} + +func AspectBlockKey() []byte { + var key []byte + key = append(key, []byte("AspectBlock")...) + key = append(key, PathSeparator...) + return key +} + +func AccountKey( + account []byte, +) []byte { + key := make([]byte, 0, len(account)+PathSeparatorLen) + key = append(key, account...) + key = append(key, PathSeparator...) + return key +} diff --git a/x/aspect/store/v0/meta.go b/x/aspect/store/v0/meta.go new file mode 100644 index 0000000..8f986fe --- /dev/null +++ b/x/aspect/store/v0/meta.go @@ -0,0 +1,417 @@ +package v0 + +import ( + "math/big" + "strings" + + "cosmossdk.io/store/prefix" + artelasdkType "github.com/artela-network/aspect-core/types" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/emirpasic/gods/sets/treeset" + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" + + aspectutils "github.com/artela-network/artela-rollkit/x/aspect/common" + "github.com/artela-network/artela-rollkit/x/aspect/store" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +var _ store.AspectMetaStore = (*metaStore)(nil) + +var reservedPropertyKeys = map[string]struct{}{ + V0AspectAccountKey: {}, + V0AspectProofKey: {}, + V0AspectPropertyAllKeyPrefix: {}, +} + +// metaStore is the version 0 aspect meta, this is no longer maintained. +// Just keeping for backward compatibility. +// Deprecated. +type metaStore struct { + BaseStore + + latestVersionCache uint64 + ctx *types.AspectStoreContext +} + +// NewAspectMetaStore creates a new instance of aspect meta Store. +// Deprecated +func NewAspectMetaStore(ctx *types.AspectStoreContext, _ []byte) store.AspectMetaStore { + var meter GasMeter + if ctx.ChargeGas() { + meter = NewGasMeter(ctx) + } else { + meter = NewNoOpGasMeter(ctx) + } + + store := runtime.KVStoreAdapter(ctx.EVMStoreService().OpenKVStore(ctx.CosmosContext())) + + return &metaStore{ + BaseStore: NewBaseStore(meter, store), + ctx: ctx, + } +} + +func (s *metaStore) StoreMeta(meta *types.AspectMeta) error { + // v0 Store saves paymaster and proof as aspect properties + paymaster := types.Property{ + Key: V0AspectAccountKey, + Value: meta.PayMaster.Bytes(), + } + proof := types.Property{ + Key: V0AspectProofKey, + Value: meta.Proof, + } + return s.storeProperties([]types.Property{paymaster, proof}) +} + +func (s *metaStore) GetMeta() (*types.AspectMeta, error) { + paymaster, err := s.GetProperty(0, V0AspectAccountKey) + if err != nil { + return nil, err + } + proof, err := s.GetProperty(0, V0AspectProofKey) + if err != nil { + return nil, err + } + + return &types.AspectMeta{ + PayMaster: common.BytesToAddress(paymaster), + Proof: proof, + }, nil +} + +// StoreBinding stores the binding of the aspect with the given ID to the account. +func (s *metaStore) StoreBinding(account common.Address, _ uint64, _ uint64, _ int8) error { + return s.saveAspectRef(s.NewPrefixStore(V0AspectRefKeyPrefix), s.ctx.AspectID, account) +} + +// RemoveBinding removes the binding of the aspect with the given ID from the account. +func (s *metaStore) RemoveBinding(account common.Address) error { + return s.removeAspectRef(s.NewPrefixStore(V0AspectRefKeyPrefix), account) +} + +func (s *metaStore) MigrateFrom(_ store.AspectMetaStore) error { + panic("cannot migrate to Store v0") +} + +func (s *metaStore) Used() (bool, error) { + v, err := s.GetLatestVersion() + if err != nil { + return false, err + } + return v > 0, err +} + +func (s *metaStore) Init() error { + // for v0 Store, we do not need to init anything + return nil +} + +// GetCode returns the code of the aspect with the given ID and version. +// If version is 0 or aspectID is empty, it returns * Store.ErrCodeNotFound. +func (s *metaStore) GetCode(version uint64) ([]byte, error) { + aspectID := s.ctx.AspectID + if version == 0 || aspectID == emptyAddress { + return nil, store.ErrCodeNotFound + } + prefixStore := s.NewPrefixStore(V0AspectCodeKeyPrefix) + storeKey := AspectVersionKey(aspectID.Bytes(), uint256.NewInt(version).Bytes()) + + // we do not charge gas for code loading + code := prefixStore.Get(storeKey) + + // stored code is already validated, so we can ignore the error here + return aspectutils.ParseByteCode(code) +} + +// GetVersionMeta returns the meta of the aspect with the given ID and version. +func (s *metaStore) GetVersionMeta(version uint64) (*types.VersionMeta, error) { + return s.getMeta(s.ctx.AspectID, version) +} + +func (s *metaStore) getMeta(aspectID common.Address, version uint64) (*types.VersionMeta, error) { + u256Version := uint256.NewInt(version) + prefixStore := s.NewPrefixStore(V0AspectJoinPointRunKeyPrefix) + storeKey := AspectArrayKey( + aspectID.Bytes(), + u256Version.Bytes(), + []byte(V0AspectRunJoinPointKey), + ) + + joinPoint, err := s.Load(prefixStore, storeKey) + if err != nil { + return nil, err + } + + // for v0 pay master / Store / code hash is not stored + return &types.VersionMeta{ + JoinPoint: big.NewInt(0).SetBytes(joinPoint).Uint64(), + }, nil +} + +func (s *metaStore) GetLatestVersion() (uint64, error) { + return s.getLatestVersion(s.ctx.AspectID) +} + +// GetLatestVersion returns the latest version of the aspect with the given ID. +func (s *metaStore) getLatestVersion(aspectID common.Address) (uint64, error) { + if s.latestVersionCache > 0 { + return s.latestVersionCache, nil + } + + prefixStore := s.NewPrefixStore(V0AspectCodeVersionKeyPrefix) + storeKey := AspectIDKey(aspectID.Bytes()) + + // v0 aspect Store uses uint256 to Store version + version := uint256.NewInt(0) + versionBytes, err := s.Load(prefixStore, storeKey) + if err != nil { + return 0, err + } + if versionBytes != nil || len(versionBytes) > 0 { + version.SetBytes(versionBytes) + } + + s.latestVersionCache = version.Uint64() + return s.latestVersionCache, nil +} + +// GetProperty returns the property of the aspect with the given ID and key. +func (s *metaStore) GetProperty(_ uint64, key string) ([]byte, error) { + aspectID := s.ctx.AspectID + codeStore := s.NewPrefixStore(V0AspectPropertyKeyPrefix) + if _, ok := reservedPropertyKeys[key]; ok { + // for reserved key, we return empty value + return nil, nil + } + + aspectPropertyKey := AspectPropertyKey( + aspectID.Bytes(), + []byte(key), + ) + + return s.Load(codeStore, aspectPropertyKey) +} + +// BumpVersion bumps the version of the aspect with the given ID. +func (s *metaStore) BumpVersion() (v uint64, err error) { + aspectID := s.ctx.AspectID + version, err := s.GetLatestVersion() + if err != nil { + s.ctx.Logger().Error("failed to get latest version", "aspect", aspectID.Hex(), "err", err) + return 0, err + } + + newVersionU64 := version + 1 + newVersion := uint256.NewInt(newVersionU64) + prefixStore := s.NewPrefixStore(V0AspectCodeVersionKeyPrefix) + storeKey := AspectIDKey(aspectID.Bytes()) + + defer func() { + if err == nil { + s.latestVersionCache = newVersionU64 + } + }() + + return newVersionU64, s.Store(prefixStore, storeKey, newVersion.Bytes()) +} + +// StoreVersionMeta stores the meta of the aspect with the given ID and version. +func (s *metaStore) StoreVersionMeta(version uint64, meta *types.VersionMeta) error { + aspectID := s.ctx.AspectID + // Store join point + if meta.JoinPoint > 0 { + u256Version := uint256.NewInt(version) + joinPointBig := big.NewInt(0).SetUint64(meta.JoinPoint) + if _, ok := artelasdkType.CheckIsJoinPoint(joinPointBig); !ok { + joinPointBig.SetUint64(0) + } + + prefixStore := s.NewPrefixStore(V0AspectJoinPointRunKeyPrefix) + storeKey := AspectArrayKey(aspectID.Bytes(), u256Version.Bytes(), []byte(V0AspectRunJoinPointKey)) + if err := s.Store(prefixStore, storeKey, joinPointBig.Bytes()); err != nil { + return err + } + } + + // for v0 pay master / proof is stored with property + // code hash is not stored + return nil +} + +// StoreCode stores the code of the aspect with the given ID and version. +func (s *metaStore) StoreCode(version uint64, code []byte) error { + aspectID := s.ctx.AspectID + prefixStore := s.NewPrefixStore(V0AspectCodeKeyPrefix) + storeKey := AspectVersionKey(aspectID.Bytes(), uint256.NewInt(version).Bytes()) + return s.Store(prefixStore, storeKey, code) +} + +// StoreProperties stores the properties of the aspect with the given ID. +func (s *metaStore) StoreProperties(_ uint64, properties []types.Property) error { + if len(properties) == 0 { + return nil + } + + // check reserved keys + for _, prop := range properties { + if _, ok := reservedPropertyKeys[prop.Key]; ok { + return store.ErrPropertyReserved + } + } + + return s.storeProperties(properties) +} + +func (s *metaStore) storeProperties(properties []types.Property) error { + aspectID := s.ctx.AspectID + prefixStore := s.NewPrefixStore(V0AspectPropertyKeyPrefix) + propertyKeysKey := AspectPropertyKey(aspectID.Bytes(), []byte(V0AspectPropertyAllKeyPrefix)) + + propertyAllKey, err := s.Load(prefixStore, propertyKeysKey) + if err != nil { + return err + } + + keySet := treeset.NewWithStringComparator() + // add propertyAllKey to keySet + if len(propertyAllKey) > 0 { + splitData := strings.Split(string(propertyAllKey), V0AspectPropertyAllKeySplit) + for _, datum := range splitData { + keySet.Add(datum) + } + } + + for i := range properties { + // add key and deduplicate + keySet.Add(properties[i].Key) + } + + // check key limit + if keySet.Size() > types.AspectPropertyLimit { + return store.ErrTooManyProperties + } + + // Store property key + for i := range properties { + key := properties[i].Key + value := properties[i].Value + + // Store + aspectPropertyKey := AspectPropertyKey( + aspectID.Bytes(), + []byte(key), + ) + + if err := s.Store(prefixStore, aspectPropertyKey, value); err != nil { + s.ctx.Logger().Error("failed to Store aspect property", "aspect", aspectID.Hex(), "key", key, "err", err) + return err + } + + s.ctx.Logger().Debug("aspect property updated", "aspect", aspectID.Hex(), "key", key) + } + + // Store AspectPropertyAllKey + keyAry := make([]string, keySet.Size()) + for i, key := range keySet.Values() { + keyAry[i] = key.(string) + } + allKeys := strings.Join(keyAry, V0AspectPropertyAllKeySplit) + allKeysKey := AspectPropertyKey( + aspectID.Bytes(), + []byte(V0AspectPropertyAllKeyPrefix), + ) + if err := s.Store(prefixStore, allKeysKey, []byte(allKeys)); err != nil { + return err + } + + return nil +} + +// LoadAspectBoundAccounts loads all accounts bound to the given aspect. +func (s *metaStore) LoadAspectBoundAccounts() ([]types.Binding, error) { + prefixStore := s.NewPrefixStore(V0AspectRefKeyPrefix) + set, err := s.loadAspectRef(prefixStore) + if err != nil { + return nil, err + } + + bindings := make([]types.Binding, 0) + if set != nil { + for _, data := range set.Values() { + contractAddr := common.HexToAddress(data.(string)) + bindings = append(bindings, types.Binding{ + Account: contractAddr, + }) + } + } + + return bindings, nil +} + +func (s *metaStore) saveAspectRef(prefixStore prefix.Store, aspectID common.Address, account common.Address) error { + storeKey := AspectIDKey(aspectID.Bytes()) + set, err := s.loadAspectRef(prefixStore) + if err != nil { + return err + } + + accountHex := account.Hex() + if set.Contains(accountHex) { + // already exist + return store.ErrAlreadyBound + } + + set.Add(accountHex) + rawJSON, err := set.MarshalJSON() + if err != nil { + return err + } + + return s.Store(prefixStore, storeKey, rawJSON) +} + +func (s *metaStore) removeAspectRef(prefixStore prefix.Store, account common.Address) error { + aspectID := s.ctx.AspectID + storeKey := AspectIDKey(aspectID.Bytes()) + set, err := s.loadAspectRef(prefixStore) + if err != nil { + return err + } + + accountHex := account.Hex() + if !set.Contains(accountHex) { + // not exist + return nil + } + + set.Remove(accountHex) + rawJSON, err := set.MarshalJSON() + if err != nil { + return err + } + + return s.Store(prefixStore, storeKey, rawJSON) +} + +func (s *metaStore) loadAspectRef(prefixStore prefix.Store) (*treeset.Set, error) { + aspectID := s.ctx.AspectID + storeKey := AspectIDKey(aspectID.Bytes()) + + rawTree, err := s.Load(prefixStore, storeKey) + if err != nil { + return nil, err + } + + if rawTree == nil { + return treeset.NewWithStringComparator(), nil + } + + set := treeset.NewWithStringComparator() + if err := set.UnmarshalJSON(rawTree); err != nil { + return nil, err + } + + return set, nil +} diff --git a/x/aspect/store/v0/state.go b/x/aspect/store/v0/state.go new file mode 100644 index 0000000..147ea3f --- /dev/null +++ b/x/aspect/store/v0/state.go @@ -0,0 +1,50 @@ +package v0 + +import ( + "github.com/cosmos/cosmos-sdk/runtime" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +var _ store.AspectStateStore = (*stateStore)(nil) + +// stateStore is the version 0 state Store, this is no longer maintained. +// Deprecated. +type stateStore struct { + BaseStore + + ctx *types.AspectStoreContext +} + +// NewStateStore creates a new instance of account state. +// Deprecated +func NewStateStore(ctx *types.AspectStoreContext) store.AspectStateStore { + // for state Store, we have already charged gas in host api, + // so no need to charge it again in the Store + store := runtime.KVStoreAdapter(ctx.EVMStoreService().OpenKVStore(ctx.CosmosContext())) + + return &stateStore{ + BaseStore: NewBaseStore(NewNoOpGasMeter(ctx), store), + ctx: ctx, + } +} + +// SetState sets the state of the aspect with the given ID and key. +func (s *stateStore) SetState(key []byte, value []byte) { + aspectID := s.ctx.AspectID + prefixStore := s.NewPrefixStore(V0AspectStateKeyPrefix) + storeKey := AspectArrayKey(aspectID.Bytes(), key) + if len(value) == 0 { + prefixStore.Delete(storeKey) + } + prefixStore.Set(storeKey, value) +} + +// GetState returns the state of the aspect with the given ID and key. +func (s *stateStore) GetState(key []byte) []byte { + aspectID := s.ctx.AspectID + prefixStore := s.NewPrefixStore(V0AspectStateKeyPrefix) + storeKey := AspectArrayKey(aspectID.Bytes(), key) + return prefixStore.Get(storeKey) +} diff --git a/x/aspect/store/v1/account.go b/x/aspect/store/v1/account.go new file mode 100644 index 0000000..daff2ad --- /dev/null +++ b/x/aspect/store/v1/account.go @@ -0,0 +1,198 @@ +package v1 + +import ( + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/ethereum/go-ethereum/common" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + v0 "github.com/artela-network/artela-rollkit/x/aspect/store/v0" + "github.com/artela-network/artela-rollkit/x/aspect/types" + aspect "github.com/artela-network/aspect-core/types" +) + +var _ store.AccountStore = (*accountStore)(nil) + +type accountStore struct { + BaseStore + + ctx *types.AccountStoreContext +} + +// NewAccountStore creates a new instance of account store. +func NewAccountStore(ctx *types.AccountStoreContext) store.AccountStore { + var meter v0.GasMeter + if ctx.ChargeGas() { + meter = v0.NewGasMeter(ctx) + } else { + meter = v0.NewNoOpGasMeter(ctx) + } + + store := runtime.KVStoreAdapter(ctx.StoreService().OpenKVStore(ctx.CosmosContext())) + + return &accountStore{ + BaseStore: NewBaseStore(ctx.CosmosContext().Logger(), meter, store), + ctx: ctx, + } +} + +func (a *accountStore) LoadAccountBoundAspects(filter types.BindingFilter) ([]types.Binding, error) { + allBindings, err := a.getAllBindings() + if err != nil { + return nil, err + } + + var result []types.Binding + for _, binding := range allBindings { + if filter.JoinPoint != nil { + jp, ok := aspect.JoinPointRunType_value[string(*filter.JoinPoint)] + if !ok { + return nil, store.ErrInvalidJoinPoint + } + if (binding.JoinPoint | uint16(jp)) == 0 { + continue + } + + result = append(result, types.Binding(binding)) + } else if filter.VerifierOnly && aspect.CheckIsTxVerifier(int64(binding.JoinPoint)) { + result = append(result, types.Binding(binding)) + } else if filter.TxLevelOnly && aspect.CheckIsTransactionLevel(int64(binding.JoinPoint)) { + result = append(result, types.Binding(binding)) + } else { + result = append(result, types.Binding(binding)) + } + } + + return result, nil +} + +func (a *accountStore) StoreBinding(aspectID common.Address, version uint64, joinPoint uint64, priority int8, isCA bool) (err error) { + allBindings, err := a.getAllBindings() + if err != nil { + return err + } + + i64JP := int64(joinPoint) + isTxVerifier := aspect.CheckIsTxVerifier(i64JP) + isTxLevel := aspect.CheckIsTransactionLevel(i64JP) + + if !isTxLevel && !isTxVerifier { + return store.ErrNoJoinPoint + } + + if !isCA && !isTxVerifier { + return store.ErrBoundNonVerifierWithEOA + } + + if len(allBindings) >= maxAspectBoundLimit { + return store.ErrBindingLimitExceeded + } + + for _, binding := range allBindings { + if binding.Account == aspectID { + return store.ErrAlreadyBound + } + if isTxVerifier && isCA && aspect.CheckIsTxVerifier(int64(binding.JoinPoint)) { + // contract only allowed to bind 1 verifier + return store.ErrBindingLimitExceeded + } + } + + newBinding := Binding{ + Account: aspectID, + Version: version, + Priority: priority, + JoinPoint: uint16(joinPoint), + } + allBindings = append(allBindings, newBinding) + + key := store.NewKeyBuilder(V1AccountBindingKeyPrefix).AppendBytes(a.ctx.Account.Bytes()).Build() + bindingsBytes, err := Bindings(allBindings).MarshalText() + if err != nil { + return err + } + + return a.Store(key, bindingsBytes) +} + +func (a *accountStore) getAllBindings() ([]Binding, error) { + key := store.NewKeyBuilder(V1AccountBindingKeyPrefix).AppendBytes(a.ctx.Account.Bytes()).Build() + bindings, err := a.Load(key) + if err != nil { + return nil, err + } + + result := make([]Binding, 0, len(bindings)/32) + for i := 0; i < len(bindings); i += 32 { + data := bindings[i : i+32] + if common.Hash(data) == emptyHash { + // EOF + return result, nil + } + + var binding Binding + if err := binding.UnmarshalText(data); err != nil { + return nil, err + } + result = append(result, binding) + } + + return result, nil +} + +func (a *accountStore) RemoveBinding(aspectID common.Address, _ uint64, _ bool) error { + key := store.NewKeyBuilder(V1AccountBindingKeyPrefix).AppendBytes(a.ctx.Account.Bytes()).Build() + allBindings, err := a.getAllBindings() + if err != nil { + return err + } + + toDelete := -1 + for i, binding := range allBindings { + if binding.Account == aspectID { + toDelete = i + break + } + } + + if toDelete < 0 { + // if not bind, return nil + return nil + } + + allBindings = append(allBindings[:toDelete], allBindings[toDelete+1:]...) + bindingsBytes, err := Bindings(allBindings).MarshalText() + if err != nil { + return err + } + return a.Store(key, bindingsBytes) +} + +func (a *accountStore) Used() (bool, error) { + key := store.NewKeyBuilder(store.AspectProtocolInfoKeyPrefix).AppendBytes(a.ctx.Account.Bytes()).Build() + protocol, err := a.Load(key) + if err != nil { + return false, err + } + + var protocolVersion store.ProtocolVersion + if err := protocolVersion.UnmarshalText(protocol); err != nil { + return false, err + } + + return protocolVersion == store.ProtocolVersion(1), nil +} + +func (a *accountStore) MigrateFrom(old store.AccountStore) error { + //TODO implement me + panic("implement me") +} + +func (a *accountStore) Init() error { + versionBytes, err := protocolVersion.MarshalText() + if err != nil { + return err + } + + key := store.NewKeyBuilder(store.AspectProtocolInfoKeyPrefix).AppendBytes(a.ctx.Account.Bytes()).Build() + return a.Store(key, versionBytes) +} diff --git a/x/aspect/store/v1/base.go b/x/aspect/store/v1/base.go new file mode 100644 index 0000000..7f685b9 --- /dev/null +++ b/x/aspect/store/v1/base.go @@ -0,0 +1,102 @@ +package v1 + +import ( + "encoding/hex" + "math" + + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + + "github.com/artela-network/artela-rollkit/x/aspect/store" + v0 "github.com/artela-network/artela-rollkit/x/aspect/store/v0" +) + +const ( + maxAspectBoundLimit = math.MaxUint8 + protocolVersion = store.ProtocolVersion(1) +) + +// BaseStore defines a shared base store which can be implemented by all other stores +type BaseStore interface { + Load(key []byte) ([]byte, error) + Store(key, value []byte) error + Version() store.ProtocolVersion + + store.GasMeteredStore +} + +type baseStore struct { + gasMeter v0.GasMeter + kvStore storetypes.KVStore + logger log.Logger +} + +func NewBaseStore(logger log.Logger, gasMeter v0.GasMeter, kvStore storetypes.KVStore) BaseStore { + return &baseStore{ + gasMeter: gasMeter, + kvStore: kvStore, + logger: logger, + } +} + +// Version returns the protocol version of the Store. +func (s *baseStore) Version() store.ProtocolVersion { + return protocolVersion +} + +// Load loads the value from the given Store and do gas metering for the given operation +func (s *baseStore) Load(key []byte) ([]byte, error) { + if key == nil { + return nil, store.ErrInvalidStorageKey + } + + value := s.kvStore.Get(key) + + s.logger.Debug("load from aspect store", "key", abbreviateHex(key), "data", abbreviateHex(value)) + // gas metering after Load, since we are not like EVM, the data length is not known before Load + if err := s.gasMeter.MeasureStorageLoad(len(key) + len(value)); err != nil { + return nil, err + } + + // copy values to avoid unexpected modification + result := make([]byte, len(value)) + copy(result, value) + + return result, nil +} + +// Store stores the value to the given store and do gas metering for the given operation +func (s *baseStore) Store(key, value []byte) error { + if key == nil { + return store.ErrInvalidStorageKey + } + + if len(value) == 0 { + // if value is nil, we just delete the key, this will not charge gas + s.logger.Debug("deleting from aspect store", "key", abbreviateHex(key)) + s.kvStore.Delete(key) + } else { + if err := s.gasMeter.MeasureStorageStore(len(key) + len(value)); err != nil { + return err + } + + s.logger.Debug("saving to aspect store", "key", abbreviateHex(key), "data", abbreviateHex(value)) + s.kvStore.Set(key, value) + } + return nil +} + +func (s *baseStore) TransferGasFrom(store store.GasMeteredStore) { + s.gasMeter.UpdateGas(store.Gas()) +} + +func (s *baseStore) Gas() uint64 { + return s.gasMeter.RemainingGas() +} + +func abbreviateHex(data []byte) string { + if len(data) > 100 { + return hex.EncodeToString(data[:100]) + "..." + } + return hex.EncodeToString(data) +} diff --git a/x/aspect/store/v1/init.go b/x/aspect/store/v1/init.go new file mode 100644 index 0000000..1cab37c --- /dev/null +++ b/x/aspect/store/v1/init.go @@ -0,0 +1,9 @@ +package v1 + +import "github.com/artela-network/artela-rollkit/x/aspect/store" + +func init() { + store.RegisterAccountStore(1, NewAccountStore) + store.RegisterAspectMetaStore(1, NewAspectMetaStore) + store.RegisterAspectStateStore(1, NewStateStore) +} diff --git a/x/aspect/store/v1/keys.go b/x/aspect/store/v1/keys.go new file mode 100644 index 0000000..39088a0 --- /dev/null +++ b/x/aspect/store/v1/keys.go @@ -0,0 +1,21 @@ +package v1 + +import ( + "github.com/artela-network/artela-rollkit/x/aspect/store" +) + +// v1 keys, first 1 byte for scope, second 2 bytes for version, next 2 bytes for type +var ( + V1AspectMetaKeyPrefix = []byte{store.AspectScope, 0x00, 0x01, 0x00, 0x01} + V1AspectBindingKeyPrefix = []byte{store.AspectScope, 0x00, 0x01, 0x00, 0x02} + V1AspectCodeKeyPrefix = []byte{store.AspectScope, 0x00, 0x01, 0x00, 0x03} + V1AspectPropertiesKeyPrefix = []byte{store.AspectScope, 0x00, 0x01, 0x00, 0x04} + V1AspectStateKeyPrefix = []byte{store.AspectScope, 0x00, 0x01, 0x00, 0xff} + + V1AccountBindingKeyPrefix = []byte{store.AccountScope, 0x00, 0x01, 0x00, 0x01} +) + +var ( + V1AspectBindingFilterKeyPrefix = byte(0x01) + V1AspectBindingDataKeyPrefix = byte(0x02) +) diff --git a/x/aspect/store/v1/meta.go b/x/aspect/store/v1/meta.go new file mode 100644 index 0000000..a1ed606 --- /dev/null +++ b/x/aspect/store/v1/meta.go @@ -0,0 +1,850 @@ +package v1 + +import ( + "encoding/json" + "math" + "sort" + + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/ethereum/go-ethereum/common" + + cuckoo "github.com/artela-network/artela-rollkit/x/aspect/cuckoofilter" + "github.com/artela-network/artela-rollkit/x/aspect/store" + v0 "github.com/artela-network/artela-rollkit/x/aspect/store/v0" + "github.com/artela-network/artela-rollkit/x/aspect/types" +) + +var _ store.AspectMetaStore = (*metaStore)(nil) + +const ( + bindingSlotSize = 120 + bindingInfoLength = 32 + bindingDataLength = 8 + filterMaxSize = 2047 + filterActualLimit = filterMaxSize * 9 / 10 // assume load factor of filter is 90% + filterManagedSlots = filterActualLimit / bindingSlotSize + maxBindingSize = filterManagedSlots * math.MaxUint8 * bindingSlotSize +) + +type metaStore struct { + BaseStore + + ext *Extension + ctx *types.AspectStoreContext + + propertiesCache map[uint64]map[string][]byte +} + +// NewAspectMetaStore creates a new instance of aspect meta Store. +func NewAspectMetaStore(ctx *types.AspectStoreContext, protocolExtension []byte) store.AspectMetaStore { + var meter v0.GasMeter + if ctx.ChargeGas() { + meter = v0.NewGasMeter(ctx) + } else { + meter = v0.NewNoOpGasMeter(ctx) + } + + ext := new(Extension) + if err := ext.UnmarshalText(protocolExtension); err != nil { + panic(err) + } + + store := runtime.KVStoreAdapter(ctx.StoreService().OpenKVStore(ctx.CosmosContext())) + + return &metaStore{ + BaseStore: NewBaseStore(ctx.CosmosContext().Logger(), meter, store), + ctx: ctx, + ext: ext, + propertiesCache: make(map[uint64]map[string][]byte), + } +} + +func (m *metaStore) GetCode(version uint64) ([]byte, error) { + // key format {5B codePrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectCodeKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + return m.Load(key) +} + +func (m *metaStore) GetVersionMeta(version uint64) (*types.VersionMeta, error) { + // key format {5B metaPrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectMetaKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + raw, err := m.Load(key) + if err != nil { + return nil, err + } + + meta := new(VersionMeta) + if err := meta.UnmarshalText(raw); err != nil { + return nil, err + } + + return &types.VersionMeta{ + JoinPoint: meta.JoinPoint, + CodeHash: meta.CodeHash, + }, nil +} + +func (m *metaStore) GetMeta() (*types.AspectMeta, error) { + return &types.AspectMeta{ + PayMaster: m.ext.PayMaster, + Proof: m.ext.Proof, + }, nil +} + +func (m *metaStore) GetLatestVersion() (uint64, error) { + return m.ext.AspectVersion, nil +} + +func (m *metaStore) getProperties(version uint64) (properties map[string][]byte, err error) { + if _, ok := m.propertiesCache[version]; ok { + return m.propertiesCache[version], nil + } + + // key format {5B propertyPrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectPropertiesKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + allProps, err := m.Load(key) + if err != nil { + return nil, err + } + + defer func() { + if err == nil { + m.propertiesCache[version] = properties + } + }() + + if len(allProps) == 0 { + return make(map[string][]byte), nil + } + + propertiesArray := make([]types.Property, 0) + if err := json.Unmarshal(allProps, &propertiesArray); err != nil { + return nil, err + } + + properties = make(map[string][]byte, len(propertiesArray)) + for _, property := range propertiesArray { + properties[property.Key] = property.Value + } + + return properties, nil +} + +func (m *metaStore) GetProperty(version uint64, propKey string) ([]byte, error) { + if version == 0 { + // for non-exist version property, return nil + return nil, nil + } + + allProps, err := m.getProperties(version) + if err != nil { + return nil, err + } + + return allProps[propKey], nil +} + +func (m *metaStore) BumpVersion() (ver uint64, err error) { + key := store.NewKeyBuilder(store.AspectProtocolInfoKeyPrefix).AppendBytes(m.ctx.AspectID.Bytes()).Build() + raw, err := m.Load(key) + if err != nil { + return 0, err + } + + m.ext.AspectVersion += 1 + defer func() { + if err != nil { + // if failed, rollback the version + m.ext.AspectVersion -= 1 + } + }() + + marshaled, err := m.ext.MarshalText() + if err != nil { + return 0, err + } + + extensionOffset := store.ProtocolInfoLen + store.ProtocolVersionLen + result := make([]byte, 0, len(raw)) + result = append(result, raw[:extensionOffset]...) + result = append(result, marshaled...) + + return m.ext.AspectVersion, m.Store(key, result) +} + +func (m *metaStore) StoreVersionMeta(version uint64, meta *types.VersionMeta) error { + // key format {5B metaPrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectMetaKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + + marshaled, err := VersionMeta(*meta).MarshalText() + if err != nil { + return err + } + + return m.Store(key, marshaled) +} + +func (m *metaStore) StoreMeta(meta *types.AspectMeta) (err error) { + oldPayMaster := m.ext.PayMaster + oldProof := m.ext.Proof + + m.ext.PayMaster = meta.PayMaster + m.ext.Proof = meta.Proof + + defer func() { + // rollback if failed + if err != nil { + m.ext.PayMaster = oldPayMaster + m.ext.Proof = oldProof + } + }() + + marshaled, err := m.ext.MarshalText() + if err != nil { + return err + } + + key := store.NewKeyBuilder(store.AspectProtocolInfoKeyPrefix).AppendBytes(m.ctx.AspectID.Bytes()).Build() + raw, err := m.Load(key) + if err != nil { + return err + } + + extensionOffset := store.ProtocolInfoLen + store.ProtocolVersionLen + result := make([]byte, 0, len(raw)) + result = append(result, raw[:extensionOffset]...) + result = append(result, marshaled...) + + return m.Store(key, result) +} + +func (m *metaStore) StoreCode(version uint64, code []byte) error { + // key format {5B codePrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectCodeKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + return m.Store(key, code) +} + +func (m *metaStore) StoreProperties(version uint64, properties []types.Property) (err error) { + // for version > 1 (upgrade case), we need to load all previous properties and append the new ones + if version > 1 { + oldVersionProperties, err := m.getProperties(version - 1) + if err != nil { + return err + } + + keySet := make(map[string]int, len(properties)) + for i, prop := range properties { + keySet[prop.Key] = i + } + + for key, value := range oldVersionProperties { + if _, ok := keySet[key]; ok { + // for exiting one, ignore the old value + continue + } + + // for non-existing one, we need to append it + properties = append(properties, types.Property{ + Key: key, + Value: value, + }) + } + } + + // check limits + if len(properties) > types.AspectPropertyLimit { + return store.ErrTooManyProperties + } + + // sort the slice lexicographically + sort.Slice(properties, func(i, j int) bool { + return properties[i].Key < properties[j].Key + }) + + // key format {5B propertyPrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectPropertiesKeyPrefix). + AppendUint64(version). + AppendBytes(m.ctx.AspectID.Bytes()). + Build() + + bytes, err := json.Marshal(properties) + if err != nil { + return store.ErrSerdeFail + } + + defer func() { + if err == nil { + m.propertiesCache[version] = make(map[string][]byte, len(properties)) + for _, prop := range properties { + m.propertiesCache[version][prop.Key] = prop.Value + } + } + }() + + return m.Store(key, bytes) +} + +func (m *metaStore) StoreBinding(account common.Address, version uint64, joinPoint uint64, priority int8) (err error) { + // bindingKey format {5B codePrefix}{8B version}{20B aspectID} + bindingKey := store.NewKeyBuilder(V1AspectBindingKeyPrefix). + AppendBytes(m.ctx.AspectID.Bytes()) + + // load first slot + bindingSlotKey := bindingKey.AppendByte(V1AspectBindingDataKeyPrefix) + firstSlotKey := bindingSlotKey.AppendUint64(0).Build() + firstSlot, err := m.Load(firstSlotKey) + if err != nil { + return err + } + + // marshal binding info + newBinding := Binding{ + Account: account, + Version: version, + Priority: priority, + JoinPoint: uint16(joinPoint), + } + newBindingBytes, err := newBinding.MarshalText() + if err != nil { + return err + } + + var length DataLength + if err := length.UnmarshalText(firstSlot); err != nil { + return err + } + + // check max binding amount, an aspect can bind with at most 459000 accounts + if length >= maxBindingSize { + return store.ErrBindingLimitExceeded + } + + filterKey := bindingKey.AppendByte(V1AspectBindingFilterKeyPrefix) + if length == 0 { + // first time this aspect is bound + // use cuckoo filter instead of bloom, since cuckoo also support delete, + // we use a separate slot to store the filters, + // each filter will manage 28 slots, which should be enough for a long time. + + // first time this aspect is bound + filter := cuckoo.NewFilter(filterMaxSize) + // insert {aspectId}:{filterManagedSlotOffset 0-27} into cuckoo filter + // each filter will manage 28 binding slots + filter.Insert(store.NewKeyBuilder(account.Bytes()).AppendUint8(0).Build()) + filterData := filter.Encode() + // save filter + if err := m.Store(filterKey.AppendUint8(0).Build(), filterData); err != nil { + return err + } + // save binding data + length := DataLength(1) + lengthBytes, err := length.MarshalText() + if err != nil { + return err + } + + // store binding data + if err := m.Store(firstSlotKey, append(lengthBytes, newBindingBytes...)); err != nil { + return err + } + + return nil + } + + lastSlot := uint64(length / bindingSlotSize) + lastFilterSlot := uint8(lastSlot / filterManagedSlots) + + var lastFilter *cuckoo.Filter + // first use filter to check whether the account is already bound + for i := uint8(0); i <= lastFilterSlot; i++ { + key := filterKey.AppendUint8(i).Build() + filterData, err := m.Load(key) + if err != nil { + return err + } + if len(filterData) == 0 { + // reached the end of the filter + break + } + + filter, err := cuckoo.Decode(filterData) + if err != nil { + return err + } + + // cache the last filter + if i == lastFilterSlot { + lastFilter = filter + } + + accountKey := store.NewKeyBuilder(account.Bytes()) + + // if total slot is less than managed, just test all slots, otherwise test managed + slotsToTest := uint8(filterManagedSlots) + if filterManagedSlots > lastSlot { + slotsToTest = uint8(lastSlot + 1) + } + + // check aspect is already bound + for j := uint8(0); j < slotsToTest; j++ { + if !filter.Lookup(accountKey.AppendUint8(j).Build()) { + // filter test fail, continue searching + continue + } + + // filter test succeeded, double check with the actual data + var bindingDataInSlot []byte + if i == 0 && j == 0 { + // since we have already loaded the first slot, no need to load it again + bindingDataInSlot = firstSlot[bindingDataLength:] + } else { + slotIndex := uint64(i)*filterManagedSlots + uint64(j) + bindingDataInSlot, err = m.Load(bindingSlotKey.AppendUint64(slotIndex).Build()) + if err != nil { + return err + } + } + for k := 0; k < len(bindingDataInSlot); k += bindingInfoLength { + data := bindingDataInSlot[k : k+bindingInfoLength] + var binding Binding + if err := binding.UnmarshalText(data); err != nil { + return err + } + if binding.Account == account { + return store.ErrAlreadyBound + } + } + } + } + + // check if the last slot is full + if length%bindingSlotSize == 0 { + // last slot is full, check if we need create a new filter + if lastSlot%filterManagedSlots == 0 { + // create a new filter + filter := cuckoo.NewFilter(filterMaxSize) + // insert {aspectId}:{filterManagedSlotOffset 0-27} into cuckoo filter + // each filter will manage 28 binding slots + filter.Insert(store.NewKeyBuilder(account.Bytes()).AppendUint8(0).Build()) + filterData := filter.Encode() + // save filter + if err := m.Store(filterKey.AppendUint8(lastFilterSlot).Build(), filterData); err != nil { + return err + } + } else { + // update filter data + lastFilterKey := filterKey.AppendUint8(lastFilterSlot).Build() + if lastFilter == nil { + // if last filter is not loaded for some reason, load and decode + filterData, err := m.Load(lastFilterKey) + if err != nil { + return err + } + + lastFilter, err = cuckoo.Decode(filterData) + if err != nil { + return err + } + } + lastFilter.Insert(store.NewKeyBuilder(account.Bytes()).AppendUint8(uint8(lastSlot % filterManagedSlots)).Build()) + filterData := lastFilter.Encode() + if err := m.Store(lastFilterKey, filterData); err != nil { + return err + } + } + // create a new slot + newSlotKey := bindingSlotKey.AppendUint64(lastSlot).Build() + if err := m.Store(newSlotKey, newBindingBytes); err != nil { + return err + } + } else { + // slot is not full, update the slot and filter directly + // update filter data + lastFilterKey := filterKey.AppendUint8(lastFilterSlot).Build() + if lastFilter == nil { + // if last filter is not loaded for some reason, load and decode + filterData, err := m.Load(lastFilterKey) + if err != nil { + return err + } + + lastFilter, err = cuckoo.Decode(filterData) + if err != nil { + return err + } + } + lastFilter.Insert(store.NewKeyBuilder(account.Bytes()).AppendUint8(uint8(lastSlot % filterManagedSlots)).Build()) + filterData := lastFilter.Encode() + if err := m.Store(lastFilterKey, filterData); err != nil { + return err + } + + // update the slot data + if lastSlot == 0 { + // since we have already loaded the first slot, no need to load it again + // just update the first slot data + firstSlot = append(firstSlot, newBindingBytes...) + } else { + // otherwise we need to load the last slot data + lastSlotKey := bindingSlotKey.AppendUint64(lastSlot).Build() + lastSlotData, err := m.Load(lastSlotKey) + if err != nil { + return err + } + + // append the new binding to the last slot and save it + lastSlotData = append(lastSlotData, newBindingBytes...) + if err := m.Store(lastSlotKey, lastSlotData); err != nil { + return err + } + } + } + + // update length + length++ + lengthBytes, err := length.MarshalText() + if err != nil { + return err + } + + // overwrite the length in first slot + copy(firstSlot, lengthBytes) + // update first slot + return m.Store(firstSlotKey, firstSlot) +} + +func (m *metaStore) LoadAspectBoundAccounts() ([]types.Binding, error) { + // key format {5B codePrefix}{8B version}{20B aspectID} + key := store.NewKeyBuilder(V1AspectBindingKeyPrefix). + AppendBytes(m.ctx.AspectID.Bytes()).AppendByte(V1AspectBindingDataKeyPrefix) + + firstSlot, err := m.Load(key.AppendUint64(0).Build()) + if err != nil { + return nil, err + } + + var length DataLength + if err := length.UnmarshalText(firstSlot); err != nil { + return nil, err + } + + // binding format for first slot {8B Length}{256B Bloom}{32B Binding}{32B Binding}... + // each slot will save maximum 120 binding info, which is 3840 bytes + bindingData := firstSlot[bindingDataLength:] + bindings := make([]types.Binding, 0, length) + for i := uint64(0); i < uint64(length); i += bindingSlotSize { + for j := 0; j < len(bindingData); j += bindingInfoLength { + data := bindingData[j : j+bindingInfoLength] + var binding Binding + if err := binding.UnmarshalText(data); err != nil { + return nil, err + } + bindings = append(bindings, types.Binding(binding)) + if uint64(len(bindings)) == uint64(length) { + // EOF + return bindings, nil + } + } + + // load next slot + bindingData, err = m.Load(key.AppendUint64((i / bindingSlotSize) + 1).Build()) + if err != nil { + return nil, err + } + } + + return bindings, nil +} + +func (m *metaStore) RemoveBinding(account common.Address) (err error) { + // bindingKey format {5B codePrefix}{8B version}{20B aspectID} + bindingKey := store.NewKeyBuilder(V1AspectBindingKeyPrefix). + AppendBytes(m.ctx.AspectID.Bytes()) + + // load first slot + bindingSlotKey := bindingKey.AppendByte(V1AspectBindingDataKeyPrefix) + firstSlotKey := bindingSlotKey.AppendUint64(0).Build() + firstSlot, err := m.Load(firstSlotKey) + if err != nil { + return err + } + + var length DataLength + if err := length.UnmarshalText(firstSlot); err != nil { + return err + } + + if length == 0 { + // if not bound, just pass + return nil + } + + lastSlot := uint64(length / bindingSlotSize) + if length%bindingSlotSize == 0 { + lastSlot = lastSlot - 1 + } + lastFilterSlot := uint8(lastSlot / filterManagedSlots) + + var ( + lastFilter *cuckoo.Filter + bindingFilter *cuckoo.Filter + bindingSlot *uint64 + bindingSlotData []byte + bindingSlotOffset *int + ) + // first use filter to check whether the account is already bound + filterKey := bindingKey.AppendByte(V1AspectBindingFilterKeyPrefix) + for i := uint8(0); i <= lastFilterSlot; i++ { + key := filterKey.AppendUint8(i).Build() + filterData, err := m.Load(key) + if err != nil { + return err + } + if len(filterData) == 0 { + // reached last filter + break + } + + filter, err := cuckoo.Decode(filterData) + if err != nil { + return err + } + + // cache the last filter + if i == lastFilterSlot { + lastFilter = filter + } + + accountKey := store.NewKeyBuilder(account.Bytes()) + for j := uint8(0); j < filterManagedSlots; j++ { + if !filter.Lookup(accountKey.AppendUint8(j).Build()) { + // filter test fail, continue searching + continue + } + + // filter test succeeded, double check with the actual data + var bindingDataInSlot []byte + slotIndex := uint64(0) + if i == 0 && j == 0 { + // since we have already loaded the first slot, no need to load it again + bindingDataInSlot = firstSlot[bindingDataLength:] + } else { + slotIndex = uint64(i)*filterManagedSlots + uint64(j) + bindingDataInSlot, err = m.Load(bindingSlotKey.AppendUint64(slotIndex).Build()) + if err != nil { + return err + } + } + // search in the slot + for k := 0; k < len(bindingDataInSlot); k += bindingInfoLength { + data := bindingDataInSlot[k : k+bindingInfoLength] + var binding Binding + if err := binding.UnmarshalText(data); err != nil { + return err + } + if binding.Account == account { + // found binding, record position and break out the loops + bindingSlotData = bindingDataInSlot + bindingSlotOffset = &k + bindingSlot = &slotIndex + bindingFilter = filter + goto BindingFound + } + } + } + } + +BindingFound: + if bindingSlotData == nil || bindingSlot == nil || bindingFilter == nil || bindingSlotOffset == nil { + // if not bound, just pass + return nil + } + + // remove the binding from the slot + if *bindingSlot == lastSlot { + // only first slot used, or binding in last slot, we can just remove the binding from the slot + if len(bindingSlotData) > bindingInfoLength { + copy(bindingSlotData[*bindingSlotOffset:], bindingSlotData[*bindingSlotOffset+bindingInfoLength:]) + } + bindingSlotData = bindingSlotData[:len(bindingSlotData)-bindingInfoLength] + if *bindingSlot > 0 { + // if not the first slot we just save the data + if err := m.Store(bindingSlotKey.AppendUint64(*bindingSlot).Build(), bindingSlotData); err != nil { + return err + } + } else { + // for the first slot we just need update the first slot data + firstSlot = append(firstSlot[:bindingDataLength], bindingSlotData...) + } + + // remove the account from the filter, and update filter + filterSlot := uint8(*bindingSlot / filterManagedSlots) + bindingFilter.Delete(store.NewKeyBuilder(account.Bytes()).AppendUint8(filterSlot).Build()) + // if there is nothing in the filter, delete it + var updatedFilter []byte + if bindingFilter.Count() > 0 { + // otherwise we update it + updatedFilter = bindingFilter.Encode() + } + + if err := m.Store(filterKey.AppendUint8(filterSlot).Build(), updatedFilter); err != nil { + return err + } + } else if lastSlot > *bindingSlot { + // move the last binding to the removed position + lastSlotKey := bindingSlotKey.AppendUint64(lastSlot).Build() + lastSlotData, err := m.Load(lastSlotKey) + if err != nil { + return err + } + lastBindingBytes := lastSlotData[len(lastSlotData)-bindingInfoLength:] + + // replace delete binding with the last binding + copy(bindingSlotData[*bindingSlotOffset:], lastBindingBytes) + lastSlotData = lastSlotData[:len(lastSlotData)-bindingInfoLength] + + // update last slot + if err := m.Store(lastSlotKey, lastSlotData); err != nil { + return err + } + + // update the updated slot + if *bindingSlot == 0 { + // for the first slot we just need to copy over the data + copy(firstSlot[bindingDataLength:], bindingSlotData) + } else { + // for other slots we need to save it first + if err := m.Store(bindingSlotKey.AppendUint64(*bindingSlot).Build(), bindingSlotData); err != nil { + return err + } + } + + // load the filter if needed + if lastFilter == nil { + // if last filter is not loaded for some reason, load and decode + filterData, err := m.Load(filterKey.AppendUint8(lastFilterSlot).Build()) + if err != nil { + return err + } + lastFilter, err = cuckoo.Decode(filterData) + if err != nil { + return err + } + } + + lastBinding := new(Binding) + if err := lastBinding.UnmarshalText(lastBindingBytes); err != nil { + return err + } + + // remove the binding from the filters + if lastSlot/filterManagedSlots == *bindingSlot/filterManagedSlots { + bindingFilterOffsetKey := uint8(*bindingSlot % filterManagedSlots) + lastFilterOffsetKey := uint8(lastSlot % filterManagedSlots) + // need to remove both last binding and the unbound one from their old position + // and add last one to the new position + lastFilter.Delete(store.NewKeyBuilder(account.Bytes()).AppendUint8(bindingFilterOffsetKey).Build()) + lastFilter.Delete(store.NewKeyBuilder(lastBinding.Account.Bytes()).AppendUint8(lastFilterOffsetKey).Build()) + lastFilter.Insert(store.NewKeyBuilder(lastBinding.Account.Bytes()).AppendUint8(bindingFilterOffsetKey).Build()) + + // update last filter + if err := m.Store(filterKey.AppendUint8(lastFilterSlot).Build(), lastFilter.Encode()); err != nil { + return err + } + } else { + // if the last slot and the binding slot are in different filters, we need to update both filters + // remove the moved binding account from the last slot filter, and update filter + lastFilterOffsetKey := uint8(lastSlot % filterManagedSlots) + lastFilter.Delete(store.NewKeyBuilder(lastBinding.Account.Bytes()).AppendUint8(lastFilterOffsetKey).Build()) + var updatedFilter []byte + if lastFilter.Count() > 0 { + updatedFilter = lastFilter.Encode() + } + if err := m.Store(filterKey.AppendUint8(lastFilterSlot).Build(), updatedFilter); err != nil { + return err + } + + // remove the account from the binding slot filter, and update filter + bindingFilterOffset := uint8(*bindingSlot % filterManagedSlots) + bindingFilter.Delete(store.NewKeyBuilder(account.Bytes()).AppendUint8(bindingFilterOffset).Build()) + bindingFilter.Insert(store.NewKeyBuilder(lastBinding.Account.Bytes()).AppendUint8(bindingFilterOffset).Build()) + if err := m.Store(filterKey.AppendUint8(uint8(*bindingSlot/filterManagedSlots)).Build(), bindingFilter.Encode()); err != nil { + return err + } + } + } else { + // should not happen + return store.ErrStorageCorrupted + } + + // update length + length-- + lengthBytes, err := length.MarshalText() + if err != nil { + return err + } + + // overwrite the length in first slot + copy(firstSlot, lengthBytes) + // update first slot + return m.Store(firstSlotKey, firstSlot) +} + +func (m *metaStore) MigrateFrom(old store.AspectMetaStore) error { + //TODO implement me + panic("implement me") +} + +func (m *metaStore) Used() (bool, error) { + return m.ext.AspectVersion > 0, nil +} + +func (m *metaStore) Init() error { + versionBytes, err := protocolVersion.MarshalText() + if err != nil { + return err + } + + info := &store.AspectInfo{ + MetaVersion: protocolVersion, + StateVersion: protocolVersion, + } + + infoBytes, err := info.MarshalText() + if err != nil { + return err + } + + extension := &Extension{ + AspectVersion: 0, + PayMaster: common.Address{}, + Proof: nil, + } + extBytes, err := extension.MarshalText() + if err != nil { + return err + } + + key := store.NewKeyBuilder(store.AspectProtocolInfoKeyPrefix).AppendBytes(m.ctx.AspectID.Bytes()).Build() + result := make([]byte, 0, len(versionBytes)+len(infoBytes)+len(extBytes)) + result = append(result, versionBytes...) + result = append(result, infoBytes...) + result = append(result, extBytes...) + + return m.Store(key, result) +} diff --git a/x/aspect/store/v1/models.go b/x/aspect/store/v1/models.go new file mode 100644 index 0000000..e1d63cd --- /dev/null +++ b/x/aspect/store/v1/models.go @@ -0,0 +1,147 @@ +package v1 + +import ( + "encoding/binary" + + "github.com/ethereum/go-ethereum/common" + + "github.com/artela-network/artela-rollkit/x/aspect/store" +) + +var emptyHash = common.Hash{} + +type DataLength uint64 + +func (l *DataLength) UnmarshalText(text []byte) error { + if len(text) < 8 { + *l = 0 + } else { + *l = DataLength(binary.BigEndian.Uint64(text[:8])) + } + return nil +} + +func (l DataLength) MarshalText() (text []byte, err error) { + result := make([]byte, 8) + binary.BigEndian.PutUint64(result, uint64(l)) + return result, nil +} + +type Bindings []Binding + +func (b *Bindings) UnmarshalText(text []byte) error { + if len(text)%32 != 0 { + return store.ErrInvalidBinding + } + for i := 0; i < len(text); i += 32 { + data := text[i : i+32] + if common.Hash(data) == emptyHash { + // EOF + return nil + } + + var binding Binding + if err := binding.UnmarshalText(data); err != nil { + return err + } + *b = append(*b, binding) + } + return nil +} + +func (b Bindings) MarshalText() (text []byte, err error) { + result := make([]byte, 0, len(b)*32) + for _, binding := range b { + marshaled, err := binding.MarshalText() + if err != nil { + return nil, err + } + result = append(result, marshaled...) + } + return result, nil +} + +type Binding struct { + Account common.Address + Version uint64 + Priority int8 + JoinPoint uint16 +} + +func (b *Binding) UnmarshalText(text []byte) error { + if len(text) < 32 { + return store.ErrInvalidBinding + } + b.Account.SetBytes(text[:20]) + b.Version = binary.BigEndian.Uint64(text[20:28]) + b.Priority = int8(text[28]) + b.JoinPoint = binary.BigEndian.Uint16(text[29:31]) + // last byte is reserved for future use + return nil +} + +func (b Binding) MarshalText() (text []byte, err error) { + result := make([]byte, 32) + copy(result[:20], b.Account.Bytes()) + binary.BigEndian.PutUint64(result[20:28], b.Version) + result[28] = byte(b.Priority) + binary.BigEndian.PutUint16(result[29:31], b.JoinPoint) + // last byte is reserved for future use + return result, nil +} + +type Extension struct { + AspectVersion uint64 + PayMaster common.Address + Proof []byte +} + +func (e *Extension) UnmarshalText(text []byte) error { + if len(text) == 0 { + // not inited + return nil + } + if len(text) < 36 { + return store.ErrInvalidExtension + } + e.AspectVersion = binary.BigEndian.Uint64(text[:8]) + e.PayMaster.SetBytes(text[8:28]) + proofLen := binary.BigEndian.Uint64(text[28:36]) + if uint64(len(text)) != 36+proofLen { + return store.ErrInvalidExtension + } + e.Proof = make([]byte, proofLen) + copy(e.Proof, text[36:]) + return nil +} + +func (e Extension) MarshalText() (text []byte, err error) { + result := make([]byte, 8+20+8+len(e.Proof)) + binary.BigEndian.PutUint64(result[:8], e.AspectVersion) + copy(result[8:28], e.PayMaster.Bytes()) + binary.BigEndian.PutUint64(result[28:36], uint64(len(e.Proof))) + copy(result[36:], e.Proof) + return result, nil +} + +// VersionMeta is the data model for holding the metadata of a specific version of aspect +type VersionMeta struct { + JoinPoint uint64 + CodeHash common.Hash +} + +func (v *VersionMeta) UnmarshalText(text []byte) error { + if len(text) < 40 { + return store.ErrInvalidVersionMeta + } + v.JoinPoint = binary.BigEndian.Uint64(text[:8]) + v.CodeHash.SetBytes(text[8:40]) + return nil +} + +func (v VersionMeta) MarshalText() (text []byte, err error) { + result := make([]byte, 40) + binary.BigEndian.PutUint64(result[:8], v.JoinPoint) + copy(result[8:], v.CodeHash.Bytes()) + return result, nil +} diff --git a/x/aspect/store/v1/state.go b/x/aspect/store/v1/state.go new file mode 100644 index 0000000..d1a349a --- /dev/null +++ b/x/aspect/store/v1/state.go @@ -0,0 +1,49 @@ +package v1 + +import ( + "github.com/artela-network/artela-rollkit/x/aspect/store" + v0 "github.com/artela-network/artela-rollkit/x/aspect/store/v0" + "github.com/artela-network/artela-rollkit/x/aspect/types" + "github.com/cosmos/cosmos-sdk/runtime" +) + +var _ store.AspectStateStore = (*stateStore)(nil) + +// stateStore is the version 1 state Store +type stateStore struct { + BaseStore + + ctx *types.AspectStoreContext +} + +// NewStateStore creates a new instance of account state. +func NewStateStore(ctx *types.AspectStoreContext) store.AspectStateStore { + // for state Store, we have already charged gas in host api, + // so no need to charge it again in the Store + store := runtime.KVStoreAdapter(ctx.StoreService().OpenKVStore(ctx.CosmosContext())) + + return &stateStore{ + BaseStore: NewBaseStore(ctx.CosmosContext().Logger(), v0.NewNoOpGasMeter(ctx), store), + ctx: ctx, + } +} + +// SetState sets the state of the aspect with the given ID and key. +func (s *stateStore) SetState(key []byte, value []byte) { + aspectID := s.ctx.AspectID + stateKey := store.NewKeyBuilder(V1AspectStateKeyPrefix).AppendBytes(aspectID.Bytes()).AppendBytes(key).Build() + // no need to check error here, since we are using noop gas meter in state store + _ = s.Store(stateKey, value) + s.ctx.Logger().Debug("set aspect state", "key", string(key), "value", abbreviateHex(value)) + return +} + +// GetState returns the state of the aspect with the given ID and key. +func (s *stateStore) GetState(key []byte) []byte { + aspectID := s.ctx.AspectID + stateKey := store.NewKeyBuilder(V1AspectStateKeyPrefix).AppendBytes(aspectID.Bytes()).AppendBytes(key).Build() + // no need to check error here, since we are using noop gas meter in state store + data, _ := s.Load(stateKey) + s.ctx.Logger().Debug("get aspect state", "key", string(key), "value", abbreviateHex(data)) + return data +} diff --git a/x/aspect/types/codec.go b/x/aspect/types/codec.go new file mode 100644 index 0000000..ac55263 --- /dev/null +++ b/x/aspect/types/codec.go @@ -0,0 +1,17 @@ +package types + +import ( + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + // this line is used by starport scaffolding # 1 +) + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + // this line is used by starport scaffolding # 3 + + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} diff --git a/x/aspect/types/constants.go b/x/aspect/types/constants.go new file mode 100644 index 0000000..ee97c61 --- /dev/null +++ b/x/aspect/types/constants.go @@ -0,0 +1,8 @@ +package types + +import "math" + +const ( + // AspectPropertyLimit is the maximum number of properties that can be set on an aspect + AspectPropertyLimit = math.MaxUint8 +) diff --git a/x/aspect/types/context.go b/x/aspect/types/context.go new file mode 100644 index 0000000..164845d --- /dev/null +++ b/x/aspect/types/context.go @@ -0,0 +1,120 @@ +package types + +import ( + cstore "cosmossdk.io/core/store" + "cosmossdk.io/log" + "github.com/artela-network/artela-evm/vm" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +type storeContext struct { + cosmosCtx sdk.Context + evmStoreService cstore.KVStoreService + storeService cstore.KVStoreService + gas uint64 + + chargeGas bool +} + +func (s *storeContext) clone() StoreContext { + return &storeContext{ + cosmosCtx: s.cosmosCtx, + evmStoreService: s.evmStoreService, + storeService: s.storeService, + gas: s.gas, + } +} + +func (s *storeContext) Logger() log.Logger { + return s.cosmosCtx.Logger() +} + +func (s *storeContext) CosmosContext() sdk.Context { + return s.cosmosCtx +} + +func (s *storeContext) EVMStoreService() cstore.KVStoreService { + return s.evmStoreService +} + +func (s *storeContext) StoreService() cstore.KVStoreService { + return s.storeService +} + +func (s *storeContext) Gas() uint64 { + return s.gas +} + +func (s *storeContext) UpdateGas(gas uint64) { + s.gas = gas +} + +func (s *storeContext) ChargeGas() bool { + return s.chargeGas +} + +func (s *storeContext) ConsumeGas(gas uint64) error { + if s.gas < gas { + s.gas = 0 + return vm.ErrOutOfGas + } + s.gas -= gas + return nil +} + +type StoreContext interface { + CosmosContext() sdk.Context + StoreService() cstore.KVStoreService + EVMStoreService() cstore.KVStoreService + Gas() uint64 + ConsumeGas(gas uint64) error + UpdateGas(gas uint64) + Logger() log.Logger + ChargeGas() bool + + clone() StoreContext +} + +func NewStoreContext(ctx sdk.Context, evmStoreService, storeService cstore.KVStoreService, gas uint64) StoreContext { + return &storeContext{ + cosmosCtx: ctx, + evmStoreService: evmStoreService, + storeService: storeService, + gas: gas, + chargeGas: true, + } +} + +func NewGasFreeStoreContext(ctx sdk.Context, evmStoreService, storeService cstore.KVStoreService) StoreContext { + return &storeContext{ + cosmosCtx: ctx, + evmStoreService: evmStoreService, + storeService: storeService, + chargeGas: false, + } +} + +type AccountStoreContext struct { + StoreContext + Account common.Address +} + +func (a *AccountStoreContext) Clone() AccountStoreContext { + return AccountStoreContext{ + StoreContext: a.StoreContext.clone(), + Account: a.Account, + } +} + +type AspectStoreContext struct { + StoreContext + AspectID common.Address +} + +func (a *AspectStoreContext) Clone() AspectStoreContext { + return AspectStoreContext{ + StoreContext: a.StoreContext.clone(), + AspectID: a.AspectID, + } +} diff --git a/x/aspect/types/errors.go b/x/aspect/types/errors.go new file mode 100644 index 0000000..edc2b31 --- /dev/null +++ b/x/aspect/types/errors.go @@ -0,0 +1,13 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "cosmossdk.io/errors" +) + +// x/aspect module sentinel errors +var ( + ErrInvalidSigner = sdkerrors.Register(ModuleName, 1100, "expected gov account as only signer for proposal message") + ErrSample = sdkerrors.Register(ModuleName, 1101, "sample error") +) diff --git a/x/aspect/types/expected_keepers.go b/x/aspect/types/expected_keepers.go new file mode 100644 index 0000000..4a50d01 --- /dev/null +++ b/x/aspect/types/expected_keepers.go @@ -0,0 +1,25 @@ +package types + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AccountKeeper defines the expected interface for the Account module. +type AccountKeeper interface { + GetAccount(context.Context, sdk.AccAddress) sdk.AccountI // only used for simulation + // Methods imported from account should be defined here +} + +// BankKeeper defines the expected interface for the Bank module. +type BankKeeper interface { + SpendableCoins(context.Context, sdk.AccAddress) sdk.Coins + // Methods imported from bank should be defined here +} + +// ParamSubspace defines the expected Subspace interface for parameters. +type ParamSubspace interface { + Get(context.Context, []byte, interface{}) + Set(context.Context, []byte, interface{}) +} diff --git a/x/aspect/types/genesis.go b/x/aspect/types/genesis.go new file mode 100644 index 0000000..2c15cd9 --- /dev/null +++ b/x/aspect/types/genesis.go @@ -0,0 +1,22 @@ +package types + +// this line is used by starport scaffolding # genesis/types/import + +// DefaultIndex is the default global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + // this line is used by starport scaffolding # genesis/types/default + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // this line is used by starport scaffolding # genesis/types/validate + + return gs.Params.Validate() +} diff --git a/x/aspect/types/genesis.pb.go b/x/aspect/types/genesis.pb.go new file mode 100644 index 0000000..2af7366 --- /dev/null +++ b/x/aspect/types/genesis.pb.go @@ -0,0 +1,324 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/aspect/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the aspect module's genesis state. +type GenesisState struct { + // params defines all the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_98b1181485b8347d, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "artela.aspect.GenesisState") +} + +func init() { proto.RegisterFile("artela/aspect/genesis.proto", fileDescriptor_98b1181485b8347d) } + +var fileDescriptor_98b1181485b8347d = []byte{ + // 216 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0x2c, 0x2a, 0x49, + 0xcd, 0x49, 0xd4, 0x4f, 0x2c, 0x2e, 0x48, 0x4d, 0x2e, 0xd1, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, + 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x85, 0x48, 0xea, 0x41, 0x24, 0xa5, 0x04, + 0x13, 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1, 0x24, 0x44, 0x85, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, + 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x45, 0xa5, 0x50, 0x0d, 0x2d, 0x48, 0x2c, 0x4a, 0xcc, 0x85, 0x9a, + 0xa9, 0xe4, 0xc1, 0xc5, 0xe3, 0x0e, 0xb1, 0x24, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x82, 0x8b, + 0x0d, 0x22, 0x2f, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xaa, 0x87, 0x62, 0xa9, 0x5e, 0x00, + 0x58, 0xd2, 0x89, 0xf3, 0xc4, 0x3d, 0x79, 0x86, 0x15, 0xcf, 0x37, 0x68, 0x31, 0x06, 0x41, 0xd5, + 0x3b, 0x05, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, + 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x79, 0x7a, 0x66, + 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xc4, 0x34, 0xdd, 0xbc, 0xd4, 0x92, 0xf2, + 0xfc, 0xa2, 0x6c, 0x18, 0xb7, 0x28, 0x3f, 0x27, 0x27, 0x3b, 0xb3, 0x44, 0xbf, 0x02, 0xe6, 0xc6, + 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x1b, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xad, 0xc6, 0x7b, 0xae, 0x16, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/aspect/types/genesis_test.go b/x/aspect/types/genesis_test.go new file mode 100644 index 0000000..0d455de --- /dev/null +++ b/x/aspect/types/genesis_test.go @@ -0,0 +1,41 @@ +package types_test + +import ( + "testing" + + "github.com/artela-network/artela-rollkit/x/aspect/types" + "github.com/stretchr/testify/require" +) + +func TestGenesisState_Validate(t *testing.T) { + tests := []struct { + desc string + genState *types.GenesisState + valid bool + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + valid: true, + }, + { + desc: "valid genesis state", + genState: &types.GenesisState{ + + // this line is used by starport scaffolding # types/genesis/validField + }, + valid: true, + }, + // this line is used by starport scaffolding # types/genesis/testcase + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/aspect/types/keys.go b/x/aspect/types/keys.go new file mode 100644 index 0000000..363f40d --- /dev/null +++ b/x/aspect/types/keys.go @@ -0,0 +1,20 @@ +package types + +const ( + // ModuleName defines the module name + ModuleName = "aspect" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_aspect" +) + +var ( + ParamsKey = []byte("p_aspect") +) + +func KeyPrefix(p string) []byte { + return []byte(p) +} diff --git a/x/aspect/types/models.go b/x/aspect/types/models.go new file mode 100644 index 0000000..4fd8abe --- /dev/null +++ b/x/aspect/types/models.go @@ -0,0 +1,58 @@ +package types + +import ( + "github.com/artela-network/aspect-core/types" + "github.com/ethereum/go-ethereum/common" +) + +// BindingFilter is the data model for holding the filter of querying aspect bindings +type BindingFilter struct { + // filter bindings with given join point + JoinPoint *types.PointCut + // only return bindings of verifier aspects + VerifierOnly bool + // only return bindings of tx level aspects + TxLevelOnly bool +} + +func NewDefaultFilter(isCA bool) BindingFilter { + if isCA { + return BindingFilter{} + } + + return BindingFilter{ + VerifierOnly: true, + } +} + +func NewJoinPointFilter(cut types.PointCut) BindingFilter { + return BindingFilter{ + JoinPoint: &cut, + } +} + +// Binding is the data model for holding the binding of an aspect to an account +type Binding struct { + Account common.Address + Version uint64 + Priority int8 + JoinPoint uint16 +} + +// VersionMeta is the data model for holding the metadata of a specific version of aspect +type VersionMeta struct { + JoinPoint uint64 + CodeHash common.Hash +} + +// AspectMeta is the data model for holding the metadata of an aspect +type AspectMeta struct { + PayMaster common.Address + Proof []byte +} + +// Property is the data model for holding the properties of an aspect +type Property struct { + Key string `json:"Key"` + Value []byte `json:"Value"` +} diff --git a/x/aspect/types/msg_update_params.go b/x/aspect/types/msg_update_params.go new file mode 100644 index 0000000..e36d023 --- /dev/null +++ b/x/aspect/types/msg_update_params.go @@ -0,0 +1,21 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.Msg = &MsgUpdateParams{} + +// ValidateBasic does a sanity check on the provided data. +func (m *MsgUpdateParams) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { + return errorsmod.Wrap(err, "invalid authority address") + } + + if err := m.Params.Validate(); err != nil { + return err + } + + return nil +} diff --git a/x/aspect/types/params.go b/x/aspect/types/params.go new file mode 100644 index 0000000..4f3215e --- /dev/null +++ b/x/aspect/types/params.go @@ -0,0 +1,32 @@ +package types + +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance +func NewParams() Params { + return Params{} +} + +// DefaultParams returns a default set of parameters +func DefaultParams() Params { + return NewParams() +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{} +} + +// Validate validates the set of params +func (p Params) Validate() error { + return nil +} diff --git a/x/aspect/types/params.pb.go b/x/aspect/types/params.pb.go new file mode 100644 index 0000000..771dbfc --- /dev/null +++ b/x/aspect/types/params.pb.go @@ -0,0 +1,289 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/aspect/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the module. +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_aa10fd154aeb7dff, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Params)(nil), "artela.aspect.Params") +} + +func init() { proto.RegisterFile("artela/aspect/params.proto", fileDescriptor_aa10fd154aeb7dff) } + +var fileDescriptor_aa10fd154aeb7dff = []byte{ + // 180 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0x2c, 0x2a, 0x49, + 0xcd, 0x49, 0xd4, 0x4f, 0x2c, 0x2e, 0x48, 0x4d, 0x2e, 0xd1, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, + 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x85, 0xc8, 0xe9, 0x41, 0xe4, 0xa4, 0x04, 0x13, + 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1, 0x24, 0x44, 0x85, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x98, + 0xa9, 0x0f, 0x62, 0x41, 0x44, 0x95, 0x34, 0xb9, 0xd8, 0x02, 0xc0, 0xe6, 0x58, 0xc9, 0xbf, 0x58, + 0x20, 0xcf, 0xd8, 0xf5, 0x7c, 0x83, 0x96, 0x18, 0xd4, 0x9a, 0x0a, 0x98, 0x45, 0x10, 0x05, 0x4e, + 0x81, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, + 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x9e, 0x9e, 0x59, 0x92, + 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0xd1, 0xac, 0x9b, 0x97, 0x5a, 0x52, 0x9e, 0x5f, + 0x94, 0x0d, 0xe3, 0x16, 0xe5, 0xe7, 0xe4, 0x64, 0x67, 0x96, 0x20, 0xcc, 0x2c, 0xa9, 0x2c, 0x48, + 0x2d, 0x4e, 0x62, 0x03, 0x3b, 0xc2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x14, 0x65, 0x62, 0xcb, + 0xda, 0x00, 0x00, 0x00, +} + +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + return true +} +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/aspect/types/query.pb.go b/x/aspect/types/query.pb.go new file mode 100644 index 0000000..8f6a8d4 --- /dev/null +++ b/x/aspect/types/query.pb.go @@ -0,0 +1,540 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/aspect/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8eb9a0eb98e11265, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params holds all the parameters of this module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8eb9a0eb98e11265, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "artela.aspect.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "artela.aspect.QueryParamsResponse") +} + +func init() { proto.RegisterFile("artela/aspect/query.proto", fileDescriptor_8eb9a0eb98e11265) } + +var fileDescriptor_8eb9a0eb98e11265 = []byte{ + // 326 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x31, 0x4b, 0xc3, 0x40, + 0x14, 0xc7, 0x73, 0x82, 0x05, 0x23, 0x0e, 0xc6, 0x0a, 0x1a, 0x24, 0x6a, 0x10, 0x91, 0x62, 0xf3, + 0x68, 0x1d, 0x74, 0xee, 0x17, 0xd0, 0x76, 0x74, 0x7b, 0x29, 0x47, 0x0c, 0x4d, 0xee, 0x5d, 0x73, + 0x57, 0xb5, 0x83, 0x8b, 0x83, 0xb3, 0xe0, 0x97, 0x70, 0xf4, 0x63, 0x74, 0x2c, 0xb8, 0x38, 0x89, + 0xb4, 0x82, 0x5f, 0x43, 0x7a, 0x17, 0x87, 0x6a, 0x71, 0x09, 0x8f, 0xf7, 0xff, 0xfd, 0xff, 0xf9, + 0xbf, 0x73, 0xb7, 0xb1, 0xd0, 0x3c, 0x43, 0x40, 0x25, 0x79, 0x57, 0x43, 0x7f, 0xc0, 0x8b, 0x61, + 0x24, 0x0b, 0xd2, 0xe4, 0xad, 0x59, 0x29, 0xb2, 0x92, 0xbf, 0x8e, 0x79, 0x2a, 0x08, 0xcc, 0xd7, + 0x12, 0x7e, 0x35, 0xa1, 0x84, 0xcc, 0x08, 0xb3, 0xa9, 0xdc, 0xee, 0x24, 0x44, 0x49, 0xc6, 0x01, + 0x65, 0x0a, 0x28, 0x04, 0x69, 0xd4, 0x29, 0x09, 0x55, 0xaa, 0xb5, 0x2e, 0xa9, 0x9c, 0x14, 0xc4, + 0xa8, 0xb8, 0xfd, 0x1d, 0x5c, 0x37, 0x62, 0xae, 0xb1, 0x01, 0x12, 0x93, 0x54, 0x18, 0xb8, 0x64, + 0xfd, 0xf9, 0x72, 0x12, 0x0b, 0xcc, 0xcb, 0x9c, 0xb0, 0xea, 0x7a, 0xed, 0x99, 0xfb, 0xc2, 0x2c, + 0x3b, 0xbc, 0x3f, 0xe0, 0x4a, 0x87, 0xe7, 0xee, 0xc6, 0xdc, 0x56, 0x49, 0x12, 0x8a, 0x7b, 0x67, + 0x6e, 0xc5, 0x9a, 0xb7, 0xd8, 0x1e, 0x3b, 0x5a, 0x6d, 0x6e, 0x46, 0x73, 0xb7, 0x45, 0x16, 0x6f, + 0xad, 0x8c, 0xde, 0x77, 0x9d, 0xe7, 0xaf, 0x97, 0x1a, 0xeb, 0x94, 0x7c, 0xf3, 0x81, 0xb9, 0xcb, + 0x26, 0xd1, 0xbb, 0x73, 0x2b, 0x16, 0xf3, 0xf6, 0x7f, 0xb9, 0xff, 0xf6, 0xf0, 0xc3, 0xff, 0x10, + 0x5b, 0x2a, 0x3c, 0xbe, 0x7f, 0xfd, 0x7c, 0x5a, 0x3a, 0xf4, 0x0e, 0xc0, 0xb2, 0x75, 0xc1, 0xf5, + 0x0d, 0x15, 0x3d, 0x58, 0x74, 0x75, 0xab, 0x3d, 0x9a, 0x04, 0x6c, 0x3c, 0x09, 0xd8, 0xc7, 0x24, + 0x60, 0x8f, 0xd3, 0xc0, 0x19, 0x4f, 0x03, 0xe7, 0x6d, 0x1a, 0x38, 0x97, 0xa7, 0x49, 0xaa, 0xaf, + 0x06, 0x71, 0xd4, 0xa5, 0x7c, 0x71, 0x52, 0xbd, 0xa0, 0x2c, 0xeb, 0xa5, 0x1a, 0x6e, 0x7f, 0x32, + 0xf5, 0x50, 0x72, 0x15, 0x57, 0xcc, 0x4b, 0x9e, 0x7c, 0x07, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x7d, + 0x15, 0x45, 0x04, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Parameters queries the parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/artela.aspect.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Parameters queries the parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/artela.aspect.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "artela.aspect.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "artela/aspect/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/aspect/types/query.pb.gw.go b/x/aspect/types/query.pb.gw.go new file mode 100644 index 0000000..889e0cb --- /dev/null +++ b/x/aspect/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: artela/aspect/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"artela-network", "artela", "aspect", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/aspect/types/tx.pb.go b/x/aspect/types/tx.pb.go new file mode 100644 index 0000000..fc1f854 --- /dev/null +++ b/x/aspect/types/tx.pb.go @@ -0,0 +1,598 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/aspect/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgUpdateParams is the Msg/UpdateParams request type. +type MsgUpdateParams struct { + // authority is the address that controls the module (defaults to x/gov unless overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the module parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_7a6b894a50f2bb09, []int{0} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_7a6b894a50f2bb09, []int{1} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgUpdateParams)(nil), "artela.aspect.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "artela.aspect.MsgUpdateParamsResponse") +} + +func init() { proto.RegisterFile("artela/aspect/tx.proto", fileDescriptor_7a6b894a50f2bb09) } + +var fileDescriptor_7a6b894a50f2bb09 = []byte{ + // 350 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2c, 0x2a, 0x49, + 0xcd, 0x49, 0xd4, 0x4f, 0x2c, 0x2e, 0x48, 0x4d, 0x2e, 0xd1, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0xe2, 0x85, 0x88, 0xeb, 0x41, 0xc4, 0xa5, 0x04, 0x13, 0x73, 0x33, 0xf3, 0xf2, + 0xf5, 0xc1, 0x24, 0x44, 0x85, 0x94, 0x78, 0x72, 0x7e, 0x71, 0x6e, 0x7e, 0xb1, 0x7e, 0x6e, 0x71, + 0xba, 0x7e, 0x99, 0x21, 0x88, 0x82, 0x4a, 0x48, 0x42, 0x24, 0xe2, 0xc1, 0x3c, 0x7d, 0x08, 0x07, + 0x2a, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x11, 0x07, 0xb1, 0xa0, 0xa2, 0x52, 0xa8, 0x6e, 0x28, + 0x48, 0x2c, 0x4a, 0xcc, 0x85, 0xea, 0x50, 0xda, 0xce, 0xc8, 0xc5, 0xef, 0x5b, 0x9c, 0x1e, 0x5a, + 0x90, 0x92, 0x58, 0x92, 0x1a, 0x00, 0x96, 0x11, 0x32, 0xe3, 0xe2, 0x4c, 0x2c, 0x2d, 0xc9, 0xc8, + 0x2f, 0xca, 0x2c, 0xa9, 0x94, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x74, 0x92, 0xb8, 0xb4, 0x45, 0x57, + 0x04, 0x6a, 0x95, 0x63, 0x4a, 0x4a, 0x51, 0x6a, 0x71, 0x71, 0x70, 0x49, 0x51, 0x66, 0x5e, 0x7a, + 0x10, 0x42, 0xa9, 0x90, 0x05, 0x17, 0x1b, 0xc4, 0x6c, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x6e, 0x23, + 0x51, 0x3d, 0x14, 0x4f, 0xea, 0x41, 0x8c, 0x77, 0xe2, 0x3c, 0x71, 0x4f, 0x9e, 0x61, 0xc5, 0xf3, + 0x0d, 0x5a, 0x8c, 0x41, 0x50, 0xf5, 0x56, 0x46, 0x4d, 0xcf, 0x37, 0x68, 0x21, 0x4c, 0xea, 0x7a, + 0xbe, 0x41, 0x4b, 0x1e, 0xea, 0xe8, 0x0a, 0x98, 0xb3, 0xd1, 0x5c, 0xa9, 0x24, 0xc9, 0x25, 0x8e, + 0x26, 0x14, 0x94, 0x5a, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0x6a, 0x94, 0xc2, 0xc5, 0xec, 0x5b, 0x9c, + 0x2e, 0x14, 0xc6, 0xc5, 0x83, 0xe2, 0x2f, 0x39, 0x34, 0xf7, 0xa0, 0x69, 0x97, 0x52, 0xc3, 0x2f, + 0x0f, 0x33, 0x5e, 0x8a, 0xb5, 0x01, 0xe4, 0x78, 0xa7, 0xc0, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, + 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, + 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4f, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, + 0x87, 0x18, 0xa9, 0x9b, 0x97, 0x5a, 0x52, 0x9e, 0x5f, 0x94, 0x0d, 0xe3, 0x16, 0xe5, 0xe7, 0xe4, + 0x64, 0x67, 0x96, 0x20, 0x7c, 0x57, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x8e, 0x14, 0x63, + 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0xfb, 0x54, 0x25, 0x36, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // UpdateParams defines a (governance) operation for updating the module + // parameters. The authority defaults to the x/gov module account. + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/artela.aspect.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // UpdateParams defines a (governance) operation for updating the module + // parameters. The authority defaults to the x/gov module account. + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/artela.aspect.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "artela.aspect.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "artela/aspect/tx.proto", +} + +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/aspect/types/types.go b/x/aspect/types/types.go new file mode 100644 index 0000000..ab1254f --- /dev/null +++ b/x/aspect/types/types.go @@ -0,0 +1 @@ +package types diff --git a/x/evm/artela/api/aspect_property_api.go b/x/evm/artela/api/aspect_property_api.go index f1e47d6..4f27643 100644 --- a/x/evm/artela/api/aspect_property_api.go +++ b/x/evm/artela/api/aspect_property_api.go @@ -4,10 +4,8 @@ import ( "context" "errors" - asptypes "github.com/artela-network/aspect-core/types" - - "github.com/artela-network/artela-rollkit/x/evm/artela/contract" "github.com/artela-network/artela-rollkit/x/evm/artela/types" + asptypes "github.com/artela-network/aspect-core/types" ) var _ asptypes.AspectPropertyHostAPI = (*aspectPropertyHostAPI)(nil) @@ -17,10 +15,7 @@ type aspectPropertyHostAPI struct { } func (a *aspectPropertyHostAPI) Get(ctx *asptypes.RunnerContext, key string) (ret []byte, err error) { - // TODO: this part looks weird, - // but due to the time issue, we just migrate the old logics for now - nativeContractStore := contract.NewAspectStore(a.aspectRuntimeContext.StoreService(), a.aspectRuntimeContext.Logger()) - ret, ctx.Gas, err = nativeContractStore.GetAspectPropertyValue(a.aspectRuntimeContext.CosmosContext(), ctx.AspectId, key, ctx.Gas) + ret = a.aspectRuntimeContext.GetAspectProperty(ctx, ctx.AspectVersion, key) return } diff --git a/x/evm/artela/api/aspect_runtime_ctx_api.go b/x/evm/artela/api/aspect_runtime_ctx_api.go index 353a05b..b88183a 100644 --- a/x/evm/artela/api/aspect_runtime_ctx_api.go +++ b/x/evm/artela/api/aspect_runtime_ctx_api.go @@ -92,7 +92,6 @@ func (a *aspectRuntimeContextHostAPI) Register() { blockCtx := datactx.NewBlockContext(a.aspectRuntimeContext) a.execMap[aspctx.BlockHeaderParentHash] = blockCtx.ValueLoader(aspctx.BlockHeaderParentHash) a.execMap[aspctx.BlockHeaderMiner] = blockCtx.ValueLoader(aspctx.BlockHeaderMiner) - a.execMap[aspctx.BlockHeaderTransactionsRoot] = blockCtx.ValueLoader(aspctx.BlockHeaderTransactionsRoot) a.execMap[aspctx.BlockHeaderNumber] = blockCtx.ValueLoader(aspctx.BlockHeaderNumber) a.execMap[aspctx.BlockHeaderTimestamp] = blockCtx.ValueLoader(aspctx.BlockHeaderTimestamp) diff --git a/x/evm/artela/api/datactx/block.go b/x/evm/artela/api/datactx/block.go index 76d3b6b..66176ff 100644 --- a/x/evm/artela/api/datactx/block.go +++ b/x/evm/artela/api/datactx/block.go @@ -35,9 +35,6 @@ func (c *BlockContext) registerLoaders() { loaders[context.BlockHeaderMiner] = func(blockCtx *types.EthBlockContext) proto.Message { return &artelatypes.BytesData{Data: blockCtx.BlockHeader().Coinbase.Bytes()} } - loaders[context.BlockHeaderTransactionsRoot] = func(blockCtx *types.EthBlockContext) proto.Message { - return &artelatypes.BytesData{Data: blockCtx.BlockHeader().TxHash.Bytes()} - } loaders[context.BlockHeaderNumber] = func(blockCtx *types.EthBlockContext) proto.Message { number := blockCtx.BlockHeader().Number.Uint64() return &artelatypes.UintData{Data: &number} diff --git a/x/evm/artela/api/datactx/tx.go b/x/evm/artela/api/datactx/tx.go index b6a0074..34b2c07 100644 --- a/x/evm/artela/api/datactx/tx.go +++ b/x/evm/artela/api/datactx/tx.go @@ -43,7 +43,7 @@ func (c *TxContext) registerLoaders() { return &artelatypes.UintData{Data: &txType} } loaders[aspctx.TxChainId] = func(_ *types.EthTxContext, tx *ethereum.Transaction) proto.Message { - if tx.ChainId() != nil { + if v, _, _ := tx.RawSignatureValues(); v.Cmp(big.NewInt(0)) != 0 && tx.ChainId() != nil { return &artelatypes.BytesData{Data: tx.ChainId().Bytes()} } return &artelatypes.BytesData{Data: []byte{}} diff --git a/x/evm/artela/api/evm_api.go b/x/evm/artela/api/evm_api.go index e34ab84..893febd 100644 --- a/x/evm/artela/api/evm_api.go +++ b/x/evm/artela/api/evm_api.go @@ -78,18 +78,23 @@ func (e *evmHostApi) StaticCall(ctx *asptypes.RunnerContext, request *asptypes.S request.Gas = &ctx.Gas } - ret, gas, err := evm.StaticCall(ctx.Ctx, vm.AccountRef(from), to, request.Data, *request.Gas) + ret, leftover, err := evm.StaticCall(ctx.Ctx, vm.AccountRef(from), to, request.Data, *request.Gas) // update gas - ctx.Gas = gas + usedGas := *request.Gas - leftover + ctx.Gas -= usedGas errStr := "" if err != nil { + // ignore revert error, error message will be set to vmError + if err.Error() != vm.ErrExecutionReverted.Error() { + return nil, err + } errStr = err.Error() } return &asptypes.StaticCallResult{ Ret: ret, - GasLeft: &gas, + GasLeft: &ctx.Gas, VmError: &errStr, }, nil } diff --git a/x/evm/artela/contract/contract.go b/x/evm/artela/contract/contract.go index 27d1ddb..3c8ce4a 100644 --- a/x/evm/artela/contract/contract.go +++ b/x/evm/artela/contract/contract.go @@ -7,39 +7,40 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/core" "github.com/artela-network/artela-evm/vm" - "github.com/artela-network/artela-rollkit/common" "github.com/artela-network/artela-rollkit/common/aspect" - "github.com/artela-network/artela-rollkit/x/evm/states" evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" ) type AspectNativeContract struct { - aspectService *AspectService - evmState *states.StateDB - evm *vm.EVM + evmState *states.StateDB + evm *vm.EVM logger log.Logger handlers map[string]Handler + + storeService store.KVStoreService + aspectStoreService store.KVStoreService } -func NewAspectNativeContract(storeService store.KVStoreService, +func NewAspectNativeContract( + storeService store.KVStoreService, + aspectStoreService store.KVStoreService, evm *vm.EVM, - getBlockHeight func() int64, evmState *states.StateDB, logger log.Logger, ) *AspectNativeContract { return &AspectNativeContract{ - aspectService: NewAspectService(storeService, getBlockHeight, logger), - evm: evm, - evmState: evmState, - logger: logger, - handlers: make(map[string]Handler), + storeService: storeService, + aspectStoreService: aspectStoreService, + evm: evm, + evmState: evmState, + logger: logger, + handlers: make(map[string]Handler), } } @@ -60,14 +61,7 @@ func (c *AspectNativeContract) register(handler Handler) { } func (c *AspectNativeContract) ApplyMessage(ctx sdk.Context, msg *core.Message, gas uint64, commit bool) (ret []byte, remainingGas uint64, err error) { - var writeCacheFunc func() - ctx, writeCacheFunc = ctx.CacheContext() - ret, remainingGas, err = c.applyMsg(ctx, msg, gas, commit) - if err == nil && commit { - writeCacheFunc() - } - - return ret, remainingGas, err + return c.applyMsg(ctx, msg, gas, commit) } func (c *AspectNativeContract) applyMsg(ctx sdk.Context, msg *core.Message, gas uint64, commit bool) (ret []byte, remainingGas uint64, err error) { @@ -86,11 +80,12 @@ func (c *AspectNativeContract) applyMsg(ctx sdk.Context, msg *core.Message, gas msg.From, parameters, commit, - c.aspectService, common.WrapLogger(c.logger.With("module", "aspect-system-contract")), c.evmState, c.evm, method, + c.storeService, + c.aspectStoreService, msg.Data, msg.Nonce, msg.GasLimit, diff --git a/x/evm/artela/contract/handlers.go b/x/evm/artela/contract/handlers.go index 56ef322..b5c37ac 100644 --- a/x/evm/artela/contract/handlers.go +++ b/x/evm/artela/contract/handlers.go @@ -7,6 +7,11 @@ import ( "math/big" "time" + asptool "github.com/artela-network/artela-rollkit/x/aspect/common" + "github.com/artela-network/artela-rollkit/x/aspect/store" + aspectmoduletypes "github.com/artela-network/artela-rollkit/x/aspect/types" + + cstore "cosmossdk.io/core/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -20,7 +25,7 @@ import ( runtime "github.com/artela-network/aspect-runtime" runtimeTypes "github.com/artela-network/aspect-runtime/types" - artool "github.com/artela-network/artela-rollkit/common" + arttool "github.com/artela-network/artela-rollkit/common" "github.com/artela-network/artela-rollkit/x/evm/artela/types" "github.com/artela-network/artela-rollkit/x/evm/states" ) @@ -36,12 +41,14 @@ type HandlerContext struct { from common.Address parameters map[string]interface{} commit bool - service *AspectService logger runtimeTypes.Logger evmState *states.StateDB evm *vm.EVM abi *abi.Method + storeService cstore.KVStoreService + aspectStoreService cstore.KVStoreService + rawInput []byte nonce uint64 gasLimit uint64 @@ -58,40 +65,70 @@ type Handler interface { type DeployHandler struct{} func (h DeployHandler) Handle(ctx *HandlerContext, gas uint64) ([]byte, uint64, error) { - aspectId, code, initData, properties, joinPoint, err := h.decodeAndValidate(ctx) + aspectID, code, initData, properties, joinPoint, paymaster, proof, err := h.decodeAndValidate(ctx) if err != nil { ctx.logger.Error("deploy aspect failed", "error", err, "from", ctx.from, "gasLimit", ctx.gasLimit) return nil, 0, err } - store := ctx.service.aspectStore - newVersion, gas, err := store.BumpAspectVersion(ctx.cosmosCtx, aspectId, gas) + // we can ignore the new store here, since new deployed aspect should not have that + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, gas)) if err != nil { - ctx.logger.Error("bump aspect version failed", "error", err) - return nil, gas, err + return nil, 0, err + } + + // check duplicate deployment + var latestVersion uint64 + if latestVersion, err = metaStore.GetLatestVersion(); err != nil { + return nil, 0, err + } else if latestVersion > 0 { + return nil, 0, errors.New("aspect already deployed") + } + + if err := metaStore.Init(); err != nil { + ctx.logger.Error("init aspect meta failed", "error", err) + return nil, 0, err } - gas, err = store.StoreAspectCode(ctx.cosmosCtx, aspectId, code, newVersion, gas) + newVersion, err := metaStore.BumpVersion() if err != nil { + ctx.logger.Error("bump aspect version failed", "error", err) + return nil, 0, err + } + + if err = metaStore.StoreCode(newVersion, code); err != nil { ctx.logger.Error("store aspect code failed", "error", err) - return nil, gas, err + return nil, 0, err } // join point might be nil, since there are some operation only Aspects - if joinPoint != nil { - store.StoreAspectJP(ctx.cosmosCtx, aspectId, *newVersion, joinPoint) + if err = metaStore.StoreVersionMeta(newVersion, &aspectmoduletypes.VersionMeta{ + JoinPoint: joinPoint.Uint64(), + CodeHash: crypto.Keccak256Hash(code), + }); err != nil { + ctx.logger.Error("store aspect meta failed", "error", err) + return nil, 0, err } - if len(properties) > 0 { - gas, err = store.StoreAspectProperty(ctx.cosmosCtx, aspectId, properties, gas) - if err != nil { - ctx.logger.Error("store aspect property failed", "error", err) - } + if err = metaStore.StoreMeta(&aspectmoduletypes.AspectMeta{ + Proof: proof, + PayMaster: paymaster, + }); err != nil { + ctx.logger.Error("store aspect meta failed", "error", err) + return nil, 0, err } + if err = metaStore.StoreProperties(newVersion, properties); err != nil { + ctx.logger.Error("store aspect property failed", "error", err) + return nil, 0, err + } + + // get remaining gas after updating store + gas = metaStore.Gas() + // initialize aspect aspectCtx := mustGetAspectContext(ctx.cosmosCtx) - runner, err := run.NewRunner(aspectCtx, ctx.logger, aspectId.String(), newVersion.Uint64(), code, ctx.commit) + runner, err := run.NewRunner(aspectCtx, ctx.logger, aspectID.String(), newVersion, code, ctx.commit) if err != nil { ctx.logger.Error("failed to create aspect runner", "error", err) return nil, 0, err @@ -107,10 +144,10 @@ func (h DeployHandler) Handle(ctx *HandlerContext, gas uint64) ([]byte, uint64, height := ctx.cosmosCtx.BlockHeight() heightU64 := uint64(height) - return runner.JoinPoint(artelasdkType.INIT_METHOD, gas, height, aspectId, &artelasdkType.InitInput{ + return runner.JoinPoint(artelasdkType.INIT_METHOD, gas, height, aspectID, &artelasdkType.InitInput{ Tx: &artelasdkType.WithFromTxInput{ Hash: txHash, - To: aspectId.Bytes(), + To: aspectID.Bytes(), From: ctx.from.Bytes(), }, Block: &artelasdkType.BlockInput{Number: &heightU64}, @@ -122,7 +159,15 @@ func (h DeployHandler) Method() string { return "deploy" } -func (h DeployHandler) decodeAndValidate(ctx *HandlerContext) (aspectId common.Address, code, initData []byte, properties []types.Property, joinPoint *big.Int, err error) { +func (h DeployHandler) decodeAndValidate(ctx *HandlerContext) ( + aspectId common.Address, + code, + initData []byte, + properties []aspectmoduletypes.Property, + joinPoint *big.Int, + paymaster common.Address, + proof []byte, + err error) { // input validations code = ctx.parameters["code"].([]byte) if len(code) == 0 { @@ -139,51 +184,27 @@ func (h DeployHandler) decodeAndValidate(ctx *HandlerContext) (aspectId common.A for i := range propertiesArr { s := propertiesArr[i] - if types.AspectProofKey == s.Key || types.AspectAccountKey == s.Key { - // Block query of account and Proof - err = errors.New("using reserved aspect property key") - return - } - - properties = append(properties, types.Property{ + properties = append(properties, aspectmoduletypes.Property{ Key: s.Key, Value: s.Value, }) } - account := ctx.parameters["account"].(common.Address) - if bytes.Equal(account.Bytes(), ctx.from.Bytes()) { - accountProperty := types.Property{ - Key: types.AspectAccountKey, - Value: account.Bytes(), - } - properties = append(properties, accountProperty) - } else { + paymaster = ctx.parameters["account"].(common.Address) + if !bytes.Equal(paymaster.Bytes(), ctx.from.Bytes()) { err = errors.New("account verification fail") return } - proof := ctx.parameters["proof"].([]byte) - proofProperty := types.Property{ - Key: types.AspectProofKey, - Value: proof, - } - properties = append(properties, proofProperty) + proof = ctx.parameters["proof"].([]byte) joinPoint = ctx.parameters["joinPoints"].(*big.Int) if joinPoint == nil { - err = errors.New("unable to decode join point") - return + joinPoint = big.NewInt(0) } aspectId = crypto.CreateAddress(ctx.from, ctx.nonce) - // check duplicate deployment - if isAspectDeployed(ctx.cosmosCtx, ctx.service.aspectStore, aspectId) { - err = errors.New("aspect already deployed") - return - } - // validate aspect code code, err = validateCode(ctx.cosmosCtx, code) return @@ -192,45 +213,87 @@ func (h DeployHandler) decodeAndValidate(ctx *HandlerContext) (aspectId common.A type UpgradeHandler struct{} func (h UpgradeHandler) Handle(ctx *HandlerContext, gas uint64) ([]byte, uint64, error) { - aspectId, code, properties, joinPoint, gas, err := h.decodeAndValidate(ctx, gas) + aspectID, code, properties, joinPoint, err := h.decodeAndValidate(ctx) if err != nil { - return nil, gas, err + return nil, 0, err } - store := ctx.service.aspectStore - newVersion, gas, err := store.BumpAspectVersion(ctx.cosmosCtx, aspectId, gas) + // check deployment + storeCtx := buildAspectStoreCtx(ctx, aspectID, gas) + currentStore, _, err := store.GetAspectMetaStore(storeCtx) + if err != nil { + return nil, 0, err + } + + // check deployment + var latestVersion uint64 + if latestVersion, err = currentStore.GetLatestVersion(); err != nil { + return nil, 0, err + } else if latestVersion == 0 { + return nil, 0, errors.New("aspect not deployed") + } + + // check aspect owner + var currentCode []byte + currentCode, err = currentStore.GetCode(latestVersion) + if err != nil { + return nil, 0, err + } + + var ok bool + ok, gas, err = checkAspectOwner(ctx.cosmosCtx, aspectID, ctx.from, storeCtx.Gas(), currentCode, latestVersion, ctx.commit) + if err != nil || !ok { + err = errors.New("aspect ownership validation failed") + return nil, 0, err + } + storeCtx.UpdateGas(gas) + + // bump version + newVersion, err := currentStore.BumpVersion() if err != nil { ctx.logger.Error("bump aspect version failed", "error", err) return nil, gas, err } - if gas, err = store.StoreAspectCode(ctx.cosmosCtx, aspectId, code, newVersion, gas); err != nil { + if err = currentStore.StoreCode(newVersion, code); err != nil { ctx.logger.Error("store aspect code failed", "error", err) - return nil, gas, err + return nil, 0, err } // join point might be nil, since there are some operation only Aspects + var jpU64 uint64 if joinPoint != nil { - store.StoreAspectJP(ctx.cosmosCtx, aspectId, *newVersion, joinPoint) + jpU64 = joinPoint.Uint64() + } + + if err = currentStore.StoreVersionMeta(newVersion, &aspectmoduletypes.VersionMeta{ + JoinPoint: jpU64, + CodeHash: common.BytesToHash(crypto.Keccak256(code)), + }); err != nil { + ctx.logger.Error("store aspect meta failed", "error", err) + return nil, 0, err } - if len(properties) > 0 { - gas, err = store.StoreAspectProperty(ctx.cosmosCtx, aspectId, properties, gas) + // save properties if any + if err = currentStore.StoreProperties(newVersion, properties); err != nil { + ctx.logger.Error("store aspect property failed", "error", err) + return nil, 0, err } - return nil, gas, err + return nil, storeCtx.Gas(), err } func (h UpgradeHandler) Method() string { return "upgrade" } -func (h UpgradeHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) (aspectId common.Address, +func (h UpgradeHandler) decodeAndValidate(ctx *HandlerContext) ( + aspectID common.Address, code []byte, - properties []types.Property, - joinPoint *big.Int, leftover uint64, err error) { - aspectId = ctx.parameters["aspectId"].(common.Address) - if bytes.Equal(emptyAddr.Bytes(), aspectId.Bytes()) { + properties []aspectmoduletypes.Property, + joinPoint *big.Int, err error) { + aspectID = ctx.parameters["aspectId"].(common.Address) + if bytes.Equal(emptyAddr.Bytes(), aspectID.Bytes()) { err = errors.New("aspectId not specified") return } @@ -247,17 +310,10 @@ func (h UpgradeHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) (aspe Value []byte `json:"value"` }) - for i := range propertiesArr { - s := propertiesArr[i] - if types.AspectProofKey == s.Key || types.AspectAccountKey == s.Key { - // Block query of account and Proof - err = errors.New("using reserved aspect property key") - return - } - - properties = append(properties, types.Property{ - Key: s.Key, - Value: s.Value, + for _, prop := range propertiesArr { + properties = append(properties, aspectmoduletypes.Property{ + Key: prop.Key, + Value: prop.Value, }) } @@ -266,23 +322,6 @@ func (h UpgradeHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) (aspe joinPoint = big.NewInt(0) } - // check deployment - store := ctx.service.aspectStore - if !isAspectDeployed(ctx.cosmosCtx, store, aspectId) { - err = errors.New("aspect not deployed") - return - } - - // check aspect owner - currentCode, version := store.GetAspectCode(ctx.cosmosCtx, aspectId, nil) - - var ok bool - ok, leftover, err = checkAspectOwner(ctx.cosmosCtx, aspectId, ctx.from, gas, currentCode, version, ctx.commit) - if err != nil || !ok { - err = errors.New("aspect ownership validation failed") - return - } - // validate aspect code code, err = validateCode(ctx.cosmosCtx, code) return @@ -291,20 +330,41 @@ func (h UpgradeHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) (aspe type BindHandler struct{} func (b BindHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, account, aspectVersion, priority, isContract, leftover, err := b.decodeAndValidate(ctx, gas) + aspectID, account, aspectVersion, priority, isContract, leftover, err := b.decodeAndValidate(ctx, gas) if err != nil { - return nil, leftover, err + return nil, 0, err } - // check aspect types - store := ctx.service.aspectStore - aspectJP, err := store.GetAspectJP(ctx.cosmosCtx, aspectId, aspectVersion) + // no need to get new version store, since we only do auto migration during aspect upgrade + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, leftover)) if err != nil { - return nil, leftover, err + return nil, 0, err + } + + // get latest version if aspect version is empty + latestVersion, err := metaStore.GetLatestVersion() + if err != nil { + return nil, 0, err + } + if latestVersion == 0 { + return nil, 0, errors.New("aspect not deployed") } - txAspect := artelasdkType.CheckIsTransactionLevel(aspectJP.Int64()) - txVerifier := artelasdkType.CheckIsTxVerifier(aspectJP.Int64()) + if aspectVersion == 0 { + // use latest if not specified + aspectVersion = latestVersion + } else if aspectVersion > latestVersion { + return nil, 0, errors.New("aspect version not deployed") + } + + meta, err := metaStore.GetVersionMeta(aspectVersion) + if err != nil { + return nil, 0, err + } + + i64JP := int64(meta.JoinPoint) + txAspect := artelasdkType.CheckIsTransactionLevel(i64JP) + txVerifier := artelasdkType.CheckIsTxVerifier(i64JP) if !txAspect && !txVerifier { return nil, 0, errors.New("aspect is either for tx or verifier") @@ -315,28 +375,34 @@ func (b BindHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remain return nil, 0, errors.New("only verifier aspect can be bound with eoa") } - // bind tx processing aspect if account is a contract - if txAspect && isContract { - if err := store.BindTxAspect(ctx.cosmosCtx, account, aspectId, aspectVersion, priority); err != nil { - ctx.logger.Error("bind tx aspect failed", "aspect", aspectId.Hex(), "version", aspectVersion.Uint64(), "contract", account.Hex(), "error", err) - return nil, 0, err - } + // save aspect -> contract bindings + if err := metaStore.StoreBinding(account, aspectVersion, meta.JoinPoint, priority); err != nil { + return nil, 0, err } - // bind tx verifier aspect - if txVerifier { - if err := store.BindVerificationAspect(ctx.cosmosCtx, account, aspectId, aspectVersion, priority, isContract); err != nil { - ctx.logger.Error("bind verifier aspect failed", "aspect", aspectId.Hex(), "version", aspectVersion.Uint64(), "account", account.Hex(), "error", err) + // init account store + accountStore, _, err := store.GetAccountStore(buildAccountStoreCtx(ctx, account, metaStore.Gas())) + if err != nil { + return nil, 0, err + } + + // check if used + if used, err := accountStore.Used(); err != nil { + return nil, 0, err + } else if !used { + // init if not used + if err := accountStore.Init(); err != nil { return nil, 0, err } } - // save reverse index - if err := store.StoreAspectRefValue(ctx.cosmosCtx, account, aspectId); err != nil { + // save account -> contract bindings + if err := accountStore.StoreBinding(aspectID, aspectVersion, meta.JoinPoint, priority, isContract); err != nil { + ctx.logger.Error("bind tx aspect failed", "aspect", aspectID.Hex(), "version", aspectVersion, "contract", account.Hex(), "error", err) return nil, 0, err } - return nil, leftover, nil + return nil, accountStore.Gas(), nil } func (b BindHandler) Method() string { @@ -346,7 +412,7 @@ func (b BindHandler) Method() string { func (b BindHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) ( aspectId common.Address, account common.Address, - aspectVersion *uint256.Int, + aspectVersion uint64, priority int8, isContract bool, leftover uint64, @@ -361,6 +427,10 @@ func (b BindHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) ( if version != nil && version.Sign() < 0 { err = errors.New("aspectVersion is negative") return + } else if version == nil { + aspectVersion = 0 + } else { + aspectVersion = version.Uint64() } account = ctx.parameters["contract"].(common.Address) @@ -371,12 +441,6 @@ func (b BindHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) ( priority = ctx.parameters["priority"].(int8) - store := ctx.service.aspectStore - if !isAspectDeployed(ctx.cosmosCtx, store, aspectId) { - err = errors.New("aspect not deployed") - return - } - isContract = len(ctx.evmState.GetCode(account)) > 0 if isContract { var isOwner bool @@ -392,41 +456,65 @@ func (b BindHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) ( leftover = gas } - aspectVersion, _ = uint256.FromBig(version) - - // overwrite aspect version, just in case if aspect version is 0 which means we will need to overwrite - // it to latest - if aspectVersion == nil || aspectVersion.Cmp(zero) <= 0 { - aspectVersion = ctx.service.aspectStore.GetAspectLastVersion(ctx.cosmosCtx, aspectId) - } - return } type UnbindHandler struct{} func (u UnbindHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, account, isContract, leftover, err := u.decodeAndValidate(ctx, gas) + aspectID, account, isContract, leftover, err := u.decodeAndValidate(ctx, gas) if err != nil { return nil, leftover, err } - store := ctx.service.aspectStore + // init account store + accountStore, _, err := store.GetAccountStore(buildAccountStoreCtx(ctx, account, leftover)) + if err != nil { + return nil, 0, err + } - if err := store.UnBindVerificationAspect(ctx.cosmosCtx, account, aspectId); err != nil { - return nil, leftover, err + bindings, err := accountStore.LoadAccountBoundAspects(aspectmoduletypes.NewDefaultFilter(isContract)) + if err != nil { + return nil, 0, err } - if isContract { - if err := store.UnBindContractAspects(ctx.cosmosCtx, account, aspectId); err != nil { - return nil, leftover, err + + // looking for binding info + version := uint64(0) + for _, binding := range bindings { + if binding.Account == aspectID { + version = binding.Version + break } } - if err := store.UnbindAspectRefValue(ctx.cosmosCtx, account, aspectId); err != nil { - return nil, leftover, err + if version == 0 { + // not bound + return nil, accountStore.Gas(), nil + } + + // init aspect meta store + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, accountStore.Gas())) + if err != nil { + return nil, 0, err } - return nil, leftover, nil + // remove account from aspect bound list + if err := metaStore.RemoveBinding(account); err != nil { + return nil, 0, err + } + // load aspect join point + meta, err := metaStore.GetVersionMeta(version) + if err != nil { + return nil, 0, err + } + + // remove aspect from account bound list + accountStore.TransferGasFrom(metaStore) + if err := accountStore.RemoveBinding(aspectID, meta.JoinPoint, isContract); err != nil { + return nil, 0, err + } + + return nil, accountStore.Gas(), nil } func (u UnbindHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) ( @@ -470,30 +558,94 @@ func (u UnbindHandler) Method() string { type ChangeVersionHandler struct{} func (c ChangeVersionHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, account, version, isContract, leftover, err := c.decodeAndValidate(ctx, gas) + aspectID, account, version, isContract, leftover, err := c.decodeAndValidate(ctx, gas) if err != nil { return nil, leftover, err } - aspectJP, err := ctx.service.aspectStore.GetAspectJP(ctx.cosmosCtx, aspectId, uint256.NewInt(version)) + // init account store + accountStore, _, err := store.GetAccountStore(buildAccountStoreCtx(ctx, account, leftover)) if err != nil { - return nil, leftover, err + return nil, 0, err } - txAspect := artelasdkType.CheckIsTransactionLevel(aspectJP.Int64()) - verifierAspect := artelasdkType.CheckIsTxVerifier(aspectJP.Int64()) + bindings, err := accountStore.LoadAccountBoundAspects(aspectmoduletypes.NewDefaultFilter(isContract)) + if err != nil { + return nil, 0, err + } + + // looking for binding info + var bindingInfo *aspectmoduletypes.Binding + for _, binding := range bindings { + if binding.Account == aspectID { + bindingInfo = &binding + break + } + } - if !txAspect && !verifierAspect { - return nil, leftover, errors.New("aspect is either for tx or verifier") + if bindingInfo == nil { + // not bound + return nil, 0, errors.New("aspect not bound") } - if !verifierAspect && !isContract { + // init aspect meta store + metaStoreCtx := buildAspectStoreCtx(ctx, aspectID, accountStore.Gas()) + metaStore, _, err := store.GetAspectMetaStore(metaStoreCtx) + if err != nil { + return nil, 0, err + } + + // load current bound version aspect meta + currentVersionMeta, err := metaStore.GetVersionMeta(bindingInfo.Version) + if err != nil { + return nil, 0, err + } + + latestVersion, err := metaStore.GetLatestVersion() + if latestVersion == 0 { + return nil, 0, errors.New("aspect not deployed") + } + + if version > latestVersion { + return nil, 0, errors.New("given version of aspect does not exist") + } + + if version == 0 { + // use latest if not specified + version = latestVersion + } + + // load new aspect meta + newVersionMeta, err := metaStore.GetVersionMeta(version) + if err != nil { + return nil, 0, err + } + + i64JP := int64(newVersionMeta.JoinPoint) + txAspect := artelasdkType.CheckIsTransactionLevel(i64JP) + txVerifier := artelasdkType.CheckIsTxVerifier(i64JP) + + if !txAspect && !txVerifier { + return nil, 0, errors.New("aspect is either for tx or verifier") + } + + // EoA can only bind with tx verifier + if !txVerifier && !isContract { return nil, 0, errors.New("only verifier aspect can be bound with eoa") } - err = ctx.service.aspectStore.ChangeBoundAspectVersion(ctx.cosmosCtx, account, aspectId, version, isContract, verifierAspect, txAspect) - remainingGas = leftover - return + // remove old version aspect from account bound list + accountStore.TransferGasFrom(metaStore) + if err := accountStore.RemoveBinding(aspectID, currentVersionMeta.JoinPoint, isContract); err != nil { + return nil, 0, err + } + + // update new binding in account store + if err := accountStore.StoreBinding(aspectID, version, newVersionMeta.JoinPoint, bindingInfo.Priority, isContract); err != nil { + return nil, 0, err + } + + return nil, accountStore.Gas(), nil } func (c ChangeVersionHandler) Method() string { @@ -520,19 +672,7 @@ func (c ChangeVersionHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) return } - // should check whether expected version is greater than - // the latest version we have, if so, the designated aspect - // does not exist yet version = ctx.parameters["version"].(uint64) - store := ctx.service.aspectStore - latestVersion := store.GetAspectLastVersion(ctx.cosmosCtx, aspectId) - if latestVersion == nil || latestVersion.Cmp(zero) == 0 || latestVersion.Uint64() < version { - err = errors.New("given version of aspect does not exist") - return - } - if version == 0 { - version = latestVersion.Uint64() - } if isContract = len(ctx.evmState.GetCode(account)) > 0; isContract { var isOwner bool @@ -551,19 +691,28 @@ func (c ChangeVersionHandler) decodeAndValidate(ctx *HandlerContext, gas uint64) type GetVersionHandler struct{} func (g GetVersionHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, err := g.decodeAndValidate(ctx) + aspectID, err := g.decodeAndValidate(ctx) + if err != nil { + return nil, 0, err + } + + // no need to get new version store, since we only do auto migration during aspect upgrade + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, gas)) if err != nil { return nil, 0, err } - version := ctx.service.aspectStore.GetAspectLastVersion(ctx.cosmosCtx, aspectId) + version, err := metaStore.GetLatestVersion() + if err != nil { + return nil, 0, err + } - ret, err = ctx.abi.Outputs.Pack(version.Uint64()) + ret, err = ctx.abi.Outputs.Pack(version) if err != nil { return nil, gas, err } - return ret, gas, nil + return ret, metaStore.Gas(), nil } func (g GetVersionHandler) Method() string { @@ -588,49 +737,29 @@ func (g GetBindingHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, return nil, 0, err } - aspectInfo := make([]types.AspectInfo, 0) - deduplicationMap := make(map[common.Address]struct{}) + // init account store + accountStore, _, err := store.GetAccountStore(buildAccountStoreCtx(ctx, account, gas)) + if err != nil { + return nil, 0, err + } - accountVerifiers, err := ctx.service.aspectStore.GetVerificationAspects(ctx.cosmosCtx, account) + bindings, err := accountStore.LoadAccountBoundAspects(aspectmoduletypes.NewDefaultFilter(isContract)) if err != nil { return nil, 0, err } - for _, aspect := range accountVerifiers { - if _, exist := deduplicationMap[aspect.Id]; exist { - continue - } - deduplicationMap[aspect.Id] = struct{}{} + aspectInfo := make([]types.AspectInfo, 0) + for _, binding := range bindings { info := types.AspectInfo{ - AspectId: aspect.Id, - Version: aspect.Version.Uint64(), - Priority: int8(aspect.Priority), + AspectId: binding.Account, + Version: binding.Version, + Priority: binding.Priority, } aspectInfo = append(aspectInfo, info) } - if isContract { - txLevelAspects, err := ctx.service.aspectStore.GetTxLevelAspects(ctx.cosmosCtx, account) - if err != nil { - return nil, 0, err - } - - for _, aspect := range txLevelAspects { - if _, exist := deduplicationMap[aspect.Id]; exist { - continue - } - deduplicationMap[aspect.Id] = struct{}{} - info := types.AspectInfo{ - AspectId: aspect.Id, - Version: aspect.Version.Uint64(), - Priority: int8(aspect.Priority), - } - aspectInfo = append(aspectInfo, info) - } - } - ret, err = ctx.abi.Outputs.Pack(aspectInfo) - return ret, gas, err + return ret, accountStore.Gas(), err } func (g GetBindingHandler) Method() string { @@ -651,21 +780,32 @@ func (g GetBindingHandler) decodeAndValidate(ctx *HandlerContext) (account commo type GetBoundAddressHandler struct{} func (g GetBoundAddressHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, err := g.decodeAndValidate(ctx) + aspectID, err := g.decodeAndValidate(ctx) if err != nil { return nil, 0, err } - value, err := ctx.service.GetAspectOf(ctx.cosmosCtx, aspectId) + // init account store + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, gas)) if err != nil { return nil, 0, err } + + // check deployment + if latestVersion, err := metaStore.GetLatestVersion(); err != nil { + return nil, 0, err + } else if latestVersion == 0 { + return nil, 0, errors.New("aspect not deployed") + } + + bindings, err := metaStore.LoadAspectBoundAccounts() + if err != nil { + return nil, 0, err + } + addressArr := make([]common.Address, 0) - if value != nil { - for _, data := range value.Values() { - contractAddr := common.HexToAddress(data.(string)) - addressArr = append(addressArr, contractAddr) - } + for _, binding := range bindings { + addressArr = append(addressArr, binding.Account) } ret, err = ctx.abi.Outputs.Pack(addressArr) @@ -683,26 +823,38 @@ func (g GetBoundAddressHandler) decodeAndValidate(ctx *HandlerContext) (aspectId return } - if !isAspectDeployed(ctx.cosmosCtx, ctx.service.aspectStore, aspectId) { - err = errors.New("aspect not deployed") - } - return } type OperationHandler struct{} func (o OperationHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, remainingGas uint64, err error) { - aspectId, args, err := o.decodeAndValidate(ctx) + aspectID, args, err := o.decodeAndValidate(ctx) if err != nil { return nil, 0, err } lastHeight := ctx.cosmosCtx.BlockHeight() - code, version := ctx.service.GetAspectCode(ctx.cosmosCtx, aspectId, nil) + metaStore, _, err := store.GetAspectMetaStore(buildAspectStoreCtx(ctx, aspectID, gas)) + if err != nil { + return nil, 0, err + } + + // check deployment + latestVersion, err := metaStore.GetLatestVersion() + if err != nil { + return nil, 0, err + } else if latestVersion == 0 { + return nil, 0, errors.New("aspect not deployed") + } + + code, err := metaStore.GetCode(latestVersion) + if err != nil { + return nil, 0, err + } aspectCtx := mustGetAspectContext(ctx.cosmosCtx) - runner, err := run.NewRunner(aspectCtx, ctx.logger, aspectId.String(), version.Uint64(), code, ctx.commit) + runner, err := run.NewRunner(aspectCtx, ctx.logger, aspectID.String(), latestVersion, code, ctx.commit) if err != nil { ctx.logger.Error("failed to create aspect runner", "error", err) return nil, 0, err @@ -715,10 +867,10 @@ func (o OperationHandler) Handle(ctx *HandlerContext, gas uint64) (ret []byte, r txHash = ethTxCtx.TxContent().Hash().Bytes() } height := uint64(lastHeight) - ret, remainingGas, err = runner.JoinPoint(artelasdkType.OPERATION_METHOD, gas, lastHeight, aspectId, &artelasdkType.OperationInput{ + ret, remainingGas, err = runner.JoinPoint(artelasdkType.OPERATION_METHOD, gas, lastHeight, aspectID, &artelasdkType.OperationInput{ Tx: &artelasdkType.WithFromTxInput{ Hash: txHash, - To: aspectId.Bytes(), + To: aspectID.Bytes(), From: ctx.from.Bytes(), }, Block: &artelasdkType.BlockInput{Number: &height}, @@ -745,29 +897,20 @@ func (o OperationHandler) decodeAndValidate(ctx *HandlerContext) (aspectId commo return } - if !isAspectDeployed(ctx.cosmosCtx, ctx.service.aspectStore, aspectId) { - err = errors.New("aspect not deployed") - return - } - args = ctx.parameters["optArgs"].([]byte) return } -func isAspectDeployed(ctx sdk.Context, store *AspectStore, aspectId common.Address) bool { - return store.GetAspectLastVersion(ctx, aspectId).Cmp(zero) > 0 -} - func validateCode(ctx sdk.Context, aspectCode []byte) ([]byte, error) { startTime := time.Now() - validator, err := runtime.NewValidator(ctx, artool.WrapLogger(ctx.Logger()), runtime.WASM) + validator, err := runtime.NewValidator(ctx, arttool.WrapLogger(ctx.Logger()), runtime.WASM) if err != nil { return nil, err } ctx.Logger().Info("validated aspect bytecode", "duration", time.Since(startTime).String()) startTime = time.Now() - parsed, err := ParseByteCode(aspectCode) + parsed, err := asptool.ParseByteCode(aspectCode) if err != nil { return nil, err } @@ -814,9 +957,9 @@ func checkContractOwner(ctx *HandlerContext, contractAddr common.Address, gas ui return result, leftover } -func checkAspectOwner(ctx sdk.Context, aspectId common.Address, sender common.Address, gas uint64, code []byte, version *uint256.Int, commit bool) (bool, uint64, error) { +func checkAspectOwner(ctx sdk.Context, aspectId common.Address, sender common.Address, gas uint64, code []byte, version uint64, commit bool) (bool, uint64, error) { aspectCtx := mustGetAspectContext(ctx) - runner, err := run.NewRunner(aspectCtx, artool.WrapLogger(ctx.Logger()), aspectId.String(), version.Uint64(), code, commit) + runner, err := run.NewRunner(aspectCtx, arttool.WrapLogger(ctx.Logger()), aspectId.String(), version, code, commit) if err != nil { panic(fmt.Sprintf("failed to create runner: %v", err)) } @@ -834,3 +977,17 @@ func mustGetAspectContext(ctx sdk.Context) *types.AspectRuntimeContext { return aspectCtx } + +func buildAspectStoreCtx(ctx *HandlerContext, aspectID common.Address, gas uint64) *aspectmoduletypes.AspectStoreContext { + return &aspectmoduletypes.AspectStoreContext{ + StoreContext: aspectmoduletypes.NewStoreContext(ctx.cosmosCtx, ctx.storeService, ctx.aspectStoreService, gas), + AspectID: aspectID, + } +} + +func buildAccountStoreCtx(ctx *HandlerContext, account common.Address, gas uint64) *aspectmoduletypes.AccountStoreContext { + return &aspectmoduletypes.AccountStoreContext{ + StoreContext: aspectmoduletypes.NewStoreContext(ctx.cosmosCtx, ctx.storeService, ctx.aspectStoreService, gas), + Account: account, + } +} diff --git a/x/evm/artela/contract/service.go b/x/evm/artela/contract/service.go deleted file mode 100644 index 66394e3..0000000 --- a/x/evm/artela/contract/service.go +++ /dev/null @@ -1,146 +0,0 @@ -package contract - -import ( - "math/big" - - "cosmossdk.io/core/store" - "cosmossdk.io/log" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/emirpasic/gods/sets/treeset" - "github.com/ethereum/go-ethereum/common" - "github.com/holiman/uint256" - "github.com/pkg/errors" - - artela "github.com/artela-network/aspect-core/types" - - evmtypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" -) - -type AspectService struct { - aspectStore *AspectStore - getHeight evmtypes.GetLastBlockHeight -} - -func NewAspectService(storeService store.KVStoreService, - getHeight evmtypes.GetLastBlockHeight, logger log.Logger) *AspectService { - return &AspectService{ - aspectStore: NewAspectStore(storeService, logger), - getHeight: getHeight, - } -} - -func (service *AspectService) GetAspectOf(ctx sdk.Context, aspectId common.Address) (*treeset.Set, error) { - aspects, err := service.aspectStore.GetAspectRefValue(ctx, aspectId) - if err != nil { - return nil, errors.Wrap(err, "load aspect ref failed") - } - return aspects, nil -} - -func (service *AspectService) GetAspectCode(ctx sdk.Context, aspectId common.Address, version *uint256.Int) ([]byte, *uint256.Int) { - if version == nil || version.Cmp(zero) <= 0 { - version = service.aspectStore.GetAspectLastVersion(ctx, aspectId) - } - return service.aspectStore.GetAspectCode(ctx, aspectId, version) -} - -func (service *AspectService) GetBoundAspectForAddr(sdkCtx sdk.Context, to common.Address) ([]*artela.AspectCode, error) { - aspects, err := service.aspectStore.GetTxLevelAspects(sdkCtx, to) - if err != nil { - return nil, errors.Wrap(err, "load contract aspect binding failed") - } - aspectCodes := make([]*artela.AspectCode, 0, len(aspects)) - if aspects == nil { - return aspectCodes, nil - } - for _, aspect := range aspects { - codeBytes, ver := service.aspectStore.GetAspectCode(sdkCtx, aspect.Id, nil) - aspectCode := &artela.AspectCode{ - AspectId: aspect.Id.String(), - Priority: uint32(aspect.Priority), - Version: ver.Uint64(), - Code: codeBytes, - } - aspectCodes = append(aspectCodes, aspectCode) - } - return aspectCodes, nil -} - -// GetAspectsForJoinPoint BoundAspects get bound Aspects on previous block -func (service *AspectService) GetAspectsForJoinPoint(ctx sdk.Context, to common.Address, cut artela.PointCut) ([]*artela.AspectCode, error) { - aspects, err := service.aspectStore.GetTxLevelAspects(ctx, to) - - if err != nil { - return nil, errors.Wrap(err, "load contract aspect binding failed") - } - - aspectCodes := make([]*artela.AspectCode, 0, len(aspects)) - if aspects == nil { - return aspectCodes, nil - } - for _, aspect := range aspects { - // check if the Join point has run permissions - jp, err := service.aspectStore.GetAspectJP(ctx, aspect.Id, nil) - if err != nil { - return nil, err - } - - if !artela.CanExecPoint(jp.Int64(), cut) { - continue - } - codeBytes, ver := service.aspectStore.GetAspectCode(ctx, aspect.Id, nil) - aspectCode := &artela.AspectCode{ - AspectId: aspect.Id.String(), - Priority: uint32(aspect.Priority), - Version: ver.Uint64(), - Code: codeBytes, - } - aspectCodes = append(aspectCodes, aspectCode) - } - - return aspectCodes, nil -} - -// GetAccountVerifiers gets the bound Aspect verifier for the account -func (service *AspectService) GetAccountVerifiers(ctx sdk.Context, to common.Address) ([]*artela.AspectCode, error) { - aspects, err := service.aspectStore.GetVerificationAspects(ctx, to) - if err != nil { - return nil, errors.Wrap(err, "load contract aspect binding failed") - } - aspectCodes := make([]*artela.AspectCode, 0, len(aspects)) - if aspects == nil { - return aspectCodes, nil - } - for _, aspect := range aspects { - // check if the verify point has run permissions - jp, err := service.aspectStore.GetAspectJP(ctx, aspect.Id, nil) - if err != nil { - return nil, err - } - - if !artela.CanExecPoint(jp.Int64(), artela.VERIFY_TX) { - continue - } - codeBytes, ver := service.aspectStore.GetAspectCode(ctx, aspect.Id, nil) - aspectCode := &artela.AspectCode{ - AspectId: aspect.Id.String(), - Priority: uint32(aspect.Priority), - Version: ver.Uint64(), - Code: codeBytes, - } - aspectCodes = append(aspectCodes, aspectCode) - } - return aspectCodes, nil -} - -func (service *AspectService) GetBlockHeight() int64 { - return service.getHeight() -} - -func (service *AspectService) GetAspectJoinPoint(ctx sdk.Context, aspectId common.Address, version *uint256.Int) (*big.Int, error) { - - if version == nil { - version = service.aspectStore.GetAspectLastVersion(ctx, aspectId) - } - return service.aspectStore.GetAspectJP(ctx, aspectId, version) -} diff --git a/x/evm/artela/contract/store.go b/x/evm/artela/contract/store.go deleted file mode 100644 index 79c8761..0000000 --- a/x/evm/artela/contract/store.go +++ /dev/null @@ -1,663 +0,0 @@ -package contract - -import ( - "bytes" - "encoding/json" - "errors" - "math" - "math/big" - "sort" - "strings" - - "cosmossdk.io/core/store" - "cosmossdk.io/log" - "cosmossdk.io/store/prefix" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/emirpasic/gods/sets/treeset" - "github.com/holiman/uint256" - "golang.org/x/exp/slices" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - - artelasdkType "github.com/artela-network/aspect-core/types" - runtimeTypes "github.com/artela-network/aspect-runtime/types" - - "github.com/artela-network/artela-rollkit/x/evm/artela/types" - evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" -) - -const ( - storageLoadCost = 50 - storageStoreCost = 20000 - storageSaveCodeCost = 1000 - storageUpdateCost = 5000 -) - -type gasMeter struct { - gas uint64 -} - -func newGasMeter(gas uint64) *gasMeter { - return &gasMeter{ - gas: gas, - } -} - -func (m *gasMeter) measureStorageUpdate(dataLen int) error { - return m.consume(dataLen, storageUpdateCost) -} - -func (m *gasMeter) measureStorageCodeSave(dataLen int) error { - return m.consume(dataLen, storageSaveCodeCost) -} - -func (m *gasMeter) measureStorageStore(dataLen int) error { - return m.consume(dataLen, storageStoreCost) -} - -func (m *gasMeter) measureStorageLoad(dataLen int) error { - return m.consume(dataLen, storageLoadCost) -} - -func (m *gasMeter) remainingGas() uint64 { - return m.gas -} - -func (m *gasMeter) consume(dataLen int, gasCostPer32Bytes uint64) error { - gas := ((uint64(dataLen) + 32) >> 5) * gasCostPer32Bytes - if m.gas < gas { - m.gas = 0 - return runtimeTypes.OutOfGasError - } - m.gas -= gas - return nil -} - -type AspectStore struct { - storeService store.KVStoreService - logger log.Logger -} - -type bindingQueryFunc func(sdk.Context, common.Address) ([]*types.AspectMeta, error) - -func NewAspectStore(storeService store.KVStoreService, logger log.Logger) *AspectStore { - return &AspectStore{ - storeService: storeService, - logger: logger, - } -} - -func (k *AspectStore) newPrefixStore(ctx sdk.Context, fixKey string) prefix.Store { - return prefix.NewStore(runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)), evmtypes.KeyPrefix(fixKey)) -} - -func (k *AspectStore) BumpAspectVersion(ctx sdk.Context, aspectID common.Address, gas uint64) (*uint256.Int, uint64, error) { - meter := newGasMeter(gas) - version := k.getAspectLastVersion(ctx, aspectID) - - newVersion := version.Add(version, uint256.NewInt(1)) - if err := k.storeAspectVersion(ctx, aspectID, newVersion, meter); err != nil { - return nil, meter.remainingGas(), err - } - - return newVersion, meter.remainingGas(), nil -} - -// StoreAspectCode aspect code -func (k *AspectStore) StoreAspectCode(ctx sdk.Context, aspectID common.Address, code []byte, version *uint256.Int, gas uint64) (uint64, error) { - meter := newGasMeter(gas) - if err := meter.measureStorageCodeSave(len(code)); err != nil { - return meter.remainingGas(), err - } - - // store code - codeStore := k.newPrefixStore(ctx, types.AspectCodeKeyPrefix) - versionKey := types.AspectVersionKey( - aspectID.Bytes(), - version.Bytes(), - ) - codeStore.Set(versionKey, code) - - k.logger.Info("saved aspect code", "id", aspectID.Hex(), "version", version.String()) - return meter.remainingGas(), nil -} - -func (k *AspectStore) GetAspectCode(ctx sdk.Context, aspectId common.Address, version *uint256.Int) ([]byte, *uint256.Int) { - codeStore := k.newPrefixStore(ctx, types.AspectCodeKeyPrefix) - if version == nil { - version = k.getAspectLastVersion(ctx, aspectId) - } - - if version.Cmp(zero) == 0 { - return nil, zero - } - - versionKey := types.AspectVersionKey( - aspectId.Bytes(), - version.Bytes(), - ) - code := codeStore.Get(versionKey) - - // stored code is already validated, so we can ignore the error here - parsed, _ := ParseByteCode(code) - - return parsed, version -} - -// storeAspectVersion version -func (k *AspectStore) storeAspectVersion(ctx sdk.Context, aspectId common.Address, version *uint256.Int, meter *gasMeter) error { - var err error - if version.Cmp(one) == 0 { - err = meter.measureStorageStore(32) - } else { - err = meter.measureStorageUpdate(32) - } - if err != nil { - return err - } - - versionStore := k.newPrefixStore(ctx, types.AspectCodeVersionKeyPrefix) - versionKey := types.AspectIDKey(aspectId.Bytes()) - versionStore.Set(versionKey, version.Bytes()) - - k.logger.Info("saved aspect version info", "id", aspectId.Hex(), "version", version.String()) - return nil -} - -func (k *AspectStore) GetAspectLastVersion(ctx sdk.Context, aspectId common.Address) *uint256.Int { - return k.getAspectLastVersion(ctx, aspectId) -} - -func (k *AspectStore) getAspectLastVersion(ctx sdk.Context, aspectId common.Address) *uint256.Int { - aspectVersionStore := k.newPrefixStore(ctx, types.AspectCodeVersionKeyPrefix) - versionKey := types.AspectIDKey(aspectId.Bytes()) - version := uint256.NewInt(0) - if data := aspectVersionStore.Get(versionKey); data != nil || len(data) > 0 { - version.SetBytes(data) - } - - return version -} - -// StoreAspectProperty -// -// @Description: property storage format -// 1. {aspectid,key}=>{prperty value} -// 2. {aspectid,"AspectPropertyAllKeyPrefix"}=>"key1,key2,key3..." -// @receiver k -// @param ctx -// @param aspectId -// @param prop -// @return error -func (k *AspectStore) StoreAspectProperty(ctx sdk.Context, aspectId common.Address, prop []types.Property, gas uint64) (uint64, error) { - meter := newGasMeter(gas) - if len(prop) == 0 { - return gas, nil - } - - // get treemap value - aspectConfigStore := k.newPrefixStore(ctx, types.AspectPropertyKeyPrefix) - // get all property key - propertyAllKey, err := k.getAspectPropertyValue(ctx, aspectId, types.AspectPropertyAllKeyPrefix, meter) - if err != nil { - return meter.remainingGas(), err - } - - keySet := treeset.NewWithStringComparator() - // add propertyAllKey to keySet - if len(propertyAllKey) > 0 { - splitData := strings.Split(string(propertyAllKey), types.AspectPropertyAllKeySplit) - for _, datum := range splitData { - keySet.Add(datum) - } - } - for i := range prop { - key := prop[i].Key - // add key and deduplicate - keySet.Add(key) - } - // check key limit - if keySet.Size() > types.AspectPropertyLimit { - return meter.remainingGas(), errors.New("aspect property limit exceeds") - } - - // store property key - for i := range prop { - key := prop[i].Key - value := prop[i].Value - - if err := meter.measureStorageCodeSave(len(key) + len(value)); err != nil { - k.logger.Error("unable to save property", "err", err, "key", key, "value", value) - return meter.remainingGas(), err - } - - // store - aspectPropertyKey := types.AspectPropertyKey( - aspectId.Bytes(), - []byte(key), - ) - - aspectConfigStore.Set(aspectPropertyKey, value) - - k.logger.Info("aspect property updated", "aspect", aspectId.Hex(), "key", key, "value", value) - } - - // store AspectPropertyAllKey - keyAry := make([]string, keySet.Size()) - for i, key := range keySet.Values() { - keyAry[i] = key.(string) - } - join := strings.Join(keyAry, types.AspectPropertyAllKeySplit) - allPropertyKeys := types.AspectPropertyKey( - aspectId.Bytes(), - []byte(types.AspectPropertyAllKeyPrefix), - ) - aspectConfigStore.Set(allPropertyKeys, []byte(join)) - - return meter.remainingGas(), nil -} - -func (k *AspectStore) GetAspectPropertyValue(ctx sdk.Context, aspectId common.Address, propertyKey string, gas uint64) ([]byte, uint64, error) { - meter := newGasMeter(gas) - value, err := k.getAspectPropertyValue(ctx, aspectId, propertyKey, meter) - return value, meter.remainingGas(), err -} - -func (k *AspectStore) getAspectPropertyValue(ctx sdk.Context, aspectId common.Address, propertyKey string, meter *gasMeter) ([]byte, error) { - codeStore := k.newPrefixStore(ctx, types.AspectPropertyKeyPrefix) - aspectPropertyKey := types.AspectPropertyKey( - aspectId.Bytes(), - []byte(propertyKey), - ) - - value := codeStore.Get(aspectPropertyKey) - return value, meter.measureStorageLoad(len(propertyKey) + len(value)) -} - -func (k *AspectStore) BindTxAspect(ctx sdk.Context, account common.Address, aspectId common.Address, aspectVersion *uint256.Int, priority int8) error { - return k.saveBindingInfo(ctx, account, aspectId, aspectVersion, priority, - k.GetTxLevelAspects, types.ContractBindKeyPrefix, math.MaxUint8) -} - -func (k *AspectStore) BindVerificationAspect(ctx sdk.Context, account common.Address, aspectId common.Address, aspectVersion *uint256.Int, priority int8, isContractAccount bool) error { - // EoA can have multiple verifiers - limit := math.MaxUint8 - if isContractAccount { - // contract can have only 1 verifier - limit = 1 - } - - return k.saveBindingInfo(ctx, account, aspectId, aspectVersion, priority, - k.GetVerificationAspects, types.VerifierBindingKeyPrefix, limit) -} - -func (k *AspectStore) saveBindingInfo(ctx sdk.Context, account common.Address, aspectId common.Address, - aspectVersion *uint256.Int, priority int8, queryBinding bindingQueryFunc, bindingNameSpace string, limit int, -) error { - // check aspect existence - code, version := k.GetAspectCode(ctx, aspectId, aspectVersion) - if code == nil || version == nil { - return errors.New("aspect not found") - } - - // get transaction level aspect binding relationships - bindings, err := queryBinding(ctx, account) - if err != nil { - return err - } - - if len(bindings) >= limit { - return errors.New("binding limit exceeded") - } - - // check duplicates - for _, binding := range bindings { - if bytes.Equal(binding.Id.Bytes(), aspectId.Bytes()) { - return errors.New("aspect already bound") - } - } - - newAspect := &types.AspectMeta{ - Id: aspectId, - Version: version, - Priority: int64(priority), - } - - bindings = append(bindings, newAspect) - - // re-sort aspects by priority - if limit != 1 { - sort.Slice(bindings, types.NewBindingPriorityComparator(bindings)) - } - - jsonBytes, err := json.Marshal(bindings) - if err != nil { - return err - } - - // save bindings - aspectBindingStore := k.newPrefixStore(ctx, bindingNameSpace) - aspectPropertyKey := types.AccountKey( - account.Bytes(), - ) - aspectBindingStore.Set(aspectPropertyKey, jsonBytes) - - k.logger.Info("binding info saved", - "aspect", aspectId.Hex(), - "contract", account.Hex(), - "bindings", string(jsonBytes), - ) - - return nil -} - -func (k *AspectStore) UnBindContractAspects(ctx sdk.Context, contract common.Address, aspectId common.Address) error { - txAspectBindings, err := k.GetTxLevelAspects(ctx, contract) - if err != nil { - return err - } - toDelete := slices.IndexFunc(txAspectBindings, func(meta *types.AspectMeta) bool { - return bytes.Equal(meta.Id.Bytes(), aspectId.Bytes()) - }) - if toDelete < 0 { - // not found - return nil - } - txAspectBindings = slices.Delete(txAspectBindings, toDelete, toDelete+1) - jsonBytes, err := json.Marshal(txAspectBindings) - if err != nil { - return err - } - // store - contractBindingStore := k.newPrefixStore(ctx, types.ContractBindKeyPrefix) - - aspectPropertyKey := types.AccountKey( - contract.Bytes(), - ) - contractBindingStore.Set(aspectPropertyKey, jsonBytes) - - k.logger.Info("tx aspect unbound", "aspect", aspectId.Hex(), "contract", contract.String()) - return nil -} - -func (k *AspectStore) GetTxLevelAspects(ctx sdk.Context, contract common.Address) ([]*types.AspectMeta, error) { - return k.getAccountBondAspects(ctx, contract, types.ContractBindKeyPrefix) -} - -func (k *AspectStore) GetVerificationAspects(ctx sdk.Context, account common.Address) ([]*types.AspectMeta, error) { - return k.getAccountBondAspects(ctx, account, types.VerifierBindingKeyPrefix) -} - -func (k *AspectStore) getAccountBondAspects(ctx sdk.Context, account common.Address, bindingPrefix string) ([]*types.AspectMeta, error) { - // retrieve raw binding store - aspectBindingStore := k.newPrefixStore(ctx, bindingPrefix) - accountKey := types.AccountKey( - account.Bytes(), - ) - rawJSON := aspectBindingStore.Get(accountKey) - - var bindings []*types.AspectMeta - if len(rawJSON) == 0 { - return bindings, nil - } - if err := json.Unmarshal(rawJSON, &bindings); err != nil { - return nil, errors.New("failed to unmarshal aspect bindings") - } - return bindings, nil -} - -func (k *AspectStore) ChangeBoundAspectVersion(ctx sdk.Context, account common.Address, aspectId common.Address, version uint64, isContract, verifierAspect, txAspect bool) error { - bindingStoreKeys := make([]string, 0, 2) - bindingStoreKeys = append(bindingStoreKeys, types.VerifierBindingKeyPrefix) - if isContract { - bindingStoreKeys = append(bindingStoreKeys, types.ContractBindKeyPrefix) - } - - bindings := make(map[string][]*types.AspectMeta, len(bindingStoreKeys)) - bindingIndex := make(map[string]int, len(bindingStoreKeys)) - - bound := false - var priority int8 - for _, bindingStoreKey := range bindingStoreKeys { - binding, err := k.getAccountBondAspects(ctx, account, bindingStoreKey) - if err != nil { - return err - } - bindings[bindingStoreKey] = binding - - for i, aspect := range binding { - if bytes.Equal(aspect.Id.Bytes(), aspectId.Bytes()) { - bindingIndex[bindingStoreKey] = i - bound = true - priority = int8(aspect.Priority) - break - } - } - } - - if !bound { - return errors.New("aspect not bound") - } - - newBindingTypes := make(map[string]bool, 2) - newBindingTypes[types.VerifierBindingKeyPrefix] = verifierAspect - newBindingTypes[types.ContractBindKeyPrefix] = txAspect - u256Version := uint256.NewInt(version) - - for bindingStoreKey, binding := range bindings { - updateIdx, ok := bindingIndex[bindingStoreKey] - if !ok { - // join-point in the new version aspect has been changed, we need to add the new binding type - if newBindingTypes[bindingStoreKey] { - var err error - if bindingStoreKey == types.ContractBindKeyPrefix { - err = k.BindTxAspect(ctx, account, aspectId, u256Version, priority) - } else { - err = k.BindVerificationAspect(ctx, account, aspectId, u256Version, priority, isContract) - } - if err != nil { - k.logger.Error("failed to add new aspect binding type", "store", bindingStoreKey, "aspect", aspectId.Hex(), "version", version, "account", account.String()) - return err - } - k.logger.Info("added new binding type", "store", bindingStoreKey, "aspect", aspectId.Hex(), "version", version, "account", account.String()) - } - continue - } - - // join-point in the new version aspect has been changed, we need to remove the non-exist binding type - if !newBindingTypes[bindingStoreKey] { - var unbind func(ctx sdk.Context, contract common.Address, aspectId common.Address) error - if bindingStoreKey == types.ContractBindKeyPrefix { - unbind = k.UnBindContractAspects - } else { - unbind = k.UnBindVerificationAspect - } - - if err := unbind(ctx, account, aspectId); err != nil { - k.logger.Error("failed to remove aspect binding type", "store", bindingStoreKey, "aspect", aspectId.Hex(), "version", version, "account", account.String()) - return err - } - - k.logger.Info("removed binding type", "store", bindingStoreKey, "aspect", aspectId.Hex(), "version", version, "account", account.String()) - continue - } - - // join-point in the new version aspect not changed, we can just update the old one - oldVer := binding[updateIdx].Version.Uint64() - binding[updateIdx].Version = u256Version - - jsonBytes, err := json.Marshal(binding) - if err != nil { - return err - } - - bindingStore := k.newPrefixStore(ctx, bindingStoreKey) - bindingKey := types.AccountKey( - account.Bytes(), - ) - bindingStore.Set(bindingKey, jsonBytes) - - k.logger.Info("aspect bound version changed", "aspect", aspectId.Hex(), "account", account.String(), "old", oldVer, "new", version) - } - - return nil -} - -func (k *AspectStore) GetAspectRefValue(ctx sdk.Context, aspectId common.Address) (*treeset.Set, error) { - aspectRefStore := k.newPrefixStore(ctx, types.AspectRefKeyPrefix) - aspectPropertyKey := types.AspectIDKey( - aspectId.Bytes(), - ) - - rawTree := aspectRefStore.Get(aspectPropertyKey) - if rawTree == nil { - return nil, nil - } - - set := treeset.NewWithStringComparator() - if err := set.UnmarshalJSON(rawTree); err != nil { - return nil, err - } - return set, nil -} - -func (k *AspectStore) StoreAspectRefValue(ctx sdk.Context, account common.Address, aspectId common.Address) error { - dataSet, err := k.GetAspectRefValue(ctx, aspectId) - if err != nil { - return err - } - if dataSet == nil { - dataSet = treeset.NewWithStringComparator() - } - dataSet.Add(account.String()) - jsonBytes, err := dataSet.MarshalJSON() - if err != nil { - return err - } - // store - aspectRefStore := k.newPrefixStore(ctx, types.AspectRefKeyPrefix) - - aspectIdKey := types.AspectIDKey( - aspectId.Bytes(), - ) - aspectRefStore.Set(aspectIdKey, jsonBytes) - - k.logger.Info("aspect bound", "aspect", aspectId.Hex(), "account", account.Hex()) - return nil -} - -func (k *AspectStore) UnbindAspectRefValue(ctx sdk.Context, account common.Address, aspectId common.Address) error { - dataSet, err := k.GetAspectRefValue(ctx, aspectId) - if err != nil { - return err - } - if dataSet == nil { - return nil - } - // remove account - dataSet.Remove(account.String()) - // marshal set and put treemap with new blockHeight - jsonBytes, err := dataSet.MarshalJSON() - if err != nil { - return err - } - // store - aspectRefStore := k.newPrefixStore(ctx, types.AspectRefKeyPrefix) - aspectPropertyKey := types.AspectIDKey( - aspectId.Bytes(), - ) - aspectRefStore.Set(aspectPropertyKey, jsonBytes) - - k.logger.Info("aspect unbound", "aspect", aspectId.Hex(), "account", account.Hex()) - return nil -} - -func (k *AspectStore) UnBindVerificationAspect(ctx sdk.Context, account common.Address, aspectId common.Address) error { - bindings, err := k.GetVerificationAspects(ctx, account) - if err != nil { - return err - } - - toDelete := slices.IndexFunc(bindings, func(meta *types.AspectMeta) bool { - return bytes.Equal(meta.Id.Bytes(), aspectId.Bytes()) - }) - - if toDelete < 0 { - // not found - return nil - } - // delete existing - bindings = slices.Delete(bindings, toDelete, toDelete+1) - - sort.Slice(bindings, types.NewBindingPriorityComparator(bindings)) - jsonBytes, err := json.Marshal(bindings) - if err != nil { - return err - } - - // save bindings - aspectBindingStore := k.newPrefixStore(ctx, types.VerifierBindingKeyPrefix) - aspectPropertyKey := types.AccountKey( - account.Bytes(), - ) - aspectBindingStore.Set(aspectPropertyKey, jsonBytes) - - k.logger.Info("aspect unbound", "aspect", aspectId.Hex(), "account", account.String()) - return nil -} - -// StoreAspectJP -// -// @Description: Stores the execute conditions of the Aspect Join point. {aspectId,version,'AspectRunJoinPointKey'}==>{value} -// @receiver k -// @param ctx -// @param aspectId -// @param version: aspect version ,optional,Default Aspect last version -// @param point JoinPointRunType value, @see join_point_type.go -// @return bool Execute Result -func (k *AspectStore) StoreAspectJP(ctx sdk.Context, aspectId common.Address, version uint256.Int, point *big.Int) { - // check point - if _, ok := artelasdkType.CheckIsJoinPoint(point); !ok { - // Default store 0 - point = big.NewInt(0) - } - - aspectPropertyStore := k.newPrefixStore(ctx, types.AspectJoinPointRunKeyPrefix) - aspectPropertyKey := types.AspectArrayKey( - aspectId.Bytes(), - version.Bytes(), - []byte(types.AspectRunJoinPointKey), - ) - aspectPropertyStore.Set(aspectPropertyKey, point.Bytes()) -} - -// GetAspectJP -// -// @Description: get Aspect Join point run -// @receiver k -// @param ctx -// @param aspectId -// @param version -// @return *big.Int -func (k *AspectStore) GetAspectJP(ctx sdk.Context, aspectId common.Address, version *uint256.Int) (*big.Int, error) { - // Default last Aspect version - latestVersion := k.GetAspectLastVersion(ctx, aspectId) - if version == nil { - version = latestVersion - } else if version.Cmp(zero) < 0 || version.Cmp(latestVersion) > 0 { - return nil, errors.New("invalid aspect version") - } - - store := k.newPrefixStore(ctx, types.AspectJoinPointRunKeyPrefix) - aspectPropertyKey := types.AspectArrayKey( - aspectId.Bytes(), - version.Bytes(), - []byte(types.AspectRunJoinPointKey), - ) - jp := store.Get(aspectPropertyKey) - if len(jp) == 0 { - return new(big.Int), nil - } - return new(big.Int).SetBytes(jp), nil -} diff --git a/x/evm/artela/provider/artela.go b/x/evm/artela/provider/artela.go deleted file mode 100644 index 19f5959..0000000 --- a/x/evm/artela/provider/artela.go +++ /dev/null @@ -1,57 +0,0 @@ -package provider - -import ( - "context" - "errors" - - "cosmossdk.io/core/store" - "cosmossdk.io/log" - "github.com/ethereum/go-ethereum/common" - - asptypes "github.com/artela-network/aspect-core/types" - - "github.com/artela-network/artela-rollkit/x/evm/artela/contract" - "github.com/artela-network/artela-rollkit/x/evm/artela/types" -) - -var _ asptypes.AspectProvider = (*ArtelaProvider)(nil) - -type ArtelaProvider struct { - service *contract.AspectService - storeService store.KVStoreService -} - -func NewArtelaProvider(storeService store.KVStoreService, - getBlockHeight types.GetLastBlockHeight, - logger log.Logger, -) *ArtelaProvider { - service := contract.NewAspectService(storeService, getBlockHeight, logger) - - return &ArtelaProvider{service, storeService} -} - -func (j *ArtelaProvider) GetTxBondAspects(ctx context.Context, address common.Address, point asptypes.PointCut) ([]*asptypes.AspectCode, error) { - if ctx == nil { - return nil, errors.New("invalid Context") - } - aspectCtx, ok := ctx.(*types.AspectRuntimeContext) - if !ok { - return nil, errors.New("failed to unwrap AspectRuntimeContext from context.Context") - } - return j.service.GetAspectsForJoinPoint(aspectCtx.CosmosContext(), address, point) -} - -func (j *ArtelaProvider) GetAccountVerifiers(ctx context.Context, address common.Address) ([]*asptypes.AspectCode, error) { - if ctx == nil { - return nil, errors.New("invalid Context") - } - aspectCtx, ok := ctx.(*types.AspectRuntimeContext) - if !ok { - return nil, errors.New("failed to unwrap AspectRuntimeContext from context.Context") - } - return j.service.GetAccountVerifiers(aspectCtx.CosmosContext(), address) -} - -func (j *ArtelaProvider) GetLatestBlock() int64 { - return j.service.GetBlockHeight() -} diff --git a/x/evm/artela/types/aspect_store_key.go b/x/evm/artela/types/aspect_store_key.go deleted file mode 100644 index 7602462..0000000 --- a/x/evm/artela/types/aspect_store_key.go +++ /dev/null @@ -1,157 +0,0 @@ -package types - -import ( - "bytes" - "encoding/binary" - "math" - "strings" - - "github.com/emirpasic/gods/utils" - "github.com/holiman/uint256" - - "github.com/ethereum/go-ethereum/common" - - artela "github.com/artela-network/aspect-core/types" -) - -var _ binary.ByteOrder - -const ( - // AspectCodeKeyPrefix is the prefix to retrieve all AspectCodeStore - AspectCodeKeyPrefix = "AspectStore/Code/" - AspectCodeVersionKeyPrefix = "AspectStore/Version/" - AspectPropertyKeyPrefix = "AspectStore/Property/" - ContractBindKeyPrefix = "AspectStore/ContractBind/" - VerifierBindingKeyPrefix = "AspectStore/VerifierBind/" - AspectRefKeyPrefix = "AspectStore/AspectRef/" - AspectStateKeyPrefix = "AspectStore/State/" - - AspectJoinPointRunKeyPrefix = "AspectStore/JoinPointRun/" - - AspectIDMapKey = "aspectId" - VersionMapKey = "version" - PriorityMapKey = "priority" - - AspectAccountKey = "Aspect_@Acount@_" - AspectProofKey = "Aspect_@Proof@_" - AspectRunJoinPointKey = "Aspect_@Run@JoinPoint@_" - AspectPropertyAllKeyPrefix = "Aspect_@Property@AllKey@_" - AspectPropertyAllKeySplit = "^^^" - AspectPropertyLimit = math.MaxUint8 -) - -var ( - PathSeparator = []byte("/") - PathSeparatorLen = len(PathSeparator) -) - -func AspectArrayKey(keys ...[]byte) []byte { - var key []byte - for _, b := range keys { - key = append(key, b...) - key = append(key, PathSeparator...) - } - return key -} - -// AspectCodeStoreKey returns the store key to retrieve a AspectCodeStore from the index fields -func AspectPropertyKey( - aspectID []byte, - propertyKey []byte, -) []byte { - key := make([]byte, 0, len(aspectID)+PathSeparatorLen*2+len(propertyKey)) - - key = append(key, aspectID...) - key = append(key, PathSeparator...) - key = append(key, propertyKey...) - key = append(key, PathSeparator...) - - return key -} - -func AspectVersionKey( - aspectID []byte, - version []byte, -) []byte { - key := make([]byte, 0, len(aspectID)+PathSeparatorLen*2+len(version)) - - key = append(key, aspectID...) - key = append(key, PathSeparator...) - key = append(key, version...) - key = append(key, PathSeparator...) - - return key -} - -func AspectIDKey( - aspectID []byte, -) []byte { - key := make([]byte, 0, len(aspectID)+PathSeparatorLen) - key = append(key, aspectID...) - key = append(key, PathSeparator...) - - return key -} - -func AspectBlockKey() []byte { - var key []byte - key = append(key, []byte("AspectBlock")...) - key = append(key, PathSeparator...) - return key -} - -func AccountKey( - account []byte, -) []byte { - key := make([]byte, 0, len(account)+PathSeparatorLen) - key = append(key, account...) - key = append(key, PathSeparator...) - return key -} - -type AspectInfo struct { - AspectId common.Address `json:"AspectId"` - Version uint64 `json:"Version"` - Priority int8 `json:"Priority"` -} - -type AspectMeta struct { - Id common.Address `json:"id"` - Version *uint256.Int `json:"version"` - Priority int64 `json:"priority"` -} -type Property struct { - Key string `json:"Key"` - Value []byte `json:"Value"` -} - -type BoundAspectCode struct { - AspectId common.Address `json:"aspectId"` - Version *uint256.Int `json:"version"` - Priority int64 `json:"priority"` - Code []byte `json:"code"` -} - -func ByMapKeyPriority(a, b interface{}) int { - priorityA, ok := a.(map[string]interface{})[PriorityMapKey] - if !ok { - priorityA = 0 - } - priorityB, okb := b.(map[string]interface{})[PriorityMapKey] - if !okb { - priorityB = 1 - } - return utils.IntComparator(priorityA, priorityB) // "-" descending order -} - -func NewBindingPriorityComparator(x []*AspectMeta) func(i, j int) bool { - return func(i, j int) bool { - return x[i].Priority < x[j].Priority && (bytes.Compare(x[i].Id.Bytes(), x[j].Id.Bytes()) < 0) - } -} - -func NewBindingAspectPriorityComparator(x []*artela.AspectCode) func(i, j int) bool { - return func(i, j int) bool { - return (x[i].Priority < x[j].Priority) && (strings.Compare(x[i].AspectId, x[j].AspectId) < 0) - } -} diff --git a/x/evm/artela/types/context.go b/x/evm/artela/types/context.go index 3c04c49..6b790a4 100644 --- a/x/evm/artela/types/context.go +++ b/x/evm/artela/types/context.go @@ -2,27 +2,26 @@ package types import ( "context" + "encoding/hex" "fmt" "math/big" "sync" "time" - "cosmossdk.io/core/store" + cstore "cosmossdk.io/core/store" "cosmossdk.io/log" - "cosmossdk.io/store/prefix" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/runtime" cosmos "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/artela-network/artela-evm/vm" + "github.com/artela-network/artela-rollkit/x/aspect/store" + "github.com/artela-network/artela-rollkit/x/aspect/types" + statedb "github.com/artela-network/artela-rollkit/x/evm/states" inherent "github.com/artela-network/aspect-core/chaincoreext/jit_inherent" artelatypes "github.com/artela-network/aspect-core/types" - - statedb "github.com/artela-network/artela-rollkit/x/evm/states" - evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" ) const ( @@ -31,7 +30,10 @@ const ( AspectModuleName = "aspect" ) -var cachedStoreService store.KVStoreService +var ( + cachedStoreService cstore.KVStoreService + cachedAspectStoreService cstore.KVStoreService +) type GetLastBlockHeight func() int64 @@ -57,12 +59,13 @@ type GetLastBlockHeight func() int64 type AspectRuntimeContext struct { baseCtx context.Context - ethTxContext *EthTxContext - aspectContext *AspectContext - ethBlockContext *EthBlockContext - aspectState *AspectState - cosmosCtx *cosmos.Context - storeService store.KVStoreService + ethTxContext *EthTxContext + aspectContext *AspectContext + ethBlockContext *EthBlockContext + aspectState *AspectState + cosmosCtx *cosmos.Context + storeService cstore.KVStoreService + aspectStoreService cstore.KVStoreService logger log.Logger jitManager *inherent.Manager @@ -70,15 +73,18 @@ type AspectRuntimeContext struct { func NewAspectRuntimeContext() *AspectRuntimeContext { return &AspectRuntimeContext{ - aspectContext: NewAspectContext(), - storeService: cachedStoreService, - logger: log.NewNopLogger(), + aspectContext: NewAspectContext(), + storeService: cachedStoreService, + aspectStoreService: cachedAspectStoreService, + logger: log.NewNopLogger(), } } -func (c *AspectRuntimeContext) Init(storeService store.KVStoreService) { +func (c *AspectRuntimeContext) Init(storeService, aspectStoreService cstore.KVStoreService) { cachedStoreService = storeService + cachedAspectStoreService = aspectStoreService c.storeService = storeService + c.aspectStoreService = aspectStoreService } func (c *AspectRuntimeContext) WithCosmosContext(newTxCtx cosmos.Context) { @@ -104,7 +110,7 @@ func (c *AspectRuntimeContext) CosmosContext() cosmos.Context { return *c.cosmosCtx } -func (c *AspectRuntimeContext) StoreService() store.KVStoreService { +func (c *AspectRuntimeContext) StoreService() cstore.KVStoreService { return c.storeService } @@ -152,24 +158,31 @@ func (c *AspectRuntimeContext) ClearBlockContext() { } func (c *AspectRuntimeContext) CreateStateObject() { - c.aspectState = NewAspectState(*c.cosmosCtx, c.storeService, AspectStateKeyPrefix, c.logger) + c.aspectState = NewAspectState(*c.cosmosCtx, c.logger) +} + +func (c *AspectRuntimeContext) GetAspectProperty(ctx *artelatypes.RunnerContext, version uint64, key string) []byte { + metaStore, _, err := store.GetAspectMetaStore(&types.AspectStoreContext{ + StoreContext: types.NewGasFreeStoreContext(*c.cosmosCtx, cachedStoreService, cachedAspectStoreService), + AspectID: ctx.AspectId, + }) + if err != nil { + panic(err) + } + + data, err := metaStore.GetProperty(version, key) + if err != nil { + panic(err) + } + return data } func (c *AspectRuntimeContext) GetAspectState(ctx *artelatypes.RunnerContext, key string) []byte { - stateKey := AspectArrayKey( - ctx.AspectId.Bytes(), - []byte(key), - ) - return c.aspectState.Get(stateKey) + return c.aspectState.Get(ctx.AspectId, key) } func (c *AspectRuntimeContext) SetAspectState(ctx *artelatypes.RunnerContext, key string, value []byte) { - stateKey := AspectArrayKey( - ctx.AspectId.Bytes(), - []byte(key), - ) - - c.aspectState.Set(stateKey, value) + c.aspectState.Set(ctx.AspectId, key, value) } func (c *AspectRuntimeContext) Destroy() { @@ -400,44 +413,65 @@ func (c *AspectContext) Clear() { } type AspectState struct { - state prefix.Store - storeService store.KVStoreService - logger log.Logger + + ctx cosmos.Context + storeCache map[common.Address]store.AspectStateStore } -func NewAspectState(ctx cosmos.Context, storeService store.KVStoreService, fixKey string, logger log.Logger) *AspectState { - cacheStore := prefix.NewStore(runtime.KVStoreAdapter(storeService.OpenKVStore(ctx)), evmtypes.KeyPrefix(fixKey)) +func NewAspectState(ctx cosmos.Context, logger log.Logger) *AspectState { stateObj := &AspectState{ - state: cacheStore, - storeService: storeService, - logger: logger, + ctx: ctx, + logger: logger, + + storeCache: make(map[common.Address]store.AspectStateStore), } return stateObj } -func (k *AspectState) Set(key, value []byte) { +func (k *AspectState) Set(aspectID common.Address, key string, value []byte) { + s := k.newStoreFromCache(aspectID) + action := "updated" if len(value) == 0 { - k.state.Delete(key) action = "deleted" - } else { - k.state.Set(key, value) } + s.SetState([]byte(key), value) + if value == nil { - k.logger.Debug("setState:", "action", action, "key", string(key), "value", "nil") + k.logger.Debug("setState:", "action", action, "key", key, "value", "nil") } else { - k.logger.Debug("setState:", "action", action, "key", string(key), "value", string(value)) + k.logger.Debug("setState:", "action", action, "key", key, "value", hex.EncodeToString(value)) } } -func (k *AspectState) Get(key []byte) []byte { - val := k.state.Get(key) +func (k *AspectState) Get(aspectID common.Address, key string) []byte { + s := k.newStoreFromCache(aspectID) + val := s.GetState([]byte(key)) + if val == nil { - k.logger.Debug("getState:", "key", string(key), "value", "nil") + k.logger.Debug("getState:", "key", key, "value", "nil") } else { - k.logger.Debug("getState:", "key", string(key), "value", string(val)) + k.logger.Debug("getState:", "key", key, "value", string(val)) } return val } + +func (k *AspectState) newStoreFromCache(aspectID common.Address) store.AspectStateStore { + s, ok := k.storeCache[aspectID] + if !ok { + var err error + s, err = store.GetAspectStateStore(&types.AspectStoreContext{ + StoreContext: types.NewGasFreeStoreContext(k.ctx, cachedStoreService, cachedAspectStoreService), + AspectID: aspectID, + }) + if err != nil { + k.logger.Error("failed to get aspect state store", "err", err) + panic(err) + } + k.storeCache[aspectID] = s + } + + return s +} diff --git a/x/evm/artela/types/models.go b/x/evm/artela/types/models.go new file mode 100644 index 0000000..4cfc18d --- /dev/null +++ b/x/evm/artela/types/models.go @@ -0,0 +1,36 @@ +package types + +import ( + "bytes" + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" +) + +type AspectInfo struct { + AspectId common.Address `json:"AspectId"` + Version uint64 `json:"Version"` + Priority int8 `json:"Priority"` +} + +type AspectMeta struct { + Id common.Address `json:"id"` + Version *uint256.Int `json:"version"` + Priority int64 `json:"priority"` +} +type Property struct { + Key string `json:"Key"` + Value []byte `json:"Value"` +} + +type BoundAspectCode struct { + AspectId common.Address `json:"aspectId"` + Version *uint256.Int `json:"version"` + Priority int64 `json:"priority"` + Code []byte `json:"code"` +} + +func NewBindingPriorityComparator(x []*AspectMeta) func(i, j int) bool { + return func(i, j int) bool { + return x[i].Priority < x[j].Priority && (bytes.Compare(x[i].Id.Bytes(), x[j].Id.Bytes()) < 0) + } +} diff --git a/x/evm/artela/types/treemap_test.go b/x/evm/artela/types/treemap_test.go deleted file mode 100644 index ce51eec..0000000 --- a/x/evm/artela/types/treemap_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - "strings" - "testing" - - "github.com/emirpasic/gods/maps/hashmap" - "github.com/emirpasic/gods/maps/treemap" - pq "github.com/emirpasic/gods/queues/priorityqueue" -) - -func TestPriorityQueue(t *testing.T) { - /* a := BondAspect{AspectId: "1111", priority: 1} - b := BondAspect{AspectId: "22222", priority: -10} - c := BondAspect{AspectId: "3333", priority: 3} - */ - ma := make(map[string]interface{}, 2) - ma[AspectIDMapKey] = "1111" - ma[PriorityMapKey] = 1 - mb := make(map[string]interface{}, 2) - mb[AspectIDMapKey] = "2222" - mb[PriorityMapKey] = -10 - mc := make(map[string]interface{}, 2) - mc[AspectIDMapKey] = "3333" - mc[PriorityMapKey] = 3 - - queue := pq.NewWith(ByMapKeyPriority) // empty - queue.Enqueue(ma) // {a 1} - queue.Enqueue(mb) // {c 3}, {a 1} - queue.Enqueue(mc) // {c 3}, {b 2}, {a 1} - - values := queue.Values() - fmt.Println(values) - toJSON, _ := queue.MarshalJSON() - - queue2 := pq.NewWith(ByMapKeyPriority) - err := queue2.UnmarshalJSON(toJSON) - if err != nil { - fmt.Println(err) - } - v2 := queue2.Values() - fmt.Println(v2) - newQueue := pq.NewWith(ByMapKeyPriority) - - value, ok := queue.Dequeue() - for ok { - s, toStrOk := value.(map[string]interface{})["AspectId"].(string) - if toStrOk && strings.EqualFold("3333", s) { - break - } - newQueue.Enqueue(value) - value, ok = queue.Dequeue() - } - fmt.Println(newQueue.Values()) -} - -func TestTreemap(_ *testing.T) { - m := hashmap.New() - m.Put("a", "1") - m.Put("b", "2") - m.Put("c", "3") - - bytes, err := json.Marshal(m) // Same as "m.ToJSON(m)" - if err != nil { - fmt.Println(err) - } - fmt.Println(string(bytes)) - - hm := hashmap.New() - - err2 := json.Unmarshal(bytes, &hm) // Same as "hm.FromJSON(bytes)" - if err2 != nil { - fmt.Println(err2) - } - - fmt.Println(hm) // HashMap map[b:2 a:1] - - treem := treemap.NewWithIntComparator() // empty (keys are of type int) - treem.Put(1000, "v1.0") // 1->x - treem.Put(2000, "v2.0") // 1->x, 2->b (in order) - treem.Put(90000000, "a") - foundKey, foundValue := treem.Floor(4) - foundKey2, foundValue2 := treem.Floor(5) - foundKey3, foundValue3 := treem.Floor(6) - foundKey4, foundValue4 := treem.Floor(90000000) - foundKey5, foundValue5 := treem.Floor(90000001) - - bytes, err = json.Marshal(treem) // Same as "m.ToJSON(m)" - if err != nil { - fmt.Println(err) - } - fmt.Println(string(bytes)) - - comparator := treemap.NewWithIntComparator() - err = json.Unmarshal(bytes, &comparator) - if err != nil { - return - } - foundKey7, foundValue7 := comparator.Floor("90") - fmt.Print("%w, %w \n", foundKey, foundValue) - fmt.Print("%w, %w \n", foundKey2, foundValue2) - fmt.Print("%w, %w \n", foundKey3, foundValue3) - fmt.Print("%w, %w \n", foundKey4, foundValue4) - fmt.Print("%w, %w \n", foundKey5, foundValue5) - fmt.Print("%w, %w \n", foundKey7, foundValue7) - /* - m := treemap.NewWithIntComparator() // empty (keys are of type int) - m.Put(1, "x") // 1->x - m.Put(4, "b") // 1->x, 2->b (in order) - m.Put(90000000, "a") - - key, value := m.Floor(3) - key1, value1 := m.Floor(50) - fmt.Print("%w, %w \n", key, value) - fmt.Print("%w, %w \n", key1, value1) - bytes, err := json.Marshal(m) - if err == nil { - tree := treemap.NewWithIntComparator() - _ = json.Unmarshal(bytes, tree) - foundKey, foundValue := tree.Floor(90) - fmt.Print("%w, %w \n", foundKey, foundValue) - } - */ -} diff --git a/x/evm/keeper/aspect.go b/x/evm/keeper/aspect.go index 13ab50c..dc7a3d8 100644 --- a/x/evm/keeper/aspect.go +++ b/x/evm/keeper/aspect.go @@ -9,10 +9,6 @@ import ( artvmtype "github.com/artela-network/artela-rollkit/x/evm/artela/types" ) -func (k Keeper) GetAspectRuntimeContext() *artvmtype.AspectRuntimeContext { - return k.aspectRuntimeContext -} - func (k Keeper) JITSenderAspectByContext(ctx context.Context, userOpHash common.Hash) (common.Address, error) { return mustGetAspectCtx(ctx).JITManager().SenderAspect(userOpHash), nil } diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 89fe74f..5100370 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -384,8 +384,10 @@ func (k *Keeper) ApplyMessageWithConfig(ctx cosmos.Context, lastHeight := uint64(ctx.BlockHeight()) // if transaction is Aspect operational, short the circuit and skip the processes if isAspectOpTx := asptypes.IsAspectContractAddr(msg.To); isAspectOpTx { - nativeContract := contract.NewAspectNativeContract(k.storeService, evm, - ctx.BlockHeight, stateDB, k.logger) + nativeContract := contract.NewAspectNativeContract( + k.storeService, + k.aspectKeeper.GetStoreService(), + evm, stateDB, k.logger) nativeContract.Init() ret, leftoverGas, vmErr = nativeContract.ApplyMessage(ctx, msg, leftoverGas, commit) } else if contractCreation { @@ -393,6 +395,12 @@ func (k *Keeper) ApplyMessageWithConfig(ctx cosmos.Context, // - reset sender's nonce to msg.Nonce() before calling evm. // - increase sender's nonce by one no matter the result. stateDB.SetNonce(sender.Address(), msg.Nonce) + + // calculate the contract address and set to context + contractAddr := crypto.CreateAddress(sender.Address(), evm.StateDB.GetNonce(sender.Address())) + aspectCtx.WithCosmosContext(aspectCtx.CosmosContext().WithValue("msgFrom", msg.From)) + aspectCtx.WithCosmosContext(aspectCtx.CosmosContext().WithValue("msgTo", contractAddr)) + ret, _, leftoverGas, vmErr = evm.Create(aspectCtx, sender, msg.Data, leftoverGas, msg.Value) stateDB.SetNonce(sender.Address(), msg.Nonce+1) } else { @@ -416,6 +424,8 @@ func (k *Keeper) ApplyMessageWithConfig(ctx cosmos.Context, } } else { // execute evm call + aspectCtx.WithCosmosContext(aspectCtx.CosmosContext().WithValue("msgFrom", msg.From)) + aspectCtx.WithCosmosContext(aspectCtx.CosmosContext().WithValue("msgTo", *msg.To)) ret, leftoverGas, vmErr = evm.Call(aspectCtx, sender, *msg.To, msg.Data, leftoverGas, msg.Value) status := ethereum.ReceiptStatusSuccessful if vmErr != nil { diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 818d5f1..8984b0f 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -24,13 +24,13 @@ import ( ethereum "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - artelatypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" - "github.com/artela-network/artela-rollkit/common" artela "github.com/artela-network/artela-rollkit/ethereum/types" + "github.com/artela-network/artela-rollkit/x/aspect/provider" "github.com/artela-network/artela-rollkit/x/evm/artela/api" - "github.com/artela-network/artela-rollkit/x/evm/artela/provider" + artelatypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" artvmtype "github.com/artela-network/artela-rollkit/x/evm/artela/types" + "github.com/artela-network/artela-rollkit/x/evm/precompile/erc20" "github.com/artela-network/artela-rollkit/x/evm/states" "github.com/artela-network/artela-rollkit/x/evm/txs" "github.com/artela-network/artela-rollkit/x/evm/types" @@ -45,6 +45,7 @@ type ( bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper feeKeeper types.FeeKeeper + aspectKeeper types.AspectKeeper subSpace types.ParamSubspace blockGetter types.BlockGetter logger log.Logger @@ -73,6 +74,8 @@ type ( // cache of aspect sig VerifySigCache *sync.Map + + erc20Contract *erc20.ERC20Contract } ) @@ -84,11 +87,11 @@ func NewKeeper( bankKeeper types.BankKeeper, stakingKeeper types.StakingKeeper, feeKeeper types.FeeKeeper, + aspectKeeper types.AspectKeeper, blockGetter types.BlockGetter, chainIDGetter types.ChainIDGetter, logger log.Logger, authority string, - ) Keeper { if _, err := sdk.AccAddressFromBech32(authority); err != nil { panic(fmt.Sprintf("invalid authority address: %s", authority)) @@ -100,10 +103,10 @@ func NewKeeper( } // init aspect - aspect := provider.NewArtelaProvider(storeService, artvmtype.GetLastBlockHeight(blockGetter), logger) + aspect := provider.NewArtelaProvider(storeService, aspectKeeper.GetStoreService(), artvmtype.GetLastBlockHeight(blockGetter)) // new Aspect Runtime Context aspectRuntimeContext := artvmtype.NewAspectRuntimeContext() - aspectRuntimeContext.Init(storeService) + aspectRuntimeContext.Init(storeService, aspectKeeper.GetStoreService()) // pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations k := Keeper{ @@ -114,6 +117,7 @@ func NewKeeper( bankKeeper: bankKeeper, stakingKeeper: stakingKeeper, feeKeeper: feeKeeper, + aspectKeeper: aspectKeeper, storeService: storeService, transientStoreService: transientStoreService, tracer: "1", @@ -140,6 +144,8 @@ func NewKeeper( aspcoretype.JITSenderAspectByContext = k.JITSenderAspectByContext aspcoretype.IsCommit = k.IsCommit + + k.erc20Contract = erc20.InitERC20Contract(k.logger, cdc, k.storeService, k.bankKeeper) return k } @@ -198,7 +204,7 @@ func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom ethereum.Bloom) { encodedBloom := base64.StdEncoding.EncodeToString(bloom.Bytes()) sprintf := fmt.Sprintf("emit block event %d bloom %s header %d, ", len(bloom.Bytes()), encodedBloom, ctx.BlockHeight()) - k.Logger().Info(sprintf) + k.Logger().Debug(sprintf) ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/evm/keeper/meter.go b/x/evm/keeper/meter.go index 0050d98..8d12ec3 100644 --- a/x/evm/keeper/meter.go +++ b/x/evm/keeper/meter.go @@ -16,6 +16,7 @@ import ( "github.com/artela-network/aspect-core/djpm" + "github.com/artela-network/artela-rollkit/x/evm/states" "github.com/artela-network/artela-rollkit/x/evm/types" ) @@ -88,7 +89,15 @@ func (k *Keeper) DeductTxCostsFromUserBalance( // fetch sender account signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, from.Bytes()) if err != nil { - return errorsmod.Wrapf(err, "account not found for sender %s", from) + // if no gas fee, create an empty account for the address + if !fees.Empty() { + return errorsmod.Wrapf(err, "account not found for sender %s", from) + } + err := k.SetAccount(ctx, from, *states.NewEmptyAccount()) + if err != nil { + return errorsmod.Wrapf(err, "account not found for sender %s and failed to create %v", from, err) + } + signerAcc, _ = authante.GetSignerAcc(ctx, k.accountKeeper, from.Bytes()) } // deduct the full gas cost from the user balance diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 5d5f9cc..9a3c44e 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -13,7 +13,7 @@ import ( func setupMsgServer(t testing.TB) (keeper.Keeper, types.MsgServer, context.Context) { k, ctx := keepertest.EvmKeeper(t) - return k, keeper.NewMsgServerImpl(k), ctx + return k, keeper.NewMsgServerImpl(&k), ctx } func TestMsgServer(t *testing.T) { diff --git a/x/evm/keeper/query.go b/x/evm/keeper/query.go index bac11f1..b6c67c5 100644 --- a/x/evm/keeper/query.go +++ b/x/evm/keeper/query.go @@ -17,11 +17,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" ethereum "github.com/ethereum/go-ethereum/core/types" + ethparams "github.com/ethereum/go-ethereum/params" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - ethparams "github.com/ethereum/go-ethereum/params" - artela "github.com/artela-network/artela-rollkit/ethereum/types" artelatypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" "github.com/artela-network/artela-rollkit/x/evm/states" @@ -655,6 +654,22 @@ func (k Keeper) GetSender(c context.Context, in *types.MsgEthereumTx) (*types.Ge return &types.GetSenderResponse{Sender: sender.String()}, nil } +func (k Keeper) AddressByDenom(c context.Context, req *types.AddressByDenomRequest) (*types.AddressByDenomResponse, error) { + ctx := cosmos.UnwrapSDKContext(c) + addrs, err := k.erc20Contract.GetProxyByDenom(ctx, req.Denom) + if err != nil { + return nil, err + } + + return &types.AddressByDenomResponse{Address: addrs}, nil +} + +func (k Keeper) DenomByAddress(c context.Context, req *types.DenomByAddressRequest) (*types.DenomByAddressResponse, error) { + ctx := cosmos.UnwrapSDKContext(c) + denom := k.erc20Contract.GetDenomByProxy(ctx, common.HexToAddress(req.Address)) + return &types.DenomByAddressResponse{Denom: denom}, nil +} + // getChainID parse chainID from current context if not provided func getChainID(ctx cosmos.Context, chainID int64) (*big.Int, error) { if chainID == 0 { diff --git a/x/evm/module/genesis_test.go b/x/evm/module/genesis_test.go index 19ccc5b..01d917a 100644 --- a/x/evm/module/genesis_test.go +++ b/x/evm/module/genesis_test.go @@ -7,6 +7,7 @@ import ( "github.com/artela-network/artela-rollkit/testutil/nullify" evm "github.com/artela-network/artela-rollkit/x/evm/module" "github.com/artela-network/artela-rollkit/x/evm/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/stretchr/testify/require" ) @@ -19,8 +20,9 @@ func TestGenesis(t *testing.T) { } k, ctx := keepertest.EvmKeeper(t) - evm.InitGenesis(ctx, k, genesisState) - got := evm.ExportGenesis(ctx, k) + ak := authkeeper.AccountKeeper{} + evm.InitGenesis(ctx, k, ak, genesisState) + got := evm.ExportGenesis(ctx, k, ak) require.NotNil(t, got) nullify.Fill(&genesisState) diff --git a/x/evm/module/module.go b/x/evm/module/module.go index 504b81c..4cbf6e1 100644 --- a/x/evm/module/module.go +++ b/x/evm/module/module.go @@ -17,6 +17,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" + // this line is used by starport scaffolding # 1 modulev1 "github.com/artela-network/artela-rollkit/api/artela/evm/module" @@ -187,6 +188,7 @@ type ModuleInputs struct { BankKeeper types.BankKeeper StakingKeeper types.StakingKeeper FeeKeeper types.FeeKeeper + AspectKeeper types.AspectKeeper BlockGetter types.BlockGetter ChainIDGetter types.ChainIDGetter @@ -205,6 +207,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { if in.Config.Authority != "" { authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority) } + k := keeper.NewKeeper( in.Cdc, in.StoreService, @@ -213,6 +216,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { in.BankKeeper, in.StakingKeeper, in.FeeKeeper, + in.AspectKeeper, in.BlockGetter, in.ChainIDGetter, in.Logger, diff --git a/x/evm/precompile/contracts.go b/x/evm/precompile/contracts.go new file mode 100644 index 0000000..e936395 --- /dev/null +++ b/x/evm/precompile/contracts.go @@ -0,0 +1,18 @@ +package precompiled + +import ( + "github.com/artela-network/artela-evm/vm" + "github.com/ethereum/go-ethereum/common" +) + +func RegisterPrecompiles(address common.Address, p vm.PrecompiledContract) { + vm.PrecompiledContractsHomestead[address] = p + vm.PrecompiledContractsByzantium[address] = p + vm.PrecompiledContractsIstanbul[address] = p + vm.PrecompiledContractsBerlin[address] = p + + vm.PrecompiledAddressesHomestead = append(vm.PrecompiledAddressesHomestead, address) + vm.PrecompiledAddressesByzantium = append(vm.PrecompiledAddressesByzantium, address) + vm.PrecompiledAddressesIstanbul = append(vm.PrecompiledAddressesIstanbul, address) + vm.PrecompiledAddressesBerlin = append(vm.PrecompiledAddressesBerlin, address) +} diff --git a/x/evm/precompile/erc20.md b/x/evm/precompile/erc20.md new file mode 100644 index 0000000..a954b79 --- /dev/null +++ b/x/evm/precompile/erc20.md @@ -0,0 +1,91 @@ +# IBC -> ERC20 Mapping + +This document introduces the design, structure, working principles, and how to use the ERC20 protocol to interact with IBC assets transferred across chains. + +## Design and Structure + +Design document references: + +[Overview Design](https://forum.artela.network/t/erc20-wrapper-of-x-bank-module-allows-eoas-and-smart-contracts-on-evm-to-interact-with-the-bank-module-through-the-wrapper-contract/12/6) + +[Detailed Design](https://forum.artela.network/t/detailed-desgined-of-ibc-erc20/13/13) + +### Goals + +The integration of IBC (Inter-Blockchain Communication) and ERC20 (Ethereum’s token standard) provides an efficient and simple management method for cross-chain asset transfer. By implementing ERC20 mapping, Cosmos ecosystem tokens (such as ATOM) can be managed using the ERC20 protocol on Artela. + +### Key Components + +- **Proxy**: An ERC20-compatible proxy for IBC assets, where all operations for IBC assets are carried out through this contract interface. +- **erc20.go**: This is an implementation of the proxy interface, used to wrap Cosmos tokens on Ethereum-compatible chains to comply with the ERC20 standard. It allows Cosmos tokens to interact with Ethereum DApps and smart contracts. +- **store.go**: Used to manage the relationship pairs between IBC and ERC20. + +### Mapping Process + +1. **Native Token Transfer**: The user initiates a transfer on the Cosmos chain and transfers tokens through IBC to the Artela chain. +2. **ERC20 Mapping Contract**: Query the denomination of the transferred asset on Artela. A proxy contract is manually deployed on Artela, and the address of this proxy contract is the ERC20 interface contract corresponding to the asset. +3. **Transfer**: Call the deployed proxy contract to transfer assets, and the underlying IBC asset will be transferred accordingly. + +## Working Principle + +### 1. IBC Transfer + +When an IBC transfer is initiated on the Cosmos chain, the user generates a cross-chain transfer request via a Cosmos wallet and sends the tokens to an IBC transfer relay chain. This chain forwards the message to the target chain, where the target chain verifies the signature, checks the transfer status, and ensures the cross-chain transfer is legitimate. + +### 2. Deploying the ERC20 Proxy Contract + +The ERC20 Proxy contract on the target chain acts as a bridge between Cosmos tokens and ERC20 tokens. It allows users to interact with the underlying IBC assets using the ERC20 protocol on the target chain. The ERC20 Proxy contract is located in `x/evm/precompile/erc20/proxy/ERC20Proxy.sol`, and the denomination specified in the constructor corresponds to the IBC asset’s denomination. + +### 3. Token Mapping + +By freely mapping IBC assets to the ERC20 interface, the underlying IBC assets can circulate through the ERC20 protocol. The ERC20 standard serves as the mapping for the IBC asset. + +## Usage + +### Deploying the ERC20 Wrapper Contract + +To deploy the ERC20 Wrapper contract on the target chain, follow these steps: + +1. **IBC Transfer** + + Use the Cosmos IBC transfer protocol to transfer assets from other chains to Artela, using wallets like Keplr. + +2. **Query Transferred Assets** + + Use `artelad query bank balances {cosmos address}` to query the denomination of the asset to be mapped. For example, the query structure is as follows: + + ```sh + artelad query bank balances art1dsgnmxpeuwsuvrc92qyy2v6jgsu2clajnfsxee + balances: + - amount: "1" + denom: ibc/725907476F79A96A2650A4D124501B5D236AB9DDFAF216F929833C6B51E42902 + - amount: "999999999999999999999" + denom: uart + pagination: + next_key: null + total: "0" + ``` + +3. **Deploy the Wrapper Contract** + + Deploy the `x/evm/precompile/erc20/proxy/ERC20Proxy.sol` contract, where the constructor parameter specifies the IBC asset to be mapped (in this example, `ibc/725907476F79A96A2650A4D124501B5D236AB9DDFAF216F929833C6B51E42902`). + Copy the address of the deployed contract. + | If a mapping contract already exists, you can query the contract address. See step 5 for the query method. + +4. **Use ERC20** + + Import the contract address from step 3 into your wallet and add it as an asset. You can then use this asset for querying or transferring. + +5. **Query the Mapped Token Pairs** + + a. Query the mapped contract address by the denomination: + + ```sh + curl localhost:8545 -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_getAddressByDenom","params":["{ibc denom}", "latest"],"id":1}' + ``` + + b. Query the denomination by the contract address: + + ```sh + curl localhost:8545 -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_getDenomByAddress","params":["{proxy address}", "latest"],"id":1}' + ``` diff --git a/x/evm/precompile/erc20/erc20.go b/x/evm/precompile/erc20/erc20.go new file mode 100644 index 0000000..1981878 --- /dev/null +++ b/x/evm/precompile/erc20/erc20.go @@ -0,0 +1,213 @@ +package erc20 + +import ( + "context" + "errors" + "math/big" + "strings" + + cstore "cosmossdk.io/core/store" + "cosmossdk.io/log" + "cosmossdk.io/math" + "github.com/artela-network/artela-evm/vm" + artelatypes "github.com/artela-network/artela-rollkit/x/evm/artela/types" + precompiled "github.com/artela-network/artela-rollkit/x/evm/precompile" + "github.com/artela-network/artela-rollkit/x/evm/precompile/erc20/proxy" + "github.com/artela-network/artela-rollkit/x/evm/precompile/erc20/types" + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +var ( + _ vm.PrecompiledContract = (*ERC20Contract)(nil) +) + +type APIMethod func(sdk.Context, common.Address, common.Address, map[string]interface{}) ([]byte, error) + +type ERC20Contract struct { + logger log.Logger + storeService cstore.KVStoreService + cdc codec.BinaryCodec + + tokenPairs types.TokenPairs // TODO cache the token pairs + bankKeeper evmtypes.BankKeeper + methods map[string]APIMethod + proxyABI abi.ABI +} + +func InitERC20Contract(logger log.Logger, cdc codec.BinaryCodec, storeService cstore.KVStoreService, bankKeeper evmtypes.BankKeeper) *ERC20Contract { + contract := &ERC20Contract{ + logger: logger, + cdc: cdc, + storeService: storeService, + bankKeeper: bankKeeper, + methods: make(map[string]APIMethod), + } + + contract.methods[types.Method_BalanceOf] = contract.handleBalanceOf + contract.methods[types.Method_Register] = contract.handleRegister + contract.methods[types.Method_Transfer] = contract.handleTransfer + + precompiled.RegisterPrecompiles(types.PrecompiledAddress, contract) + + var err error + contract.proxyABI, err = abi.JSON(strings.NewReader(proxy.ERC20ProxyAbi)) + if err != nil { + panic(err) + } + return contract +} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *ERC20Contract) RequiredGas(input []byte) uint64 { + return 21000 +} + +func (c *ERC20Contract) Run(ctx context.Context, input []byte) ([]byte, error) { + var sdkCtx sdk.Context + if aspectCtx, ok := ctx.(*artelatypes.AspectRuntimeContext); !ok { + return nil, errors.New("failed to unwrap AspectRuntimeContext from context.Context") + } else { + sdkCtx = aspectCtx.CosmosContext() + } + + if len(input) < 4 { + return nil, errors.New("invalid input") + } + + // get tx.from, which is the proxy contract address + caller, ok := sdkCtx.Value("msgFrom").(common.Address) + if !ok { + return nil, errors.New("from address not valiad") + } + + // get tx.To, which is the proxy contract address + msgTo, ok := sdkCtx.Value("msgTo").(common.Address) + if !ok { + return nil, errors.New("to address not valiad") + } + + var ( + methodID = input[:4] + inputData = input[4:] + ) + + method, err := c.proxyABI.MethodById(methodID) + if err != nil { + return nil, err + } + + fn, ok := c.methods[method.Name] + if !ok { + return nil, errors.New("unknown method") + } + + args := make(map[string]interface{}) + if err := method.Inputs.UnpackIntoMap(args, inputData); err != nil { + return nil, err + } + + return fn(sdkCtx, msgTo, caller, args) +} + +func (c *ERC20Contract) handleRegister(ctx sdk.Context, proxy common.Address, _ common.Address, args map[string]interface{}) ([]byte, error) { + if len(args) != 1 { + return types.False32Byte, errors.New("invalid input") + } + + denom, ok := args["denom"].(string) + if !ok || len(denom) == 0 { + return types.False32Byte, errors.New("invalid input denom") + } + + prefix := "IBC/" + if !strings.HasPrefix(strings.ToUpper(denom), prefix) { + return types.False32Byte, errors.New("denom not valid") + } + + if d := c.GetDenomByProxy(ctx, proxy); len(d) > 0 { + return types.False32Byte, errors.New("proxy has been registered") + } + + if err := c.registerNewTokenPairs(ctx, denom, proxy); err != nil { + return types.False32Byte, err + } + return types.True32Byte, nil +} + +func (c *ERC20Contract) handleBalanceOf(ctx sdk.Context, proxy common.Address, _ common.Address, args map[string]interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("invalid input") + } + + denom, err := c.getDenom(ctx, proxy) + if err != nil { + return nil, err + } + + addr, ok := args["account"].(common.Address) + if !ok { + return nil, errors.New("invalid input account") + } + + accAddr := sdk.AccAddress(addr.Bytes()) + + coin := c.bankKeeper.GetBalance(ctx, accAddr, denom) + balance := coin.Amount.BigInt() + + packed, err := c.proxyABI.Methods[types.Method_BalanceOf].Outputs.Pack(balance) + if err != nil { + return nil, err + } + return packed, nil +} + +func (c *ERC20Contract) handleTransfer(ctx sdk.Context, proxy common.Address, caller common.Address, args map[string]interface{}) ([]byte, error) { + if len(args) != 2 { + return types.False32Byte, errors.New("invalid input") + } + + denom, err := c.getDenom(ctx, proxy) + if err != nil { + return types.False32Byte, err + } + + fromAccAddr := sdk.AccAddress(caller.Bytes()) + + to, ok := args["to"].(common.Address) + if !ok { + return types.False32Byte, errors.New("invalid input address") + } + toAccAddr := sdk.AccAddress(to.Bytes()) + + amount, ok := args["amount"].(*big.Int) + if !ok { + return types.False32Byte, errors.New("invalid input amount") + } + + coins := sdk.NewCoins(sdk.NewCoin(denom, math.NewIntFromBigInt(amount))) + if err := c.bankKeeper.IsSendEnabledCoins(ctx, coins...); err != nil { + return types.False32Byte, err + } + + err = c.bankKeeper.SendCoins( + ctx, fromAccAddr, toAccAddr, coins) + if err != nil { + return types.False32Byte, err + } + + return types.True32Byte, nil +} + +func (c *ERC20Contract) getDenom(ctx sdk.Context, proxy common.Address) (string, error) { + // get registered denom for the proxy address + denom := c.GetDenomByProxy(ctx, proxy) + if len(denom) == 0 { + return "", errors.New("no registered coin found") + } + + return denom, nil +} diff --git a/x/evm/precompile/erc20/proxy/ERC20Proxy.sol b/x/evm/precompile/erc20/proxy/ERC20Proxy.sol new file mode 100644 index 0000000..c3abdc8 --- /dev/null +++ b/x/evm/precompile/erc20/proxy/ERC20Proxy.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract ERC20Proxy { + // Address of the precompiled ERC20 contract + address public constant ERC20_PRECOMPILED_ADDRESS = address(0x0000000000000000000000000000000000000101); + + // Event for successful registration + event RegistrationSuccess(bool success); + + // ERC20 standard events + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor(string memory denom) { + bool success = register(denom); + emit RegistrationSuccess(success); + } + + /** + * @dev Fallback function that forwards all unknown calls to the precompiled ERC20 contract. + */ + fallback() external payable { + _delegate(ERC20_PRECOMPILED_ADDRESS); + } + + /** + * @dev Receive function to accept plain Ether transfers. + */ + receive() external payable {} + + /** + * @dev Delegates the request to the target address and returns the result to the caller. + * @param target The address of the target contract (i.e., the precompiled ERC20 contract). + */ + function _delegate(address target) internal { + (bool success, bytes memory returndata) = target.delegatecall(msg.data); + assembly { + switch success + case 0 { revert(add(returndata, 32), mload(returndata)) } // Revert on failure + default { return(add(returndata, 32), mload(returndata)) } // Return data on success + } + } + + /** + * @dev Registers the token with the specified denom in the precompiled ERC20 contract. + * @param denom The token denomination to register. + * @return success Whether the registration was successful. + */ + function register(string memory denom) internal returns (bool) { + (bool success, ) = ERC20_PRECOMPILED_ADDRESS.delegatecall( + abi.encodeWithSignature("register(string)", denom) + ); + require(success, "ERC20: registration failed"); + return success; + } + + /** + * @dev Queries the token balance of an account. + * @param account The address of the account to query. + * @return balance The token balance of the account. + */ + function balanceOf(address account) external returns (uint256) { + (bool success, bytes memory result) = ERC20_PRECOMPILED_ADDRESS.delegatecall( + abi.encodeWithSignature("balanceOf(address)", account) + ); + require(success, "ERC20: delegate call failed"); + return abi.decode(result, (uint256)); + } + + /** + * @dev Transfers tokens to a specified address. + * @param to The address to receive the tokens. + * @param amount The amount of tokens to transfer. + * @return success Whether the transfer was successful. + */ + function transfer(address to, uint256 amount) external returns (bool) { + (bool success, bytes memory result) = ERC20_PRECOMPILED_ADDRESS.delegatecall( + abi.encodeWithSignature("transfer(address,uint256)", to, amount) + ); + require(success, "ERC20: transfer failed"); + + emit Transfer(msg.sender, to, amount); // Emit Transfer event + return abi.decode(result, (bool)); + } + + /** + * @dev Approves a spender to use a specified amount of tokens. + * @param spender The address authorized to spend the tokens. + * @param amount The amount of tokens to approve. + * @return success Whether the approval was successful. + */ + function approve(address spender, uint256 amount) external returns (bool) { + (bool success, bytes memory result) = ERC20_PRECOMPILED_ADDRESS.delegatecall( + abi.encodeWithSignature("approve(address,uint256)", spender, amount) + ); + require(success, "ERC20: approve failed"); + + emit Approval(msg.sender, spender, amount); // Emit Approval event + return abi.decode(result, (bool)); + } + + /** + * @dev Queries the allowance of a spender for a specific owner. + * @param owner The address of the token holder. + * @param spender The address authorized to spend the tokens. + * @return remaining The remaining amount of tokens the spender can use. + */ + function allowance(address owner, address spender) external returns (uint256) { + (bool success, bytes memory result) = ERC20_PRECOMPILED_ADDRESS.delegatecall( + abi.encodeWithSignature("allowance(address,address)", owner, spender) + ); + require(success, "ERC20: allowance query failed"); + return abi.decode(result, (uint256)); + } +} diff --git a/x/evm/precompile/erc20/proxy/ERC20ProxyCompiled.go b/x/evm/precompile/erc20/proxy/ERC20ProxyCompiled.go new file mode 100644 index 0000000..09a117b --- /dev/null +++ b/x/evm/precompile/erc20/proxy/ERC20ProxyCompiled.go @@ -0,0 +1,212 @@ +package proxy + +const ( + ERC20ProxyBin = `608060405234801561000f575f5ffd5b5060405161122d38038061122d8339818101604052810190610031919061030e565b5f6100418261008160201b60201c565b90507ffcc2869d2ba3df58e629ad93fc7e1e2c05a9f6ce6223e40ff0041b7670ca1a9681604051610072919061036f565b60405180910390a150506104bc565b5f5f61010173ffffffffffffffffffffffffffffffffffffffff16836040516024016100ad91906103da565b6040516020818303038152906040527ff2c298be000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610137919061043e565b5f60405180830381855af49150503d805f811461016f576040519150601f19603f3d011682016040523d82523d5f602084013e610174565b606091505b50509050806101b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101af9061049e565b60405180910390fd5b80915050919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610220826101da565b810181811067ffffffffffffffff8211171561023f5761023e6101ea565b5b80604052505050565b5f6102516101c1565b905061025d8282610217565b919050565b5f67ffffffffffffffff82111561027c5761027b6101ea565b5b610285826101da565b9050602081019050919050565b8281835e5f83830152505050565b5f6102b26102ad84610262565b610248565b9050828152602081018484840111156102ce576102cd6101d6565b5b6102d9848285610292565b509392505050565b5f82601f8301126102f5576102f46101d2565b5b81516103058482602086016102a0565b91505092915050565b5f60208284031215610323576103226101ca565b5b5f82015167ffffffffffffffff8111156103405761033f6101ce565b5b61034c848285016102e1565b91505092915050565b5f8115159050919050565b61036981610355565b82525050565b5f6020820190506103825f830184610360565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f6103ac82610388565b6103b68185610392565b93506103c6818560208601610292565b6103cf816101da565b840191505092915050565b5f6020820190508181035f8301526103f281846103a2565b905092915050565b5f81519050919050565b5f81905092915050565b5f610418826103fa565b6104228185610404565b9350610432818560208601610292565b80840191505092915050565b5f610449828461040e565b915081905092915050565b7f45524332303a20726567697374726174696f6e206661696c65640000000000005f82015250565b5f610488601a83610392565b915061049382610454565b602082019050919050565b5f6020820190508181035f8301526104b58161047c565b9050919050565b610d64806104c95f395ff3fe60806040526004361061004d575f3560e01c8063095ea7b31461006157806370a082311461009d578063a9059cbb146100d9578063d3ed45f814610115578063dd62ed3e1461013f57610054565b3661005457005b61005f61010161017b565b005b34801561006c575f5ffd5b50610087600480360381019061008291906108c0565b6101fe565b6040516100949190610918565b60405180910390f35b3480156100a8575f5ffd5b506100c360048036038101906100be9190610931565b6103bc565b6040516100d0919061096b565b60405180910390f35b3480156100e4575f5ffd5b506100ff60048036038101906100fa91906108c0565b610512565b60405161010c9190610918565b60405180910390f35b348015610120575f5ffd5b506101296106d0565b6040516101369190610993565b60405180910390f35b34801561014a575f5ffd5b50610165600480360381019061016091906109ac565b6106d6565b604051610172919061096b565b60405180910390f35b5f5f8273ffffffffffffffffffffffffffffffffffffffff165f366040516101a4929190610a26565b5f60405180830381855af49150503d805f81146101dc576040519150601f19603f3d011682016040523d82523d5f602084013e6101e1565b606091505b5091509150815f81146101f657815160208301f35b815160208301fd5b5f5f5f61010173ffffffffffffffffffffffffffffffffffffffff16858560405160240161022d929190610a3e565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516102b79190610aad565b5f60405180830381855af49150503d805f81146102ef576040519150601f19603f3d011682016040523d82523d5f602084013e6102f4565b606091505b509150915081610339576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033090610b1d565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92586604051610396919061096b565b60405180910390a3808060200190518101906103b29190610b65565b9250505092915050565b5f5f5f61010173ffffffffffffffffffffffffffffffffffffffff16846040516024016103e99190610993565b6040516020818303038152906040527f70a08231000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104739190610aad565b5f60405180830381855af49150503d805f81146104ab576040519150601f19603f3d011682016040523d82523d5f602084013e6104b0565b606091505b5091509150816104f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ec90610bda565b60405180910390fd5b808060200190518101906105099190610c0c565b92505050919050565b5f5f5f61010173ffffffffffffffffffffffffffffffffffffffff168585604051602401610541929190610a3e565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516105cb9190610aad565b5f60405180830381855af49150503d805f8114610603576040519150601f19603f3d011682016040523d82523d5f602084013e610608565b606091505b50915091508161064d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161064490610c81565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef866040516106aa919061096b565b60405180910390a3808060200190518101906106c69190610b65565b9250505092915050565b61010181565b5f5f5f61010173ffffffffffffffffffffffffffffffffffffffff168585604051602401610705929190610c9f565b6040516020818303038152906040527fdd62ed3e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161078f9190610aad565b5f60405180830381855af49150503d805f81146107c7576040519150601f19603f3d011682016040523d82523d5f602084013e6107cc565b606091505b509150915081610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161080890610d10565b60405180910390fd5b808060200190518101906108259190610c0c565b9250505092915050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61085c82610833565b9050919050565b61086c81610852565b8114610876575f5ffd5b50565b5f8135905061088781610863565b92915050565b5f819050919050565b61089f8161088d565b81146108a9575f5ffd5b50565b5f813590506108ba81610896565b92915050565b5f5f604083850312156108d6576108d561082f565b5b5f6108e385828601610879565b92505060206108f4858286016108ac565b9150509250929050565b5f8115159050919050565b610912816108fe565b82525050565b5f60208201905061092b5f830184610909565b92915050565b5f602082840312156109465761094561082f565b5b5f61095384828501610879565b91505092915050565b6109658161088d565b82525050565b5f60208201905061097e5f83018461095c565b92915050565b61098d81610852565b82525050565b5f6020820190506109a65f830184610984565b92915050565b5f5f604083850312156109c2576109c161082f565b5b5f6109cf85828601610879565b92505060206109e085828601610879565b9150509250929050565b5f81905092915050565b828183375f83830152505050565b5f610a0d83856109ea565b9350610a1a8385846109f4565b82840190509392505050565b5f610a32828486610a02565b91508190509392505050565b5f604082019050610a515f830185610984565b610a5e602083018461095c565b9392505050565b5f81519050919050565b8281835e5f83830152505050565b5f610a8782610a65565b610a9181856109ea565b9350610aa1818560208601610a6f565b80840191505092915050565b5f610ab88284610a7d565b915081905092915050565b5f82825260208201905092915050565b7f45524332303a20617070726f7665206661696c656400000000000000000000005f82015250565b5f610b07601583610ac3565b9150610b1282610ad3565b602082019050919050565b5f6020820190508181035f830152610b3481610afb565b9050919050565b610b44816108fe565b8114610b4e575f5ffd5b50565b5f81519050610b5f81610b3b565b92915050565b5f60208284031215610b7a57610b7961082f565b5b5f610b8784828501610b51565b91505092915050565b7f45524332303a2064656c65676174652063616c6c206661696c656400000000005f82015250565b5f610bc4601b83610ac3565b9150610bcf82610b90565b602082019050919050565b5f6020820190508181035f830152610bf181610bb8565b9050919050565b5f81519050610c0681610896565b92915050565b5f60208284031215610c2157610c2061082f565b5b5f610c2e84828501610bf8565b91505092915050565b7f45524332303a207472616e73666572206661696c6564000000000000000000005f82015250565b5f610c6b601683610ac3565b9150610c7682610c37565b602082019050919050565b5f6020820190508181035f830152610c9881610c5f565b9050919050565b5f604082019050610cb25f830185610984565b610cbf6020830184610984565b9392505050565b7f45524332303a20616c6c6f77616e6365207175657279206661696c65640000005f82015250565b5f610cfa601d83610ac3565b9150610d0582610cc6565b602082019050919050565b5f6020820190508181035f830152610d2781610cee565b905091905056fea2646970667358221220115ee257bb0d95108c8e6dd77167504375849ff19e41c29cb3b7dd604c88f7c964736f6c634300081b0033` + ERC20ProxyAbi = `[ + { + "inputs": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "RegistrationSuccess", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "ERC20_PRECOMPILED_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "denom", + "type": "string" + } + ], + "name": "register", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ]` +) diff --git a/x/evm/precompile/erc20/store.go b/x/evm/precompile/erc20/store.go new file mode 100644 index 0000000..039c5fb --- /dev/null +++ b/x/evm/precompile/erc20/store.go @@ -0,0 +1,65 @@ +package erc20 + +import ( + "fmt" + + "cosmossdk.io/store/prefix" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + + evmtypes "github.com/artela-network/artela-rollkit/x/evm/types" +) + +func (c *ERC20Contract) registerNewTokenPairs(ctx sdk.Context, denom string, proxy common.Address) error { + c.setDenomByProxy(ctx, denom, proxy) + return c.appendProxyByDenom(ctx, denom, proxy) +} + +func (c *ERC20Contract) GetProxyByDenom(ctx sdk.Context, denom string) ([]string, error) { + store := prefix.NewStore(runtime.KVStoreAdapter(c.storeService.OpenKVStore(ctx)), evmtypes.KeyPrefixERC20Denom) + data := store.Get([]byte(denom)) + if len(data)%common.AddressLength != 0 { + return nil, fmt.Errorf("failed to load proxy address, value: %x", data) + } + + addrs := make([]string, len(data)/common.AddressLength) + for i := 0; i < len(data); i += common.AddressLength { + addrs[i/common.AddressLength] = common.BytesToAddress(data[i : i+common.AddressLength]).String() + } + + return addrs, nil +} + +func (c *ERC20Contract) appendProxyByDenom(ctx sdk.Context, denom string, proxy common.Address) error { + store := prefix.NewStore(runtime.KVStoreAdapter(c.storeService.OpenKVStore(ctx)), evmtypes.KeyPrefixERC20Denom) + data := store.Get([]byte(denom)) + if len(data)%common.AddressLength != 0 { + return fmt.Errorf("failed to load proxy address, value: %x", data) + } + + newData := make([]byte, len(data)+common.AddressLength) + copy(newData, data) + copy(newData[len(data):], proxy.Bytes()) + store.Set([]byte(denom), newData) + + c.logger.Debug("setState: set ProxyByDenom", + "denom", denom, + "addrs", fmt.Sprintf("%x", newData)) + return nil +} + +func (c *ERC20Contract) GetDenomByProxy(ctx sdk.Context, proxy common.Address) string { + store := prefix.NewStore(runtime.KVStoreAdapter(c.storeService.OpenKVStore(ctx)), evmtypes.KeyPrefixERC20Address) + data := store.Get(proxy.Bytes()) + return string(data) +} + +func (c *ERC20Contract) setDenomByProxy(ctx sdk.Context, denom string, proxy common.Address) { + store := prefix.NewStore(runtime.KVStoreAdapter(c.storeService.OpenKVStore(ctx)), evmtypes.KeyPrefixERC20Address) + store.Set(proxy.Bytes(), []byte(denom)) + + c.logger.Debug("setState: set DenomByProxy", + "addr", proxy.String(), + "denom", denom) +} diff --git a/x/evm/precompile/erc20/types/constants.go b/x/evm/precompile/erc20/types/constants.go new file mode 100644 index 0000000..065a641 --- /dev/null +++ b/x/evm/precompile/erc20/types/constants.go @@ -0,0 +1,16 @@ +package types + +import "github.com/ethereum/go-ethereum/common" + +const ( + Method_Transfer = "transfer" + Method_BalanceOf = "balanceOf" + Method_Register = "register" +) + +var ( + True32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + False32Byte = make([]byte, 32) + + PrecompiledAddress = common.HexToAddress("0x0000000000000000000000000000000000000101") +) diff --git a/x/evm/precompile/erc20/types/erc20.pb.go b/x/evm/precompile/erc20/types/erc20.pb.go new file mode 100644 index 0000000..4b57732 --- /dev/null +++ b/x/evm/precompile/erc20/types/erc20.pb.go @@ -0,0 +1,552 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/evm/v1/erc20.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type TokenPair struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` +} + +func (m *TokenPair) Reset() { *m = TokenPair{} } +func (m *TokenPair) String() string { return proto.CompactTextString(m) } +func (*TokenPair) ProtoMessage() {} +func (*TokenPair) Descriptor() ([]byte, []int) { + return fileDescriptor_3201b9e77833b996, []int{0} +} +func (m *TokenPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenPair.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenPair.Merge(m, src) +} +func (m *TokenPair) XXX_Size() int { + return m.Size() +} +func (m *TokenPair) XXX_DiscardUnknown() { + xxx_messageInfo_TokenPair.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenPair proto.InternalMessageInfo + +func (m *TokenPair) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *TokenPair) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type TokenPairs struct { + TokenPairs []*TokenPair `protobuf:"bytes,1,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs,omitempty"` +} + +func (m *TokenPairs) Reset() { *m = TokenPairs{} } +func (m *TokenPairs) String() string { return proto.CompactTextString(m) } +func (*TokenPairs) ProtoMessage() {} +func (*TokenPairs) Descriptor() ([]byte, []int) { + return fileDescriptor_3201b9e77833b996, []int{1} +} +func (m *TokenPairs) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenPairs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenPairs.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenPairs) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenPairs.Merge(m, src) +} +func (m *TokenPairs) XXX_Size() int { + return m.Size() +} +func (m *TokenPairs) XXX_DiscardUnknown() { + xxx_messageInfo_TokenPairs.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenPairs proto.InternalMessageInfo + +func (m *TokenPairs) GetTokenPairs() []*TokenPair { + if m != nil { + return m.TokenPairs + } + return nil +} + +func init() { + proto.RegisterType((*TokenPair)(nil), "artela.evm.v1.TokenPair") + proto.RegisterType((*TokenPairs)(nil), "artela.evm.v1.TokenPairs") +} + +func init() { proto.RegisterFile("artela/evm/v1/erc20.proto", fileDescriptor_3201b9e77833b996) } + +var fileDescriptor_3201b9e77833b996 = []byte{ + // 227 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0x2c, 0x2a, 0x49, + 0xcd, 0x49, 0xd4, 0x4f, 0x2d, 0xcb, 0xd5, 0x2f, 0x33, 0xd4, 0x4f, 0x2d, 0x4a, 0x36, 0x32, 0xd0, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x85, 0x48, 0xe9, 0xa5, 0x96, 0xe5, 0xea, 0x95, 0x19, + 0x4a, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x65, 0xf4, 0x41, 0x2c, 0x88, 0x22, 0x25, 0x6b, 0x2e, + 0xce, 0x90, 0xfc, 0xec, 0xd4, 0xbc, 0x80, 0xc4, 0xcc, 0x22, 0x21, 0x09, 0x2e, 0xf6, 0xc4, 0x94, + 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x18, 0x57, 0x48, 0x84, + 0x8b, 0x35, 0x25, 0x35, 0x2f, 0x3f, 0x57, 0x82, 0x09, 0x2c, 0x0e, 0xe1, 0x28, 0xb9, 0x73, 0x71, + 0xc1, 0x35, 0x17, 0x0b, 0x59, 0x72, 0x71, 0x97, 0x80, 0x78, 0xf1, 0x05, 0x20, 0xae, 0x04, 0xa3, + 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x84, 0x1e, 0x8a, 0x2b, 0xf4, 0xe0, 0xea, 0x83, 0xb8, 0x4a, 0xe0, + 0x5a, 0x9d, 0x3c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, + 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x3f, 0x3d, + 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x62, 0x92, 0x6e, 0x5e, 0x6a, 0x49, + 0x79, 0x7e, 0x51, 0x36, 0x94, 0x0b, 0xf2, 0x75, 0x05, 0xd8, 0xfb, 0x25, 0x95, 0x05, 0xa9, 0xc5, + 0x49, 0x6c, 0x60, 0x7f, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3c, 0xba, 0x95, 0x6e, 0x19, + 0x01, 0x00, 0x00, +} + +func (m *TokenPair) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TokenPairs) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenPairs) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenPairs) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TokenPairs) > 0 { + for iNdEx := len(m.TokenPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintErc20(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintErc20(dAtA []byte, offset int, v uint64) int { + offset -= sovErc20(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *TokenPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + return n +} + +func (m *TokenPairs) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TokenPairs) > 0 { + for _, e := range m.TokenPairs { + l = e.Size() + n += 1 + l + sovErc20(uint64(l)) + } + } + return n +} + +func sovErc20(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozErc20(x uint64) (n int) { + return sovErc20(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *TokenPair) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TokenPairs) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenPairs: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenPairs: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenPairs = append(m.TokenPairs, &TokenPair{}) + if err := m.TokenPairs[len(m.TokenPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipErc20(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthErc20 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupErc20 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthErc20 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthErc20 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowErc20 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupErc20 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/erc20.pb.go b/x/evm/types/erc20.pb.go new file mode 100644 index 0000000..9fcb46f --- /dev/null +++ b/x/evm/types/erc20.pb.go @@ -0,0 +1,552 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: artela/evm/erc20.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type TokenPair struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` +} + +func (m *TokenPair) Reset() { *m = TokenPair{} } +func (m *TokenPair) String() string { return proto.CompactTextString(m) } +func (*TokenPair) ProtoMessage() {} +func (*TokenPair) Descriptor() ([]byte, []int) { + return fileDescriptor_2cc4f6d04cdea721, []int{0} +} +func (m *TokenPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenPair.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenPair.Merge(m, src) +} +func (m *TokenPair) XXX_Size() int { + return m.Size() +} +func (m *TokenPair) XXX_DiscardUnknown() { + xxx_messageInfo_TokenPair.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenPair proto.InternalMessageInfo + +func (m *TokenPair) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *TokenPair) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type TokenPairs struct { + TokenPairs []*TokenPair `protobuf:"bytes,1,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs,omitempty"` +} + +func (m *TokenPairs) Reset() { *m = TokenPairs{} } +func (m *TokenPairs) String() string { return proto.CompactTextString(m) } +func (*TokenPairs) ProtoMessage() {} +func (*TokenPairs) Descriptor() ([]byte, []int) { + return fileDescriptor_2cc4f6d04cdea721, []int{1} +} +func (m *TokenPairs) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenPairs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenPairs.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenPairs) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenPairs.Merge(m, src) +} +func (m *TokenPairs) XXX_Size() int { + return m.Size() +} +func (m *TokenPairs) XXX_DiscardUnknown() { + xxx_messageInfo_TokenPairs.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenPairs proto.InternalMessageInfo + +func (m *TokenPairs) GetTokenPairs() []*TokenPair { + if m != nil { + return m.TokenPairs + } + return nil +} + +func init() { + proto.RegisterType((*TokenPair)(nil), "artela.evm.TokenPair") + proto.RegisterType((*TokenPairs)(nil), "artela.evm.TokenPairs") +} + +func init() { proto.RegisterFile("artela/evm/erc20.proto", fileDescriptor_2cc4f6d04cdea721) } + +var fileDescriptor_2cc4f6d04cdea721 = []byte{ + // 227 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2c, 0x2a, 0x49, + 0xcd, 0x49, 0xd4, 0x4f, 0x2d, 0xcb, 0xd5, 0x4f, 0x2d, 0x4a, 0x36, 0x32, 0xd0, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0xe2, 0x82, 0x88, 0xeb, 0xa5, 0x96, 0xe5, 0x4a, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, + 0x83, 0x85, 0xf5, 0x41, 0x2c, 0x88, 0x0a, 0x25, 0x6b, 0x2e, 0xce, 0x90, 0xfc, 0xec, 0xd4, 0xbc, + 0x80, 0xc4, 0xcc, 0x22, 0x21, 0x09, 0x2e, 0xf6, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, + 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x18, 0x57, 0x48, 0x84, 0x8b, 0x35, 0x25, 0x35, 0x2f, 0x3f, + 0x57, 0x82, 0x09, 0x2c, 0x0e, 0xe1, 0x28, 0xb9, 0x70, 0x71, 0xc1, 0x35, 0x17, 0x0b, 0x99, 0x71, + 0x71, 0x97, 0x80, 0x78, 0xf1, 0x05, 0x20, 0xae, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0xa8, + 0x1e, 0xc2, 0x09, 0x7a, 0x70, 0xc5, 0x41, 0x5c, 0x25, 0x70, 0x7d, 0x4e, 0x7e, 0x27, 0x1e, 0xc9, + 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, + 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x92, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, + 0x9c, 0x9f, 0xab, 0x0f, 0x31, 0x46, 0x37, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x1b, 0xc6, 0x2d, + 0xca, 0xcf, 0xc9, 0xc9, 0xce, 0x2c, 0xd1, 0xaf, 0x00, 0x7b, 0xbd, 0xa4, 0xb2, 0x20, 0xb5, 0x38, + 0x89, 0x0d, 0xec, 0x33, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x75, 0x46, 0xd5, 0x0a, 0x15, + 0x01, 0x00, 0x00, +} + +func (m *TokenPair) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TokenPairs) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenPairs) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenPairs) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TokenPairs) > 0 { + for iNdEx := len(m.TokenPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintErc20(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintErc20(dAtA []byte, offset int, v uint64) int { + offset -= sovErc20(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *TokenPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + return n +} + +func (m *TokenPairs) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TokenPairs) > 0 { + for _, e := range m.TokenPairs { + l = e.Size() + n += 1 + l + sovErc20(uint64(l)) + } + } + return n +} + +func sovErc20(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozErc20(x uint64) (n int) { + return sovErc20(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *TokenPair) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TokenPairs) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenPairs: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenPairs: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenPairs = append(m.TokenPairs, &TokenPair{}) + if err := m.TokenPairs[len(m.TokenPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipErc20(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowErc20 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthErc20 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupErc20 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthErc20 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthErc20 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowErc20 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupErc20 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/expected_keepers.go b/x/evm/types/expected_keepers.go index 059d337..a5a9102 100644 --- a/x/evm/types/expected_keepers.go +++ b/x/evm/types/expected_keepers.go @@ -5,6 +5,7 @@ import ( "math/big" "cosmossdk.io/core/address" + cstore "cosmossdk.io/core/store" sdk "github.com/cosmos/cosmos-sdk/types" authmodule "github.com/cosmos/cosmos-sdk/x/auth/types" stakingmodule "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -61,3 +62,7 @@ type ParamSubspace interface { Get(context.Context, []byte, interface{}) Set(context.Context, []byte, interface{}) } + +type AspectKeeper interface { + GetStoreService() cstore.KVStoreService +} diff --git a/x/evm/types/keys.go b/x/evm/types/keys.go index 419e0c4..6608d7a 100644 --- a/x/evm/types/keys.go +++ b/x/evm/types/keys.go @@ -39,6 +39,8 @@ const ( prefixCode = iota + 1 prefixStorage prefixParams + prefixERC20Address + prefixERC20Denom ) // prefix bytes for the EVM transient store @@ -74,9 +76,11 @@ const ( // KVStore key prefixes var ( - KeyPrefixCode = []byte{prefixCode} - KeyPrefixStorage = []byte{prefixStorage} - KeyPrefixParams = []byte{prefixParams} + KeyPrefixCode = []byte{prefixCode} + KeyPrefixStorage = []byte{prefixStorage} + KeyPrefixParams = []byte{prefixParams} + KeyPrefixERC20Address = []byte{prefixERC20Address} + KeyPrefixERC20Denom = []byte{prefixERC20Denom} ) // Transient Store key prefixes diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index 15de9fe..1b4c271 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -1350,6 +1350,182 @@ func (m *GetSenderResponse) GetSender() string { return "" } +type DenomByAddressRequest struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *DenomByAddressRequest) Reset() { *m = DenomByAddressRequest{} } +func (m *DenomByAddressRequest) String() string { return proto.CompactTextString(m) } +func (*DenomByAddressRequest) ProtoMessage() {} +func (*DenomByAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_09631cdbc49bb889, []int{25} +} +func (m *DenomByAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomByAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomByAddressRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DenomByAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomByAddressRequest.Merge(m, src) +} +func (m *DenomByAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *DenomByAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DenomByAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomByAddressRequest proto.InternalMessageInfo + +func (m *DenomByAddressRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +type DenomByAddressResponse struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` +} + +func (m *DenomByAddressResponse) Reset() { *m = DenomByAddressResponse{} } +func (m *DenomByAddressResponse) String() string { return proto.CompactTextString(m) } +func (*DenomByAddressResponse) ProtoMessage() {} +func (*DenomByAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_09631cdbc49bb889, []int{26} +} +func (m *DenomByAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomByAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomByAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DenomByAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomByAddressResponse.Merge(m, src) +} +func (m *DenomByAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *DenomByAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DenomByAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomByAddressResponse proto.InternalMessageInfo + +func (m *DenomByAddressResponse) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type AddressByDenomRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` +} + +func (m *AddressByDenomRequest) Reset() { *m = AddressByDenomRequest{} } +func (m *AddressByDenomRequest) String() string { return proto.CompactTextString(m) } +func (*AddressByDenomRequest) ProtoMessage() {} +func (*AddressByDenomRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_09631cdbc49bb889, []int{27} +} +func (m *AddressByDenomRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddressByDenomRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddressByDenomRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddressByDenomRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddressByDenomRequest.Merge(m, src) +} +func (m *AddressByDenomRequest) XXX_Size() int { + return m.Size() +} +func (m *AddressByDenomRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AddressByDenomRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AddressByDenomRequest proto.InternalMessageInfo + +func (m *AddressByDenomRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type AddressByDenomResponse struct { + Address []string `protobuf:"bytes,1,rep,name=address,proto3" json:"address,omitempty"` +} + +func (m *AddressByDenomResponse) Reset() { *m = AddressByDenomResponse{} } +func (m *AddressByDenomResponse) String() string { return proto.CompactTextString(m) } +func (*AddressByDenomResponse) ProtoMessage() {} +func (*AddressByDenomResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_09631cdbc49bb889, []int{28} +} +func (m *AddressByDenomResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddressByDenomResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddressByDenomResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddressByDenomResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddressByDenomResponse.Merge(m, src) +} +func (m *AddressByDenomResponse) XXX_Size() int { + return m.Size() +} +func (m *AddressByDenomResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AddressByDenomResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AddressByDenomResponse proto.InternalMessageInfo + +func (m *AddressByDenomResponse) GetAddress() []string { + if m != nil { + return m.Address + } + return nil +} + func init() { proto.RegisterType((*QueryAccountRequest)(nil), "artela.evm.QueryAccountRequest") proto.RegisterType((*QueryAccountResponse)(nil), "artela.evm.QueryAccountResponse") @@ -1376,108 +1552,120 @@ func init() { proto.RegisterType((*QueryBaseFeeRequest)(nil), "artela.evm.QueryBaseFeeRequest") proto.RegisterType((*QueryBaseFeeResponse)(nil), "artela.evm.QueryBaseFeeResponse") proto.RegisterType((*GetSenderResponse)(nil), "artela.evm.GetSenderResponse") + proto.RegisterType((*DenomByAddressRequest)(nil), "artela.evm.DenomByAddressRequest") + proto.RegisterType((*DenomByAddressResponse)(nil), "artela.evm.DenomByAddressResponse") + proto.RegisterType((*AddressByDenomRequest)(nil), "artela.evm.AddressByDenomRequest") + proto.RegisterType((*AddressByDenomResponse)(nil), "artela.evm.AddressByDenomResponse") } func init() { proto.RegisterFile("artela/evm/query.proto", fileDescriptor_09631cdbc49bb889) } var fileDescriptor_09631cdbc49bb889 = []byte{ - // 1524 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4b, 0x6f, 0x1b, 0x47, - 0x12, 0x16, 0x4d, 0x4a, 0xa4, 0x8a, 0x92, 0x2d, 0xb7, 0x69, 0x3d, 0xc6, 0x12, 0x29, 0x8f, 0x56, - 0x8f, 0xf5, 0x63, 0xc6, 0xd6, 0x1a, 0x0b, 0xac, 0x81, 0xc5, 0xc2, 0x12, 0x6c, 0xad, 0xe1, 0x07, - 0xbc, 0xb4, 0xb0, 0x87, 0x00, 0x01, 0xd1, 0x1c, 0xb6, 0x86, 0x8c, 0x38, 0xd3, 0xf4, 0x74, 0x53, - 0xa1, 0x62, 0xf8, 0x92, 0x00, 0x41, 0x80, 0xe4, 0x60, 0x20, 0xe7, 0x00, 0x3e, 0xe5, 0x2f, 0xe4, - 0x2f, 0xf8, 0x68, 0x20, 0x97, 0x20, 0x07, 0x27, 0x90, 0x73, 0xc8, 0x6f, 0xf0, 0x29, 0xe8, 0xc7, - 0x90, 0x3d, 0xe2, 0x48, 0x8a, 0x03, 0xfb, 0x22, 0x4d, 0x57, 0x57, 0xd7, 0xf7, 0x55, 0x57, 0x75, - 0x55, 0x11, 0xa6, 0x71, 0xc4, 0x49, 0x1b, 0xbb, 0x64, 0x2f, 0x70, 0x9f, 0x74, 0x49, 0xb4, 0xef, - 0x74, 0x22, 0xca, 0x29, 0x02, 0x25, 0x77, 0xc8, 0x5e, 0x60, 0x9d, 0xc5, 0x41, 0x2b, 0xa4, 0xae, - 0xfc, 0xab, 0xb6, 0xad, 0x92, 0x4f, 0x7d, 0x2a, 0x3f, 0x5d, 0xf1, 0xa5, 0xa5, 0xf3, 0x3e, 0xa5, - 0x7e, 0x9b, 0xb8, 0xb8, 0xd3, 0x72, 0x71, 0x18, 0x52, 0x8e, 0x79, 0x8b, 0x86, 0x4c, 0xef, 0x5e, - 0xf2, 0x28, 0x0b, 0x28, 0x73, 0xeb, 0x98, 0x11, 0x85, 0xe5, 0xee, 0x5d, 0xaf, 0x13, 0x8e, 0xaf, - 0xbb, 0x1d, 0xec, 0xb7, 0x42, 0xa9, 0xac, 0x75, 0x2b, 0xda, 0x92, 0x5c, 0xd5, 0xbb, 0x3b, 0x2e, - 0x6f, 0x05, 0x84, 0x71, 0x1c, 0x74, 0xb4, 0xc2, 0x8c, 0xc1, 0xbb, 0x83, 0x23, 0x1c, 0xc4, 0x28, - 0x25, 0x63, 0x83, 0xec, 0x05, 0x5a, 0x7a, 0xce, 0x90, 0xf2, 0x9e, 0x12, 0xda, 0xff, 0x82, 0x73, - 0xff, 0x13, 0x34, 0x6e, 0x79, 0x1e, 0xed, 0x86, 0xbc, 0x4a, 0x9e, 0x74, 0x09, 0xe3, 0x68, 0x16, - 0xf2, 0xb8, 0xd1, 0x88, 0x08, 0x63, 0xb3, 0x99, 0xc5, 0xcc, 0xda, 0x78, 0x35, 0x5e, 0xde, 0x2c, - 0x7c, 0xf5, 0xa2, 0x32, 0xf2, 0xfb, 0x8b, 0xca, 0x88, 0xed, 0x41, 0x29, 0x79, 0x94, 0x75, 0x68, - 0xc8, 0x88, 0x38, 0x5b, 0xc7, 0x6d, 0x1c, 0x7a, 0x24, 0x3e, 0xab, 0x97, 0xe8, 0x02, 0x8c, 0x7b, - 0xb4, 0x41, 0x6a, 0x4d, 0xcc, 0x9a, 0xb3, 0xa7, 0xe4, 0x5e, 0x41, 0x08, 0xfe, 0x8b, 0x59, 0x13, - 0x95, 0x60, 0x34, 0xa4, 0xe2, 0x50, 0x76, 0x31, 0xb3, 0x96, 0xab, 0xaa, 0x85, 0xfd, 0x1f, 0x98, - 0x93, 0x20, 0x9b, 0xf2, 0xde, 0xfe, 0x02, 0xcb, 0x2f, 0x33, 0x60, 0xa5, 0x59, 0xd0, 0x64, 0x97, - 0xe1, 0xb4, 0x0a, 0x49, 0x2d, 0x69, 0x69, 0x52, 0x49, 0x6f, 0x29, 0x21, 0xb2, 0xa0, 0xc0, 0x04, - 0xa8, 0xe0, 0x77, 0x4a, 0xf2, 0xeb, 0xaf, 0x85, 0x09, 0xac, 0xac, 0xd6, 0xc2, 0x6e, 0x50, 0x27, - 0x91, 0xf6, 0x60, 0x52, 0x4b, 0x1f, 0x4a, 0xa1, 0x7d, 0x0f, 0xe6, 0x25, 0x8f, 0xff, 0xe3, 0x76, - 0xab, 0x81, 0x39, 0x8d, 0x0e, 0x39, 0x73, 0x11, 0x26, 0x3c, 0x1a, 0x1e, 0xe6, 0x51, 0x14, 0xb2, - 0x5b, 0x43, 0x5e, 0x7d, 0x9d, 0x81, 0x85, 0x23, 0xac, 0x69, 0xc7, 0x56, 0xe1, 0x4c, 0xcc, 0x2a, - 0x69, 0x31, 0x26, 0xfb, 0x1e, 0x5d, 0x8b, 0x93, 0x68, 0x43, 0xc5, 0xf9, 0x5d, 0xc2, 0x73, 0x4d, - 0x27, 0x51, 0xff, 0xe8, 0x49, 0x49, 0x64, 0xdf, 0xd3, 0x60, 0x8f, 0x39, 0x8d, 0xb0, 0x7f, 0x32, - 0x18, 0x9a, 0x82, 0xec, 0x2e, 0xd9, 0xd7, 0xf9, 0x26, 0x3e, 0x0d, 0xf8, 0x2b, 0x1a, 0xbe, 0x6f, - 0x4c, 0xc3, 0x97, 0x60, 0x74, 0x0f, 0xb7, 0xbb, 0x31, 0xb8, 0x5a, 0xd8, 0xff, 0x84, 0x29, 0x9d, - 0x4a, 0x8d, 0x77, 0x72, 0x72, 0x15, 0xce, 0x1a, 0xe7, 0x34, 0x04, 0x82, 0x9c, 0xc8, 0x7d, 0x79, - 0x6a, 0xa2, 0x2a, 0xbf, 0xed, 0xcf, 0x00, 0x49, 0xc5, 0xed, 0xde, 0x7d, 0xea, 0xb3, 0x18, 0x02, - 0x41, 0x4e, 0xbe, 0x18, 0x65, 0x5f, 0x7e, 0xa3, 0x3b, 0x00, 0x83, 0x82, 0x21, 0x7d, 0x2b, 0xae, - 0xaf, 0x38, 0x2a, 0x69, 0x1d, 0x51, 0x5d, 0x1c, 0x55, 0xc9, 0x74, 0x75, 0x71, 0x1e, 0x0d, 0xae, - 0xaa, 0x6a, 0x9c, 0x34, 0x48, 0x7e, 0x91, 0xd1, 0x17, 0x1b, 0x83, 0x6b, 0x9e, 0x4b, 0x90, 0x6b, - 0x53, 0x5f, 0x78, 0x97, 0x5d, 0x2b, 0xae, 0x9f, 0x71, 0x06, 0x45, 0xd1, 0xb9, 0x4f, 0xfd, 0xaa, - 0xdc, 0x44, 0x5b, 0x29, 0x74, 0x56, 0x4f, 0xa4, 0xa3, 0x10, 0x4c, 0x3e, 0x76, 0x49, 0xdf, 0xc0, - 0x23, 0x59, 0xcf, 0x34, 0x63, 0x7b, 0x4b, 0x53, 0x8b, 0xa5, 0x9a, 0xda, 0x35, 0x18, 0x53, 0x75, - 0x4f, 0x5e, 0x4d, 0x71, 0x1d, 0x99, 0xe4, 0x94, 0xee, 0x46, 0xee, 0xe5, 0xeb, 0xca, 0x48, 0x55, - 0xeb, 0xd9, 0x3f, 0x64, 0xe0, 0xf4, 0x6d, 0xde, 0xdc, 0xc4, 0xed, 0xb6, 0x71, 0xbb, 0x38, 0xf2, - 0x59, 0x1c, 0x07, 0xf1, 0x8d, 0x66, 0x20, 0xef, 0x63, 0x56, 0xf3, 0x70, 0x47, 0x3f, 0x89, 0x31, - 0x1f, 0xb3, 0x4d, 0xdc, 0x41, 0x1f, 0xc3, 0x54, 0x27, 0xa2, 0x1d, 0xca, 0x48, 0xd4, 0x7f, 0x56, - 0xe2, 0x49, 0x4c, 0x6c, 0xac, 0xbf, 0x7d, 0x5d, 0x71, 0xfc, 0x16, 0x6f, 0x76, 0xeb, 0x8e, 0x47, - 0x03, 0x57, 0x17, 0x7a, 0xf5, 0xef, 0x2a, 0x6b, 0xec, 0xba, 0x7c, 0xbf, 0x43, 0x98, 0xb3, 0x39, - 0x78, 0xcf, 0xd5, 0x33, 0xb1, 0xad, 0xf8, 0x2d, 0xce, 0x41, 0xc1, 0x6b, 0xe2, 0x56, 0x58, 0x6b, - 0x35, 0x66, 0x73, 0x8b, 0x99, 0xb5, 0x6c, 0x35, 0x2f, 0xd7, 0x77, 0x1b, 0xf6, 0x2a, 0x9c, 0xbb, - 0xcd, 0x78, 0x2b, 0xc0, 0x9c, 0x6c, 0xe1, 0xc1, 0x15, 0x4c, 0x41, 0xd6, 0xc7, 0x8a, 0x7c, 0xae, - 0x2a, 0x3e, 0xed, 0x83, 0x6c, 0x1c, 0xc7, 0x08, 0x7b, 0x64, 0xbb, 0x17, 0xfb, 0x79, 0x19, 0xb2, - 0x01, 0xf3, 0xf5, 0x4d, 0xcd, 0x99, 0x37, 0xf5, 0x80, 0xf9, 0xb7, 0x79, 0x93, 0x44, 0xa4, 0x1b, - 0x6c, 0xf7, 0xaa, 0x42, 0x0b, 0xdd, 0x84, 0x09, 0x2e, 0x8e, 0xd7, 0x3c, 0x1a, 0xee, 0xb4, 0x7c, - 0x1d, 0xd1, 0x19, 0xf3, 0x94, 0x34, 0xbf, 0x29, 0xb7, 0xab, 0x45, 0x3e, 0x58, 0xa0, 0x7f, 0xc3, - 0x44, 0x27, 0x22, 0x0d, 0xe2, 0x11, 0xc6, 0x68, 0x24, 0xee, 0x27, 0x7b, 0x3c, 0x62, 0x42, 0x5d, - 0xd4, 0xc1, 0x7a, 0x9b, 0x7a, 0xbb, 0x71, 0xc5, 0x51, 0xf7, 0x50, 0x94, 0x32, 0x55, 0x6f, 0xd0, - 0x02, 0x80, 0x52, 0x91, 0xcf, 0x62, 0x54, 0x3e, 0x8b, 0x71, 0x29, 0x91, 0x9d, 0x64, 0x33, 0xde, - 0x16, 0x0d, 0x73, 0x76, 0x4c, 0x52, 0xb7, 0x1c, 0xd5, 0x4d, 0x9d, 0xb8, 0x9b, 0x3a, 0xdb, 0x71, - 0x37, 0xdd, 0x28, 0x88, 0x14, 0x79, 0xfe, 0x4b, 0x25, 0xa3, 0x8d, 0x88, 0x9d, 0xd4, 0x48, 0xe7, - 0x3f, 0x4c, 0xa4, 0x0b, 0x89, 0x48, 0x23, 0x1b, 0x26, 0x15, 0xfd, 0x00, 0xf7, 0x6a, 0x22, 0xb8, - 0xe3, 0xc6, 0x0d, 0x3c, 0xc0, 0xbd, 0x2d, 0xcc, 0xec, 0x4b, 0xba, 0x6e, 0xf5, 0x63, 0x3c, 0x28, - 0x2a, 0x0d, 0xcc, 0x71, 0x9c, 0xcc, 0xe2, 0xdb, 0xfe, 0x3e, 0x0b, 0xd3, 0x03, 0xe5, 0x0d, 0x61, - 0xc5, 0xc8, 0x09, 0xde, 0x8b, 0x9f, 0xf6, 0x71, 0x39, 0xc1, 0x7b, 0x6c, 0x28, 0x27, 0xb2, 0xef, - 0x90, 0x13, 0x87, 0x83, 0x3a, 0x7a, 0x52, 0x50, 0xc7, 0x8e, 0x0f, 0x6a, 0xfe, 0xfd, 0x05, 0xb5, - 0xf0, 0x61, 0x82, 0x3a, 0x7e, 0x42, 0x50, 0x61, 0x38, 0xa8, 0x57, 0x61, 0x66, 0x28, 0x4e, 0xc7, - 0xc4, 0xf5, 0x7c, 0xbf, 0xeb, 0x32, 0x72, 0x87, 0xc4, 0xd5, 0xdd, 0xbe, 0xdf, 0xef, 0xa8, 0x5a, - 0xac, 0x4d, 0xdc, 0x80, 0x82, 0x28, 0xc4, 0xb5, 0x1d, 0xa2, 0xbb, 0xda, 0xc6, 0xdc, 0xcf, 0xaf, - 0x2b, 0xe7, 0x95, 0x87, 0xac, 0xb1, 0xeb, 0xb4, 0xa8, 0x1b, 0x60, 0xde, 0x74, 0xee, 0x86, 0x5c, - 0x74, 0x5b, 0x79, 0xda, 0xbe, 0x0c, 0x67, 0xb7, 0x08, 0x7f, 0x4c, 0xc2, 0x06, 0x89, 0xfa, 0xa6, - 0xa6, 0x61, 0x8c, 0x49, 0x89, 0x6e, 0x49, 0x7a, 0xb5, 0xfe, 0xb6, 0x08, 0xa3, 0x12, 0x1b, 0x31, - 0xc8, 0xeb, 0x81, 0x04, 0x55, 0xcc, 0x04, 0x49, 0x99, 0x35, 0xad, 0xc5, 0xa3, 0x15, 0x14, 0x9e, - 0xbd, 0xfc, 0xf9, 0x8f, 0xbf, 0x7d, 0x7b, 0xaa, 0x82, 0x16, 0x5c, 0x63, 0x84, 0xd5, 0x23, 0x88, - 0xfb, 0x54, 0x07, 0xf2, 0x19, 0xfa, 0x26, 0x03, 0x93, 0x89, 0x29, 0x0f, 0x2d, 0x0f, 0x99, 0x4e, - 0x9b, 0x23, 0xad, 0x95, 0x93, 0xd4, 0x34, 0x8f, 0x2b, 0x92, 0xc7, 0x0a, 0xfa, 0x9b, 0xc9, 0x23, - 0x1e, 0x1f, 0x87, 0xe8, 0x7c, 0x97, 0x81, 0xa9, 0xc3, 0xe3, 0x19, 0x5a, 0x1b, 0x82, 0x3a, 0x62, - 0x1e, 0xb4, 0xfe, 0xfe, 0x27, 0x34, 0x35, 0xaf, 0x1b, 0x92, 0x97, 0x83, 0xae, 0x98, 0xbc, 0xf6, - 0x62, 0xed, 0x01, 0x35, 0x73, 0xbe, 0x7c, 0x86, 0x38, 0xe4, 0xf5, 0xd4, 0x95, 0x12, 0xa3, 0xe4, - 0x28, 0x97, 0x12, 0xa3, 0x43, 0x03, 0x9b, 0xbd, 0x22, 0x39, 0x2c, 0xa2, 0xb2, 0xc9, 0x41, 0xcf, - 0x6c, 0xcc, 0xb8, 0x95, 0x7d, 0xc8, 0xeb, 0x61, 0x2b, 0x05, 0x35, 0x39, 0xd3, 0xa5, 0xa0, 0x1e, - 0x9a, 0xd3, 0xec, 0xcb, 0x12, 0x75, 0x19, 0x2d, 0x99, 0xa8, 0x4c, 0x29, 0x0d, 0x40, 0xdd, 0xa7, - 0xbb, 0x64, 0xff, 0x19, 0x6a, 0x42, 0x4e, 0x4c, 0x60, 0x68, 0x3e, 0x25, 0xdc, 0xfd, 0x81, 0xce, - 0x5a, 0x38, 0x62, 0x57, 0x23, 0x2e, 0x49, 0xc4, 0x05, 0x74, 0x21, 0x99, 0x03, 0x8d, 0x84, 0x93, - 0x04, 0xc6, 0xd4, 0xf8, 0x81, 0xca, 0x43, 0xd6, 0x12, 0x93, 0x8d, 0x55, 0x39, 0x72, 0x5f, 0xe3, - 0x59, 0x12, 0xaf, 0x84, 0x90, 0x3b, 0xf4, 0x6b, 0x0f, 0xed, 0x40, 0x5e, 0x0f, 0x33, 0xc8, 0x32, - 0xed, 0x24, 0x27, 0x1c, 0xeb, 0xe2, 0xd1, 0x85, 0x3d, 0x46, 0x99, 0x97, 0x28, 0xd3, 0xa8, 0x64, - 0xa2, 0x10, 0xde, 0xac, 0x79, 0xc2, 0x78, 0x1b, 0x8a, 0xc6, 0xec, 0x71, 0x2c, 0x56, 0xc2, 0x9f, - 0x94, 0x81, 0xc5, 0x5e, 0x94, 0x48, 0x16, 0x9a, 0x4d, 0x20, 0x69, 0x45, 0x51, 0x19, 0xd1, 0x27, - 0x90, 0xd7, 0x6d, 0x2d, 0x25, 0x43, 0x92, 0x43, 0x4d, 0x4a, 0x86, 0x1c, 0xea, 0x88, 0xe9, 0x9e, - 0xa9, 0x3e, 0xc6, 0x7b, 0x68, 0x0f, 0x60, 0x50, 0x6d, 0x91, 0x9d, 0x6e, 0xcd, 0x6c, 0x99, 0xd6, - 0xd2, 0xb1, 0x3a, 0x1a, 0xb4, 0x22, 0x41, 0xe7, 0xd0, 0xcc, 0x30, 0xa8, 0x2c, 0xf8, 0xc2, 0x47, - 0x5d, 0x9f, 0x53, 0xdf, 0x9e, 0x59, 0xd0, 0x53, 0xdf, 0x5e, 0xa2, 0xb4, 0xa7, 0xfb, 0x18, 0x17, - 0x7b, 0x44, 0x60, 0xbc, 0x5f, 0xc2, 0xd1, 0xd1, 0x4d, 0x3e, 0x99, 0xf8, 0x43, 0x45, 0xdf, 0x2e, - 0x4b, 0x90, 0x59, 0x34, 0x6d, 0x82, 0xf8, 0x84, 0xd7, 0x54, 0xf1, 0xdf, 0x78, 0xf8, 0xf2, 0xa0, - 0x9c, 0x79, 0x75, 0x50, 0xce, 0xfc, 0x7a, 0x50, 0xce, 0x3c, 0x7f, 0x53, 0x1e, 0x79, 0xf5, 0xa6, - 0x3c, 0xf2, 0xd3, 0x9b, 0xf2, 0xc8, 0x47, 0x37, 0x8c, 0xbe, 0xaa, 0xce, 0x5e, 0x0d, 0x09, 0xff, - 0x94, 0x46, 0xbb, 0xf1, 0x32, 0xa2, 0xed, 0xf6, 0x6e, 0x8b, 0xbb, 0x3d, 0x75, 0x51, 0xa2, 0xd3, - 0xd6, 0xc7, 0x64, 0x53, 0xff, 0xc7, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xea, 0x16, 0xe0, 0x4b, - 0x9e, 0x11, 0x00, 0x00, + // 1649 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4b, 0x6f, 0x1b, 0xc9, + 0x11, 0xd6, 0x98, 0x94, 0x48, 0x95, 0x1e, 0x96, 0xdb, 0xd4, 0x6b, 0x2c, 0x91, 0xf2, 0x28, 0x7a, + 0xd8, 0xb2, 0x66, 0x2c, 0xc5, 0x08, 0x10, 0x03, 0x41, 0x60, 0x2a, 0xb6, 0x62, 0xf8, 0x01, 0x87, + 0x16, 0x72, 0x08, 0x10, 0x10, 0x4d, 0xb2, 0x35, 0x64, 0xc4, 0x99, 0xa1, 0xa7, 0x9b, 0x0a, 0x19, + 0x43, 0x97, 0x04, 0x08, 0x8c, 0x24, 0x07, 0x23, 0x39, 0x07, 0xf0, 0x29, 0x7f, 0x21, 0x7f, 0xc1, + 0x47, 0x03, 0x7b, 0x59, 0xec, 0xc1, 0xbb, 0x90, 0xf7, 0xb0, 0xbf, 0x61, 0x4f, 0x8b, 0x7e, 0x0c, + 0xd9, 0x43, 0x8e, 0xa4, 0xf5, 0xc2, 0xbe, 0x88, 0xd3, 0xdd, 0xd5, 0xf5, 0x7d, 0xdd, 0x55, 0x5d, + 0x5f, 0x09, 0xe6, 0x70, 0xc8, 0x48, 0x13, 0x3b, 0xe4, 0xd8, 0x73, 0x5e, 0xb4, 0x49, 0xd8, 0xb5, + 0x5b, 0x61, 0xc0, 0x02, 0x04, 0x72, 0xde, 0x26, 0xc7, 0x9e, 0x79, 0x05, 0x7b, 0x0d, 0x3f, 0x70, + 0xc4, 0x5f, 0xb9, 0x6c, 0xe6, 0xdc, 0xc0, 0x0d, 0xc4, 0xa7, 0xc3, 0xbf, 0xd4, 0xec, 0x92, 0x1b, + 0x04, 0x6e, 0x93, 0x38, 0xb8, 0xd5, 0x70, 0xb0, 0xef, 0x07, 0x0c, 0xb3, 0x46, 0xe0, 0x53, 0xb5, + 0x7a, 0xb3, 0x1a, 0x50, 0x2f, 0xa0, 0x4e, 0x05, 0x53, 0x22, 0xb1, 0x9c, 0xe3, 0x9d, 0x0a, 0x61, + 0x78, 0xc7, 0x69, 0x61, 0xb7, 0xe1, 0x0b, 0x63, 0x65, 0x5b, 0x50, 0x9e, 0xc4, 0xa8, 0xd2, 0x3e, + 0x74, 0x58, 0xc3, 0x23, 0x94, 0x61, 0xaf, 0xa5, 0x0c, 0xe6, 0x35, 0xde, 0x2d, 0x1c, 0x62, 0x2f, + 0x42, 0xc9, 0x69, 0x0b, 0xe4, 0xd8, 0x53, 0xb3, 0x57, 0xb5, 0x59, 0xd6, 0x91, 0x93, 0xd6, 0x2f, + 0xe1, 0xea, 0xef, 0x38, 0x8d, 0x7b, 0xd5, 0x6a, 0xd0, 0xf6, 0x59, 0x89, 0xbc, 0x68, 0x13, 0xca, + 0xd0, 0x02, 0x64, 0x70, 0xad, 0x16, 0x12, 0x4a, 0x17, 0x8c, 0x15, 0x63, 0x73, 0xbc, 0x14, 0x0d, + 0xef, 0x66, 0x5f, 0xbd, 0x29, 0x8c, 0x7c, 0xf7, 0xa6, 0x30, 0x62, 0x55, 0x21, 0x17, 0xdf, 0x4a, + 0x5b, 0x81, 0x4f, 0x09, 0xdf, 0x5b, 0xc1, 0x4d, 0xec, 0x57, 0x49, 0xb4, 0x57, 0x0d, 0xd1, 0x35, + 0x18, 0xaf, 0x06, 0x35, 0x52, 0xae, 0x63, 0x5a, 0x5f, 0xb8, 0x24, 0xd6, 0xb2, 0x7c, 0xe2, 0xb7, + 0x98, 0xd6, 0x51, 0x0e, 0x46, 0xfd, 0x80, 0x6f, 0x4a, 0xad, 0x18, 0x9b, 0xe9, 0x92, 0x1c, 0x58, + 0xbf, 0x86, 0x45, 0x01, 0xb2, 0x27, 0xee, 0xed, 0x27, 0xb0, 0xfc, 0xbb, 0x01, 0x66, 0x92, 0x07, + 0x45, 0x76, 0x0d, 0xa6, 0x65, 0x48, 0xca, 0x71, 0x4f, 0x53, 0x72, 0xf6, 0x9e, 0x9c, 0x44, 0x26, + 0x64, 0x29, 0x07, 0xe5, 0xfc, 0x2e, 0x09, 0x7e, 0xbd, 0x31, 0x77, 0x81, 0xa5, 0xd7, 0xb2, 0xdf, + 0xf6, 0x2a, 0x24, 0x54, 0x27, 0x98, 0x52, 0xb3, 0x4f, 0xc5, 0xa4, 0xf5, 0x08, 0x96, 0x04, 0x8f, + 0xdf, 0xe3, 0x66, 0xa3, 0x86, 0x59, 0x10, 0x0e, 0x1c, 0xe6, 0x3a, 0x4c, 0x56, 0x03, 0x7f, 0x90, + 0xc7, 0x04, 0x9f, 0xbb, 0x37, 0x74, 0xaa, 0x7f, 0x1a, 0xb0, 0x7c, 0x86, 0x37, 0x75, 0xb0, 0x0d, + 0xb8, 0x1c, 0xb1, 0x8a, 0x7b, 0x8c, 0xc8, 0x7e, 0xc2, 0xa3, 0x45, 0x49, 0x54, 0x94, 0x71, 0xfe, + 0x98, 0xf0, 0xdc, 0x56, 0x49, 0xd4, 0xdb, 0x7a, 0x51, 0x12, 0x59, 0x8f, 0x14, 0xd8, 0x73, 0x16, + 0x84, 0xd8, 0xbd, 0x18, 0x0c, 0xcd, 0x40, 0xea, 0x88, 0x74, 0x55, 0xbe, 0xf1, 0x4f, 0x0d, 0xfe, + 0x96, 0x82, 0xef, 0x39, 0x53, 0xf0, 0x39, 0x18, 0x3d, 0xc6, 0xcd, 0x76, 0x04, 0x2e, 0x07, 0xd6, + 0x2f, 0x60, 0x46, 0xa5, 0x52, 0xed, 0xa3, 0x0e, 0xb9, 0x01, 0x57, 0xb4, 0x7d, 0x0a, 0x02, 0x41, + 0x9a, 0xe7, 0xbe, 0xd8, 0x35, 0x59, 0x12, 0xdf, 0xd6, 0x5f, 0x00, 0x09, 0xc3, 0x83, 0xce, 0xe3, + 0xc0, 0xa5, 0x11, 0x04, 0x82, 0xb4, 0x78, 0x31, 0xd2, 0xbf, 0xf8, 0x46, 0x0f, 0x00, 0xfa, 0x05, + 0x43, 0x9c, 0x6d, 0x62, 0x77, 0xdd, 0x96, 0x49, 0x6b, 0xf3, 0xea, 0x62, 0xcb, 0x4a, 0xa6, 0xaa, + 0x8b, 0xfd, 0xac, 0x7f, 0x55, 0x25, 0x6d, 0xa7, 0x46, 0xf2, 0x6f, 0x86, 0xba, 0xd8, 0x08, 0x5c, + 0xf1, 0x5c, 0x85, 0x74, 0x33, 0x70, 0xf9, 0xe9, 0x52, 0x9b, 0x13, 0xbb, 0x97, 0xed, 0x7e, 0x51, + 0xb4, 0x1f, 0x07, 0x6e, 0x49, 0x2c, 0xa2, 0xfd, 0x04, 0x3a, 0x1b, 0x17, 0xd2, 0x91, 0x08, 0x3a, + 0x1f, 0x2b, 0xa7, 0x6e, 0xe0, 0x99, 0xa8, 0x67, 0x8a, 0xb1, 0xb5, 0xaf, 0xa8, 0x45, 0xb3, 0x8a, + 0xda, 0x6d, 0x18, 0x93, 0x75, 0x4f, 0x5c, 0xcd, 0xc4, 0x2e, 0xd2, 0xc9, 0x49, 0xdb, 0x62, 0xfa, + 0xed, 0xfb, 0xc2, 0x48, 0x49, 0xd9, 0x59, 0xff, 0x37, 0x60, 0xfa, 0x3e, 0xab, 0xef, 0xe1, 0x66, + 0x53, 0xbb, 0x5d, 0x1c, 0xba, 0x34, 0x8a, 0x03, 0xff, 0x46, 0xf3, 0x90, 0x71, 0x31, 0x2d, 0x57, + 0x71, 0x4b, 0x3d, 0x89, 0x31, 0x17, 0xd3, 0x3d, 0xdc, 0x42, 0x7f, 0x84, 0x99, 0x56, 0x18, 0xb4, + 0x02, 0x4a, 0xc2, 0xde, 0xb3, 0xe2, 0x4f, 0x62, 0xb2, 0xb8, 0xfb, 0xfd, 0xfb, 0x82, 0xed, 0x36, + 0x58, 0xbd, 0x5d, 0xb1, 0xab, 0x81, 0xe7, 0xa8, 0x42, 0x2f, 0x7f, 0xb6, 0x69, 0xed, 0xc8, 0x61, + 0xdd, 0x16, 0xa1, 0xf6, 0x5e, 0xff, 0x3d, 0x97, 0x2e, 0x47, 0xbe, 0xa2, 0xb7, 0xb8, 0x08, 0xd9, + 0x6a, 0x1d, 0x37, 0xfc, 0x72, 0xa3, 0xb6, 0x90, 0x5e, 0x31, 0x36, 0x53, 0xa5, 0x8c, 0x18, 0x3f, + 0xac, 0x59, 0x1b, 0x70, 0xf5, 0x3e, 0x65, 0x0d, 0x0f, 0x33, 0xb2, 0x8f, 0xfb, 0x57, 0x30, 0x03, + 0x29, 0x17, 0x4b, 0xf2, 0xe9, 0x12, 0xff, 0xb4, 0x4e, 0x53, 0x51, 0x1c, 0x43, 0x5c, 0x25, 0x07, + 0x9d, 0xe8, 0x9c, 0x5b, 0x90, 0xf2, 0xa8, 0xab, 0x6e, 0x6a, 0x51, 0xbf, 0xa9, 0x27, 0xd4, 0xbd, + 0xcf, 0xea, 0x24, 0x24, 0x6d, 0xef, 0xa0, 0x53, 0xe2, 0x56, 0xe8, 0x2e, 0x4c, 0x32, 0xbe, 0xbd, + 0x5c, 0x0d, 0xfc, 0xc3, 0x86, 0xab, 0x22, 0x3a, 0xaf, 0xef, 0x12, 0xee, 0xf7, 0xc4, 0x72, 0x69, + 0x82, 0xf5, 0x07, 0xe8, 0x57, 0x30, 0xd9, 0x0a, 0x49, 0x8d, 0x54, 0x09, 0xa5, 0x41, 0xc8, 0xef, + 0x27, 0x75, 0x3e, 0x62, 0xcc, 0x9c, 0xd7, 0xc1, 0x4a, 0x33, 0xa8, 0x1e, 0x45, 0x15, 0x47, 0xde, + 0xc3, 0x84, 0x98, 0x93, 0xf5, 0x06, 0x2d, 0x03, 0x48, 0x13, 0xf1, 0x2c, 0x46, 0xc5, 0xb3, 0x18, + 0x17, 0x33, 0x42, 0x49, 0xf6, 0xa2, 0x65, 0x2e, 0x98, 0x0b, 0x63, 0x82, 0xba, 0x69, 0x4b, 0x35, + 0xb5, 0x23, 0x35, 0xb5, 0x0f, 0x22, 0x35, 0x2d, 0x66, 0x79, 0x8a, 0xbc, 0xfe, 0xba, 0x60, 0x28, + 0x27, 0x7c, 0x25, 0x31, 0xd2, 0x99, 0xcf, 0x13, 0xe9, 0x6c, 0x2c, 0xd2, 0xc8, 0x82, 0x29, 0x49, + 0xdf, 0xc3, 0x9d, 0x32, 0x0f, 0xee, 0xb8, 0x76, 0x03, 0x4f, 0x70, 0x67, 0x1f, 0x53, 0xeb, 0xa6, + 0xaa, 0x5b, 0xbd, 0x18, 0xf7, 0x8b, 0x4a, 0x0d, 0x33, 0x1c, 0x25, 0x33, 0xff, 0xb6, 0xfe, 0x97, + 0x82, 0xb9, 0xbe, 0x71, 0x91, 0x7b, 0xd1, 0x72, 0x82, 0x75, 0xa2, 0xa7, 0x7d, 0x5e, 0x4e, 0xb0, + 0x0e, 0x1d, 0xca, 0x89, 0xd4, 0x47, 0xe4, 0xc4, 0x60, 0x50, 0x47, 0x2f, 0x0a, 0xea, 0xd8, 0xf9, + 0x41, 0xcd, 0x7c, 0xba, 0xa0, 0x66, 0x3f, 0x4f, 0x50, 0xc7, 0x2f, 0x08, 0x2a, 0x0c, 0x07, 0x75, + 0x1b, 0xe6, 0x87, 0xe2, 0x74, 0x4e, 0x5c, 0x67, 0x7b, 0xaa, 0x4b, 0xc9, 0x03, 0x12, 0x55, 0x77, + 0xeb, 0x71, 0x4f, 0x51, 0xd5, 0xb4, 0x72, 0x71, 0x07, 0xb2, 0xbc, 0x10, 0x97, 0x0f, 0x89, 0x52, + 0xb5, 0xe2, 0xe2, 0x57, 0xef, 0x0b, 0xb3, 0xf2, 0x84, 0xb4, 0x76, 0x64, 0x37, 0x02, 0xc7, 0xc3, + 0xac, 0x6e, 0x3f, 0xf4, 0x19, 0x57, 0x5b, 0xb1, 0xdb, 0xda, 0x82, 0x2b, 0xfb, 0x84, 0x3d, 0x27, + 0x7e, 0x8d, 0x84, 0x3d, 0x57, 0x73, 0x30, 0x46, 0xc5, 0x8c, 0x92, 0x24, 0x35, 0xb2, 0x76, 0x60, + 0xf6, 0x37, 0xc4, 0x0f, 0xbc, 0x62, 0x37, 0xba, 0xa2, 0x8b, 0x44, 0xd2, 0xb2, 0x61, 0x6e, 0x70, + 0x4b, 0x5f, 0x82, 0x6b, 0x7c, 0x25, 0x92, 0x60, 0x31, 0xb0, 0xb6, 0x61, 0x56, 0x19, 0x16, 0xbb, + 0x62, 0x63, 0x04, 0x91, 0x6c, 0xbe, 0x0b, 0x73, 0x83, 0xe6, 0xfd, 0x06, 0xa3, 0x4f, 0x29, 0xa5, + 0x51, 0xda, 0xfd, 0xf7, 0x34, 0x8c, 0x8a, 0x1b, 0x44, 0x14, 0x32, 0xaa, 0xad, 0x42, 0x05, 0x3d, + 0xcd, 0x13, 0x3a, 0x66, 0x73, 0xe5, 0x6c, 0x03, 0x89, 0x68, 0xad, 0xfd, 0xf5, 0x8b, 0x6f, 0xff, + 0x73, 0xa9, 0x80, 0x96, 0x1d, 0xad, 0x11, 0x57, 0x8d, 0x94, 0xf3, 0x52, 0xa1, 0x9f, 0xa0, 0x7f, + 0x19, 0x30, 0x15, 0xeb, 0x55, 0xd1, 0xda, 0x90, 0xeb, 0xa4, 0x6e, 0xd8, 0x5c, 0xbf, 0xc8, 0x4c, + 0xf1, 0xb8, 0x25, 0x78, 0xac, 0xa3, 0x9f, 0xe9, 0x3c, 0xa2, 0x26, 0x78, 0x88, 0xce, 0x7f, 0x0d, + 0x98, 0x19, 0x6c, 0x32, 0xd1, 0xe6, 0x10, 0xd4, 0x19, 0x5d, 0xad, 0x79, 0xe3, 0x47, 0x58, 0x2a, + 0x5e, 0x77, 0x04, 0x2f, 0x1b, 0xdd, 0xd2, 0x79, 0x1d, 0x47, 0xd6, 0x7d, 0x6a, 0x7a, 0x97, 0x7c, + 0x82, 0x18, 0x64, 0x54, 0xef, 0x98, 0x10, 0xa3, 0x78, 0x43, 0x9a, 0x10, 0xa3, 0x81, 0xb6, 0xd3, + 0x5a, 0x17, 0x1c, 0x56, 0x50, 0x5e, 0xe7, 0xa0, 0x3a, 0x4f, 0xaa, 0xdd, 0x4a, 0x17, 0x32, 0xaa, + 0x65, 0x4c, 0x40, 0x8d, 0x77, 0xa6, 0x09, 0xa8, 0x03, 0xdd, 0xa6, 0xb5, 0x25, 0x50, 0xd7, 0xd0, + 0xaa, 0x8e, 0x4a, 0xa5, 0x51, 0x1f, 0xd4, 0x79, 0x79, 0x44, 0xba, 0x27, 0xa8, 0x0e, 0x69, 0xde, + 0x47, 0xa2, 0xa5, 0x84, 0x70, 0xf7, 0xda, 0x52, 0x73, 0xf9, 0x8c, 0x55, 0x85, 0xb8, 0x2a, 0x10, + 0x97, 0xd1, 0xb5, 0x78, 0x0e, 0xd4, 0x62, 0x87, 0x24, 0x30, 0x26, 0x9b, 0x28, 0x94, 0x1f, 0xf2, + 0x16, 0xeb, 0xcf, 0xcc, 0xc2, 0x99, 0xeb, 0x0a, 0xcf, 0x14, 0x78, 0x39, 0x84, 0x9c, 0xa1, 0xff, + 0x59, 0xd1, 0x21, 0x64, 0x54, 0x4b, 0x86, 0x4c, 0xdd, 0x4f, 0xbc, 0x4f, 0x33, 0xaf, 0x9f, 0x2d, + 0x4f, 0x11, 0xca, 0x92, 0x40, 0x99, 0x43, 0x39, 0x1d, 0x85, 0xb0, 0x7a, 0xb9, 0xca, 0x9d, 0x37, + 0x61, 0x42, 0xeb, 0xa0, 0xce, 0xc5, 0x8a, 0x9d, 0x27, 0xa1, 0xed, 0xb2, 0x56, 0x04, 0x92, 0x89, + 0x16, 0x62, 0x48, 0xca, 0x90, 0xd7, 0x77, 0xf4, 0x27, 0xc8, 0x28, 0x71, 0x4e, 0xc8, 0x90, 0x78, + 0x6b, 0x96, 0x90, 0x21, 0x03, 0xba, 0x9e, 0x7c, 0x32, 0xa9, 0xc6, 0xac, 0x83, 0x8e, 0x01, 0xfa, + 0x9a, 0x81, 0xac, 0x64, 0x6f, 0xba, 0xf0, 0x9b, 0xab, 0xe7, 0xda, 0x28, 0xd0, 0x82, 0x00, 0x5d, + 0x44, 0xf3, 0xc3, 0xa0, 0x42, 0xb6, 0xf8, 0x19, 0x95, 0xca, 0x24, 0xbe, 0x3d, 0x5d, 0x96, 0x12, + 0xdf, 0x5e, 0x4c, 0xa0, 0x92, 0xcf, 0x18, 0x49, 0x16, 0x22, 0x30, 0xde, 0x13, 0x22, 0x74, 0x76, + 0xab, 0x12, 0x4f, 0xfc, 0x21, 0xe9, 0xb2, 0xf2, 0x02, 0x64, 0x01, 0xcd, 0xe9, 0x20, 0x2e, 0x61, + 0x65, 0x29, 0x61, 0xe8, 0x1f, 0x06, 0x4c, 0xc7, 0x05, 0x09, 0xc5, 0x12, 0x2f, 0x51, 0xdf, 0x4c, + 0xeb, 0x3c, 0x13, 0x85, 0xbc, 0x23, 0x90, 0xb7, 0xd0, 0x8d, 0x58, 0x79, 0xdb, 0x71, 0x84, 0x50, + 0x95, 0x2b, 0xdd, 0xa8, 0xa4, 0x69, 0x0f, 0xf0, 0x95, 0x01, 0xd3, 0x71, 0xf9, 0x8a, 0x93, 0x49, + 0x54, 0xc2, 0x38, 0x99, 0x64, 0xf5, 0xb3, 0x1c, 0x41, 0xe6, 0x06, 0xda, 0x18, 0x20, 0xa3, 0xa0, + 0x39, 0x1d, 0xc1, 0xcb, 0x79, 0x29, 0x7e, 0x4e, 0x8a, 0x4f, 0xdf, 0x9e, 0xe6, 0x8d, 0x77, 0xa7, + 0x79, 0xe3, 0x9b, 0xd3, 0xbc, 0xf1, 0xfa, 0x43, 0x7e, 0xe4, 0xdd, 0x87, 0xfc, 0xc8, 0x97, 0x1f, + 0xf2, 0x23, 0x7f, 0xb8, 0xa3, 0x75, 0x4d, 0xd2, 0xd9, 0xb6, 0x4f, 0xd8, 0x9f, 0x83, 0xf0, 0x28, + 0x1a, 0x86, 0x41, 0xb3, 0x79, 0xd4, 0x60, 0x4e, 0x47, 0x26, 0x10, 0xef, 0xa3, 0x2a, 0x63, 0xa2, + 0x65, 0xfb, 0xf9, 0x0f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3f, 0xd4, 0x4a, 0x3a, 0x7c, 0x13, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1521,6 +1709,10 @@ type QueryClient interface { BaseFee(ctx context.Context, in *QueryBaseFeeRequest, opts ...grpc.CallOption) (*QueryBaseFeeResponse, error) // GetSender gets sender the tx GetSender(ctx context.Context, in *MsgEthereumTx, opts ...grpc.CallOption) (*GetSenderResponse, error) + // DenomByAddress returns the denom mapping to address + DenomByAddress(ctx context.Context, in *DenomByAddressRequest, opts ...grpc.CallOption) (*DenomByAddressResponse, error) + // DenomByAddress returns the denom mapping to address + AddressByDenom(ctx context.Context, in *AddressByDenomRequest, opts ...grpc.CallOption) (*AddressByDenomResponse, error) } type queryClient struct { @@ -1648,6 +1840,24 @@ func (c *queryClient) GetSender(ctx context.Context, in *MsgEthereumTx, opts ... return out, nil } +func (c *queryClient) DenomByAddress(ctx context.Context, in *DenomByAddressRequest, opts ...grpc.CallOption) (*DenomByAddressResponse, error) { + out := new(DenomByAddressResponse) + err := c.cc.Invoke(ctx, "/artela.evm.Query/DenomByAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AddressByDenom(ctx context.Context, in *AddressByDenomRequest, opts ...grpc.CallOption) (*AddressByDenomResponse, error) { + out := new(AddressByDenomResponse) + err := c.cc.Invoke(ctx, "/artela.evm.Query/AddressByDenom", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Account queries an Ethereum account. @@ -1679,6 +1889,10 @@ type QueryServer interface { BaseFee(context.Context, *QueryBaseFeeRequest) (*QueryBaseFeeResponse, error) // GetSender gets sender the tx GetSender(context.Context, *MsgEthereumTx) (*GetSenderResponse, error) + // DenomByAddress returns the denom mapping to address + DenomByAddress(context.Context, *DenomByAddressRequest) (*DenomByAddressResponse, error) + // DenomByAddress returns the denom mapping to address + AddressByDenom(context.Context, *AddressByDenomRequest) (*AddressByDenomResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1724,6 +1938,12 @@ func (*UnimplementedQueryServer) BaseFee(ctx context.Context, req *QueryBaseFeeR func (*UnimplementedQueryServer) GetSender(ctx context.Context, req *MsgEthereumTx) (*GetSenderResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSender not implemented") } +func (*UnimplementedQueryServer) DenomByAddress(ctx context.Context, req *DenomByAddressRequest) (*DenomByAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomByAddress not implemented") +} +func (*UnimplementedQueryServer) AddressByDenom(ctx context.Context, req *AddressByDenomRequest) (*AddressByDenomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddressByDenom not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1963,6 +2183,42 @@ func _Query_GetSender_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Query_DenomByAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DenomByAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomByAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/artela.evm.Query/DenomByAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomByAddress(ctx, req.(*DenomByAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AddressByDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddressByDenomRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AddressByDenom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/artela.evm.Query/AddressByDenom", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AddressByDenom(ctx, req.(*AddressByDenomRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "artela.evm.Query", HandlerType: (*QueryServer)(nil), @@ -2019,6 +2275,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "GetSender", Handler: _Query_GetSender_Handler, }, + { + MethodName: "DenomByAddress", + Handler: _Query_DenomByAddress_Handler, + }, + { + MethodName: "AddressByDenom", + Handler: _Query_AddressByDenom_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "artela/evm/query.proto", @@ -2977,6 +3241,128 @@ func (m *GetSenderResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *DenomByAddressRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DenomByAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomByAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DenomByAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DenomByAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomByAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddressByDenomRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddressByDenomRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddressByDenomRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddressByDenomResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddressByDenomResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddressByDenomResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + for iNdEx := len(m.Address) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Address[iNdEx]) + copy(dAtA[i:], m.Address[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -3399,15 +3785,69 @@ func (m *GetSenderResponse) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *QueryAccountRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 +func (m *DenomByAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *DenomByAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *AddressByDenomRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *AddressByDenomResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Address) > 0 { + for _, s := range m.Address { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryAccountRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 @@ -6120,6 +6560,334 @@ func (m *GetSenderResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *DenomByAddressRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DenomByAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomByAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DenomByAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DenomByAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomByAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddressByDenomRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddressByDenomRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressByDenomRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddressByDenomResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddressByDenomResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressByDenomResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/evm/types/query.pb.gw.go b/x/evm/types/query.pb.gw.go index d9f5177..ede013e 100644 --- a/x/evm/types/query.pb.gw.go +++ b/x/evm/types/query.pb.gw.go @@ -595,6 +595,114 @@ func local_request_Query_GetSender_0(ctx context.Context, marshaler runtime.Mars } +func request_Query_DenomByAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DenomByAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := client.DenomByAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomByAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DenomByAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := server.DenomByAddress(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_AddressByDenom_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AddressByDenomRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := client.AddressByDenom(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AddressByDenom_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AddressByDenomRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := server.AddressByDenom(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -900,6 +1008,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_DenomByAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomByAddress_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomByAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AddressByDenom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AddressByDenom_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AddressByDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1201,6 +1355,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_DenomByAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomByAddress_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomByAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AddressByDenom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AddressByDenom_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AddressByDenom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1230,6 +1424,10 @@ var ( pattern_Query_BaseFee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"artela", "evm", "base_fee"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_GetSender_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"artela", "evm", "get_sender"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomByAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"artela", "evm", "v1", "denom_by_address", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AddressByDenom_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"artela", "evm", "v1", "address_by_denom", "denom"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -1258,4 +1456,8 @@ var ( forward_Query_BaseFee_0 = runtime.ForwardResponseMessage forward_Query_GetSender_0 = runtime.ForwardResponseMessage + + forward_Query_DenomByAddress_0 = runtime.ForwardResponseMessage + + forward_Query_AddressByDenom_0 = runtime.ForwardResponseMessage ) diff --git a/x/evm/types/query_unpacker.go b/x/evm/types/query_unpacker.go new file mode 100644 index 0000000..a281592 --- /dev/null +++ b/x/evm/types/query_unpacker.go @@ -0,0 +1,28 @@ +package types + +import ( + codec "github.com/cosmos/cosmos-sdk/codec/types" +) + +var ( + _ codec.UnpackInterfacesMessage = (*QueryTraceTxRequest)(nil) + _ codec.UnpackInterfacesMessage = (*QueryTraceBlockRequest)(nil) +) + +func (m QueryTraceTxRequest) UnpackInterfaces(unPacker codec.AnyUnpacker) error { + for _, msg := range m.Predecessors { + if err := msg.UnpackInterfaces(unPacker); err != nil { + return err + } + } + return m.Msg.UnpackInterfaces(unPacker) +} + +func (m QueryTraceBlockRequest) UnpackInterfaces(unPacker codec.AnyUnpacker) error { + for _, msg := range m.Txs { + if err := msg.UnpackInterfaces(unPacker); err != nil { + return err + } + } + return nil +} diff --git a/x/fee/keeper/msg_update_params_test.go b/x/fee/keeper/msg_update_params_test.go index c5d2c47..a5dac79 100644 --- a/x/fee/keeper/msg_update_params_test.go +++ b/x/fee/keeper/msg_update_params_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + cosmos "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -12,7 +13,8 @@ import ( func TestMsgUpdateParams(t *testing.T) { k, ms, ctx := setupMsgServer(t) params := types.DefaultParams() - require.NoError(t, k.SetParams(ctx, params)) + sdkCtx := cosmos.UnwrapSDKContext(ctx) + require.NoError(t, k.SetParams(sdkCtx, params)) wctx := sdk.UnwrapSDKContext(ctx) // default params diff --git a/x/fee/types/genesis_test.go b/x/fee/types/genesis_test.go index 8be7553..01ff614 100644 --- a/x/fee/types/genesis_test.go +++ b/x/fee/types/genesis_test.go @@ -3,9 +3,9 @@ package types_test import ( "testing" - "artela/x/fee/types" - "github.com/stretchr/testify/require" + + "github.com/artela-network/artela-rollkit/x/fee/types" ) func TestGenesisState_Validate(t *testing.T) {