diff --git a/api/ethermint/evm/v1/tx.pulsar.go b/api/ethermint/evm/v1/tx.pulsar.go index a8110a1f1f..09535e28ce 100644 --- a/api/ethermint/evm/v1/tx.pulsar.go +++ b/api/ethermint/evm/v1/tx.pulsar.go @@ -21,11 +21,12 @@ import ( ) var ( - md_MsgEthereumTx protoreflect.MessageDescriptor - fd_MsgEthereumTx_data protoreflect.FieldDescriptor - fd_MsgEthereumTx_size protoreflect.FieldDescriptor - fd_MsgEthereumTx_hash protoreflect.FieldDescriptor - fd_MsgEthereumTx_from protoreflect.FieldDescriptor + md_MsgEthereumTx protoreflect.MessageDescriptor + fd_MsgEthereumTx_data protoreflect.FieldDescriptor + fd_MsgEthereumTx_size protoreflect.FieldDescriptor + fd_MsgEthereumTx_hash protoreflect.FieldDescriptor + fd_MsgEthereumTx_deprecated_from protoreflect.FieldDescriptor + fd_MsgEthereumTx_from protoreflect.FieldDescriptor ) func init() { @@ -34,6 +35,7 @@ func init() { fd_MsgEthereumTx_data = md_MsgEthereumTx.Fields().ByName("data") fd_MsgEthereumTx_size = md_MsgEthereumTx.Fields().ByName("size") fd_MsgEthereumTx_hash = md_MsgEthereumTx.Fields().ByName("hash") + fd_MsgEthereumTx_deprecated_from = md_MsgEthereumTx.Fields().ByName("deprecated_from") fd_MsgEthereumTx_from = md_MsgEthereumTx.Fields().ByName("from") } @@ -120,8 +122,14 @@ func (x *fastReflection_MsgEthereumTx) Range(f func(protoreflect.FieldDescriptor return } } - if x.From != "" { - value := protoreflect.ValueOfString(x.From) + if x.DeprecatedFrom != "" { + value := protoreflect.ValueOfString(x.DeprecatedFrom) + if !f(fd_MsgEthereumTx_deprecated_from, value) { + return + } + } + if len(x.From) != 0 { + value := protoreflect.ValueOfBytes(x.From) if !f(fd_MsgEthereumTx_from, value) { return } @@ -147,8 +155,10 @@ func (x *fastReflection_MsgEthereumTx) Has(fd protoreflect.FieldDescriptor) bool return x.Size != float64(0) || math.Signbit(x.Size) case "ethermint.evm.v1.MsgEthereumTx.hash": return x.Hash != "" + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": + return x.DeprecatedFrom != "" case "ethermint.evm.v1.MsgEthereumTx.from": - return x.From != "" + return len(x.From) != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: ethermint.evm.v1.MsgEthereumTx")) @@ -171,8 +181,10 @@ func (x *fastReflection_MsgEthereumTx) Clear(fd protoreflect.FieldDescriptor) { x.Size = float64(0) case "ethermint.evm.v1.MsgEthereumTx.hash": x.Hash = "" + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": + x.DeprecatedFrom = "" case "ethermint.evm.v1.MsgEthereumTx.from": - x.From = "" + x.From = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: ethermint.evm.v1.MsgEthereumTx")) @@ -198,9 +210,12 @@ func (x *fastReflection_MsgEthereumTx) Get(descriptor protoreflect.FieldDescript case "ethermint.evm.v1.MsgEthereumTx.hash": value := x.Hash return protoreflect.ValueOfString(value) + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": + value := x.DeprecatedFrom + return protoreflect.ValueOfString(value) case "ethermint.evm.v1.MsgEthereumTx.from": value := x.From - return protoreflect.ValueOfString(value) + return protoreflect.ValueOfBytes(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: ethermint.evm.v1.MsgEthereumTx")) @@ -227,8 +242,10 @@ func (x *fastReflection_MsgEthereumTx) Set(fd protoreflect.FieldDescriptor, valu x.Size = value.Float() case "ethermint.evm.v1.MsgEthereumTx.hash": x.Hash = value.Interface().(string) + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": + x.DeprecatedFrom = value.Interface().(string) case "ethermint.evm.v1.MsgEthereumTx.from": - x.From = value.Interface().(string) + x.From = value.Bytes() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: ethermint.evm.v1.MsgEthereumTx")) @@ -258,6 +275,8 @@ func (x *fastReflection_MsgEthereumTx) Mutable(fd protoreflect.FieldDescriptor) panic(fmt.Errorf("field size of message ethermint.evm.v1.MsgEthereumTx is not mutable")) case "ethermint.evm.v1.MsgEthereumTx.hash": panic(fmt.Errorf("field hash of message ethermint.evm.v1.MsgEthereumTx is not mutable")) + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": + panic(fmt.Errorf("field deprecated_from of message ethermint.evm.v1.MsgEthereumTx is not mutable")) case "ethermint.evm.v1.MsgEthereumTx.from": panic(fmt.Errorf("field from of message ethermint.evm.v1.MsgEthereumTx is not mutable")) default: @@ -280,8 +299,10 @@ func (x *fastReflection_MsgEthereumTx) NewField(fd protoreflect.FieldDescriptor) return protoreflect.ValueOfFloat64(float64(0)) case "ethermint.evm.v1.MsgEthereumTx.hash": return protoreflect.ValueOfString("") - case "ethermint.evm.v1.MsgEthereumTx.from": + case "ethermint.evm.v1.MsgEthereumTx.deprecated_from": return protoreflect.ValueOfString("") + case "ethermint.evm.v1.MsgEthereumTx.from": + return protoreflect.ValueOfBytes(nil) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: ethermint.evm.v1.MsgEthereumTx")) @@ -362,6 +383,10 @@ func (x *fastReflection_MsgEthereumTx) ProtoMethods() *protoiface.Methods { if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } + l = len(x.DeprecatedFrom) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } l = len(x.From) if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) @@ -400,6 +425,13 @@ func (x *fastReflection_MsgEthereumTx) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], x.From) i = runtime.EncodeVarint(dAtA, i, uint64(len(x.From))) i-- + dAtA[i] = 0x2a + } + if len(x.DeprecatedFrom) > 0 { + i -= len(x.DeprecatedFrom) + copy(dAtA[i:], x.DeprecatedFrom) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.DeprecatedFrom))) + i-- dAtA[i] = 0x22 } if len(x.Hash) > 0 { @@ -559,7 +591,7 @@ func (x *fastReflection_MsgEthereumTx) ProtoMethods() *protoiface.Methods { iNdEx = postIndex case 4: if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field DeprecatedFrom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -587,7 +619,41 @@ func (x *fastReflection_MsgEthereumTx) ProtoMethods() *protoiface.Methods { if postIndex > l { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } - x.From = string(dAtA[iNdEx:postIndex]) + x.DeprecatedFrom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.From = append(x.From[:0], dAtA[iNdEx:postIndex]...) + if x.From == nil { + x.From = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex @@ -5788,10 +5854,12 @@ type MsgEthereumTx struct { Size float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"size,omitempty"` // hash of the transaction in hex format Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` - // from is the ethereum signer address in hex format. This address value is checked + // Deprecated: Do not use. + DeprecatedFrom string `protobuf:"bytes,4,opt,name=deprecated_from,json=deprecatedFrom,proto3" json:"deprecated_from,omitempty"` + // from is the bytes of ethereum signer address. This address value is checked // against the address derived from the signature (V, R, S) using the // secp256k1 elliptic curve - From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` } func (x *MsgEthereumTx) Reset() { @@ -5835,13 +5903,21 @@ func (x *MsgEthereumTx) GetHash() string { return "" } -func (x *MsgEthereumTx) GetFrom() string { +// Deprecated: Do not use. +func (x *MsgEthereumTx) GetDeprecatedFrom() string { if x != nil { - return x.From + return x.DeprecatedFrom } return "" } +func (x *MsgEthereumTx) GetFrom() []byte { + if x != nil { + return x.From + } + return nil +} + // LegacyTx is the transaction data of regular Ethereum transactions. // NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the // AllowUnprotectedTxs parameter is disabled. @@ -6412,7 +6488,7 @@ var file_ethermint_evm_v1_tx_proto_rawDesc = []byte{ 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0xc8, 0x01, 0x0a, 0x0d, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, + 0xf5, 0x01, 0x0a, 0x0d, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x12, 0x45, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x42, 0x1b, 0xca, 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, @@ -6421,145 +6497,147 @@ var file_ethermint_evm_v1_tx_proto_rawDesc = []byte{ 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x42, 0x05, 0xea, 0xde, 0x1f, 0x01, 0x2d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b, 0xf2, 0xde, 0x1f, 0x07, 0x72, 0x6c, 0x70, 0x3a, 0x22, 0x2d, 0x22, 0x52, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x3a, 0x20, 0x88, 0xa0, 0x1f, 0x00, 0x8a, 0xe7, - 0xb0, 0x2a, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x4d, 0x73, 0x67, - 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x22, 0xbe, 0x02, 0x0a, 0x08, 0x4c, - 0x65, 0x67, 0x61, 0x63, 0x79, 0x54, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x44, 0x0a, - 0x09, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x27, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, 0x73, 0x50, 0x72, - 0x69, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x0f, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x0e, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x46, 0x72, 0x6f, + 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x3a, 0x20, 0x88, 0xa0, 0x1f, 0x00, 0x8a, 0xe7, 0xb0, 0x2a, 0x17, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x22, 0xbe, 0x02, 0x0a, 0x08, 0x4c, 0x65, 0x67, 0x61, + 0x63, 0x79, 0x54, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x67, 0x61, + 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xe2, + 0xde, 0x1f, 0x08, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x03, 0x67, 0x61, 0x73, + 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, + 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, + 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x06, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x49, + 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0c, 0x0a, + 0x01, 0x76, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, 0x12, 0x0c, 0x0a, 0x01, 0x72, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, 0x0a, 0x01, 0x73, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, 0x1f, 0x00, 0xca, 0xb4, 0x2d, + 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0xcf, 0x03, 0x0a, 0x0c, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x78, 0x12, 0x4a, 0x0a, 0x08, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, + 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, + 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, + 0x44, 0xea, 0xde, 0x1f, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x52, 0x07, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x67, + 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19, + 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, + 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, 0x73, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xe2, 0xde, 0x1f, 0x08, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x03, - 0x67, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x74, 0x6f, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x67, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x23, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, - 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, 0x12, 0x0c, - 0x0a, 0x01, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, 0x0a, 0x01, - 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, 0x1f, 0x00, - 0xca, 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0xcf, 0x03, 0x0a, 0x0c, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x78, 0x12, 0x4a, 0x0a, 0x08, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x07, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x49, 0x44, 0xea, 0xde, 0x1f, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x52, - 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x36, - 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x19, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, - 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, - 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x42, 0x0c, 0xe2, 0xde, 0x1f, 0x08, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x23, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, - 0xe2, 0xde, 0x1f, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x5b, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x42, 0x20, 0xc8, 0xde, 0x1f, 0x00, 0xea, 0xde, 0x1f, 0x0a, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0xaa, 0xdf, 0x1f, 0x0a, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, - 0x12, 0x0c, 0x0a, 0x01, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, - 0x0a, 0x01, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, - 0x1f, 0x00, 0xca, 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, - 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8d, 0x04, - 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x46, 0x65, 0x65, 0x54, 0x78, 0x12, 0x4a, - 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x07, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0xea, 0xde, 0x1f, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, - 0x44, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x12, 0x39, 0x0a, 0x0b, 0x67, 0x61, 0x73, 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, 0x70, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, - 0x52, 0x09, 0x67, 0x61, 0x73, 0x54, 0x69, 0x70, 0x43, 0x61, 0x70, 0x12, 0x39, 0x0a, 0x0b, 0x67, - 0x61, 0x73, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x19, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x09, 0x67, 0x61, 0x73, - 0x46, 0x65, 0x65, 0x43, 0x61, 0x70, 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x04, 0x42, 0x0c, 0xe2, 0xde, 0x1f, 0x08, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x23, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, - 0xe2, 0xde, 0x1f, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x5b, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x42, 0x20, 0xc8, 0xde, 0x1f, 0x00, 0xea, 0xde, 0x1f, 0x0a, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0xaa, 0xdf, 0x1f, 0x0a, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, - 0x12, 0x0c, 0x0a, 0x01, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, - 0x0a, 0x01, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, - 0x1f, 0x00, 0xca, 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, - 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0x22, 0x0a, - 0x1a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x3a, 0x04, 0x88, 0xa0, 0x1f, - 0x00, 0x22, 0xa4, 0x01, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, - 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, - 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x76, 0x6d, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x76, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, - 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, - 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xba, 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, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, - 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 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, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, - 0x78, 0x2f, 0x65, 0x76, 0x6d, 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, 0xe9, 0x01, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x65, - 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x12, 0x1f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, - 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, - 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x1a, 0x27, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, - 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, - 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x74, 0x68, 0x65, - 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x74, 0x78, 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, + 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x5b, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x08, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, + 0x70, 0x6c, 0x65, 0x42, 0x20, 0xc8, 0xde, 0x1f, 0x00, 0xea, 0xde, 0x1f, 0x0a, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0xaa, 0xdf, 0x1f, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, 0x12, 0x0c, 0x0a, + 0x01, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, 0x0a, 0x01, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, 0x1f, 0x00, 0xca, + 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8d, 0x04, 0x0a, 0x0c, 0x44, + 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x46, 0x65, 0x65, 0x54, 0x78, 0x12, 0x4a, 0x0a, 0x08, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x07, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x49, 0x44, 0xea, 0xde, 0x1f, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x52, 0x07, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x39, 0x0a, + 0x0b, 0x67, 0x61, 0x73, 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x19, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x09, 0x67, + 0x61, 0x73, 0x54, 0x69, 0x70, 0x43, 0x61, 0x70, 0x12, 0x39, 0x0a, 0x0b, 0x67, 0x61, 0x73, 0x5f, + 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x09, 0x67, 0x61, 0x73, 0x46, 0x65, 0x65, + 0x43, 0x61, 0x70, 0x12, 0x1e, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x0c, 0xe2, 0xde, 0x1f, 0x08, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x03, + 0x67, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x23, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, + 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x5b, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x09, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, + 0x70, 0x6c, 0x65, 0x42, 0x20, 0xc8, 0xde, 0x1f, 0x00, 0xea, 0xde, 0x1f, 0x0a, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0xaa, 0xdf, 0x1f, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x76, 0x12, 0x0c, 0x0a, + 0x01, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x72, 0x12, 0x0c, 0x0a, 0x01, 0x73, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x01, 0x73, 0x3a, 0x1f, 0x88, 0xa0, 0x1f, 0x00, 0xca, + 0xb4, 0x2d, 0x17, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x78, 0x44, 0x61, 0x74, 0x61, 0x22, 0x22, 0x0a, 0x1a, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xa4, + 0x01, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, + 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x74, 0x68, + 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, + 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x6d, 0x5f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x6d, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, + 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xba, 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, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, + 0x6d, 0x2e, 0x76, 0x31, 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, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x78, 0x2f, 0x65, + 0x76, 0x6d, 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, 0xe9, 0x01, + 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x54, 0x78, 0x12, 0x1f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, + 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x75, 0x6d, 0x54, 0x78, 0x1a, 0x27, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x74, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x5f, 0x74, 0x78, 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x65, 0x74, 0x68, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x31, 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, 0xaa, 0x01, 0x0a, - 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, - 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x27, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x65, 0x76, 0x6d, - 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x45, 0x45, 0x58, 0xaa, - 0x02, 0x10, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x45, 0x76, 0x6d, 0x2e, - 0x56, 0x31, 0xca, 0x02, 0x10, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x5c, 0x45, - 0x76, 0x6d, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, - 0x74, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, - 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 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, 0xaa, 0x01, 0x0a, 0x14, 0x63, 0x6f, + 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x65, 0x76, 0x6d, 0x2e, + 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x31, + 0x3b, 0x65, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x45, 0x45, 0x58, 0xaa, 0x02, 0x10, 0x45, + 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x31, 0xca, + 0x02, 0x10, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x5c, 0x45, 0x76, 0x6d, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x5c, 0x45, + 0x76, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x3a, 0x3a, 0x45, + 0x76, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 8fb0b5fae7..a149ff7022 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -70,7 +70,7 @@ func (suite AnteTestSuite) TestAnteHandler() { suite.Require().NoError(acc.SetSequence(1)) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000)) + suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000), evmtypes.DefaultEVMDenom) suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100)) } @@ -96,7 +96,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -117,7 +117,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -138,7 +138,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -160,7 +160,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -182,7 +182,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -204,7 +204,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -225,7 +225,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -235,7 +235,7 @@ func (suite AnteTestSuite) TestAnteHandler() { "fail - CheckTx (cosmos tx is not valid)", func() sdk.Tx { signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) // bigger than MaxGasWanted @@ -247,7 +247,7 @@ func (suite AnteTestSuite) TestAnteHandler() { "fail - CheckTx (memo too long)", func() sdk.Tx { signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) txBuilder.SetMemo(strings.Repeat("*", 257)) @@ -258,7 +258,7 @@ func (suite AnteTestSuite) TestAnteHandler() { "fail - CheckTx (ExtensionOptionsEthereumTx not set)", func() sdk.Tx { signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false, true) return txBuilder.GetTx() @@ -272,7 +272,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress()) suite.Require().NoError(err) signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, true) return tx @@ -284,7 +284,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress()) suite.Require().NoError(err) signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) txBuilder.SetMemo("memo for cosmos tx not allowed") @@ -297,7 +297,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress()) suite.Require().NoError(err) signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) txBuilder.SetTimeoutHeight(10) @@ -310,7 +310,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress()) suite.Require().NoError(err) signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) @@ -330,7 +330,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress()) suite.Require().NoError(err) signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) @@ -590,10 +590,12 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - msg.From = addr.Hex() + msg.From = addr.Bytes() tx := suite.CreateTestTx(msg, privKey, 1, false) msg = tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx) - msg.From = addr.Hex() + msg.From = addr.Bytes() + // arbitrary modify + msg.From[0] = msg.From[0] + 1 return tx }, true, false, false, }, @@ -907,7 +909,7 @@ func (suite AnteTestSuite) TestAnteHandler() { nil, nil, ) - ethTx.From = addr.Hex() + ethTx.From = addr.Bytes() msg := authz.NewMsgExec( sdk.AccAddress(privKey.PubKey().Address()), @@ -977,7 +979,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -999,7 +1001,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -1021,7 +1023,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -1044,7 +1046,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1067,7 +1069,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1090,7 +1092,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1113,7 +1115,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1136,7 +1138,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) // bigger than MaxGasWanted @@ -1161,7 +1163,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false) txBuilder.SetMemo(strings.Repeat("*", 257)) @@ -1184,7 +1186,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -1205,7 +1207,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() { suite.app.AccountKeeper.SetAccount(suite.ctx, acc) suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx) - suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000)) + suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000), evmtypes.DefaultEVMDenom) _, err := suite.anteHandler(suite.ctx, tc.txFn(), false) if tc.expPass { suite.Require().NoError(err) @@ -1243,7 +1245,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -1265,7 +1267,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() { nil, &types.AccessList{}, ) - signedContractTx.From = addr.Hex() + signedContractTx.From = addr.Bytes() tx := suite.CreateTestTx(signedContractTx, privKey, 1, false) return tx @@ -1288,7 +1290,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1311,7 +1313,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() { nil, &types.AccessList{}, ) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() tx := suite.CreateTestTx(signedTx, privKey, 1, false) return tx @@ -1334,7 +1336,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() { suite.app.AccountKeeper.SetAccount(suite.ctx, acc) suite.ctx = suite.ctx.WithIsCheckTx(true) - suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000)) + suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000), evmtypes.DefaultEVMDenom) _, err := suite.anteHandler(suite.ctx, tc.txFn(), false) if tc.expErr == nil { suite.Require().NoError(err) diff --git a/app/ante/authz_test.go b/app/ante/authz_test.go index 0b83d9081f..2999f9d549 100644 --- a/app/ante/authz_test.go +++ b/app/ante/authz_test.go @@ -227,6 +227,8 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { _, testAddresses, err := generatePrivKeyAddressPairs(10) suite.Require().NoError(err) + fromAddr := []byte{0, 0} + testcases := []struct { name string msgs []sdk.Msg @@ -238,7 +240,7 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { msgs: []sdk.Msg{ newGenericMsgGrant( testAddresses, - sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), + sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{From: fromAddr}), ), }, expectedCode: sdkerrors.ErrUnauthorized.ABCICode(), @@ -258,7 +260,7 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { msgs: []sdk.Msg{ newGenericMsgGrant( testAddresses, - sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), + sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{From: fromAddr}), ), }, expectedCode: sdkerrors.ErrUnauthorized.ABCICode(), @@ -271,7 +273,7 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { testAddresses[1], []sdk.Msg{ createMsgSend(testAddresses), - &evmtypes.MsgEthereumTx{}, + &evmtypes.MsgEthereumTx{From: fromAddr}, }, ), }, @@ -284,7 +286,7 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { testAddresses[1], 2, []sdk.Msg{ - &evmtypes.MsgEthereumTx{}, + &evmtypes.MsgEthereumTx{From: fromAddr}, }, ), }, @@ -326,7 +328,7 @@ func (suite *AnteTestSuite) TestRejectDeliverMsgsInAuthz() { bz, err := txEncoder(tx) suite.Require().NoError(err) - resCheckTx, _ := suite.app.CheckTx( + resCheckTx, _ := suite.app.CheckTxSync( &abci.RequestCheckTx{ Tx: bz, Type: abci.CheckTxType_New, diff --git a/app/ante/eip712.go b/app/ante/eip712.go index 368b7165fb..33d3a371fc 100644 --- a/app/ante/eip712.go +++ b/app/ante/eip712.go @@ -62,7 +62,7 @@ func NewLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), authante.NewValidateMemoDecorator(options.AccountKeeper), authante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - authante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), + NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators authante.NewSetPubKeyDecorator(options.AccountKeeper), authante.NewValidateSigCountDecorator(options.AccountKeeper), @@ -71,7 +71,6 @@ func NewLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { NewLegacyEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), authante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), ) } diff --git a/app/ante/eth.go b/app/ante/eth.go index 2a1403e926..5e148331aa 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -16,6 +16,7 @@ package ante import ( + "fmt" "math" "math/big" @@ -31,7 +32,6 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" ) // EthAccountVerificationDecorator validates an account balance checks @@ -88,13 +88,14 @@ func (avd EthAccountVerificationDecorator) AnteHandle( if acct == nil { acc := avd.ak.NewAccountWithAddress(ctx, from) avd.ak.SetAccount(ctx, acc) - acct = statedb.NewEmptyAccount() } else if acct.IsContract() { return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) } - if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil { + params := avd.evmKeeper.GetParams(ctx) + balance := avd.evmKeeper.GetBalance(ctx, from, params.EvmDenom) + if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(balance), txData); err != nil { return ctx, errorsmod.Wrap(err, "failed to check sender balance") } } @@ -173,15 +174,13 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula return ctx, errorsmod.Wrap(err, "failed to unpack tx data") } - if ctx.IsCheckTx() && egcd.maxGasWanted != 0 { - // We can't trust the tx gas limit, because we'll refund the unused gas. - if txData.GetGas() > egcd.maxGasWanted { - gasWanted += egcd.maxGasWanted - } else { - gasWanted += txData.GetGas() - } - } else { - gasWanted += txData.GetGas() + // We can't trust the tx gas limit, because we'll refund the unused gas. + gasLimit := msgEthTx.GetGas() + if egcd.maxGasWanted != 0 { + gasLimit = min(gasLimit, egcd.maxGasWanted) + } + if gasWanted > math.MaxInt64-gasLimit { + return ctx, fmt.Errorf("gasWanted(%d) + gasLimit(%d) overflow", gasWanted, gasLimit) } evmDenom := evmParams.GetEvmDenom() @@ -191,7 +190,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula return ctx, errorsmod.Wrapf(err, "failed to verify the fees") } - err = egcd.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.HexToAddress(msgEthTx.From)) + err = egcd.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.BytesToAddress(msgEthTx.From)) if err != nil { return ctx, errorsmod.Wrapf(err, "failed to deduct transaction costs from user balance") } @@ -260,7 +259,6 @@ func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator { func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { params := ctd.evmKeeper.GetParams(ctx) ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID()) - signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight())) for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) @@ -270,11 +268,11 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg) - coreMsg, err := msgEthTx.AsMessage(signer, baseFee) + coreMsg, err := msgEthTx.AsMessage(baseFee) if err != nil { return ctx, errorsmod.Wrapf( err, - "failed to create an ethereum core.Message from signer %T", signer, + "failed to create an ethereum core.Message", ) } diff --git a/app/ante/eth_test.go b/app/ante/eth_test.go index f97b0b5b41..f1df45c8c7 100644 --- a/app/ante/eth_test.go +++ b/app/ante/eth_test.go @@ -25,7 +25,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() { addr := tests.GenerateAddress() tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - tx.From = addr.Hex() + tx.From = addr.Bytes() var vmdb *statedb.StateDB @@ -112,7 +112,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() { addr := tests.GenerateAddress() tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - tx.From = addr.Hex() + tx.From = addr.Bytes() testCases := []struct { name string @@ -168,7 +168,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() { txGasLimit := uint64(1000) tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), txGasLimit, big.NewInt(1), nil, nil, nil, nil) - tx.From = addr.Hex() + tx.From = addr.Bytes() ethCfg := suite.app.EvmKeeper.GetParams(suite.ctx). ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID()) @@ -185,7 +185,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() { tx2GasLimit := uint64(1000000) tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}}) - tx2.From = addr.Hex() + tx2.From = addr.Bytes() tx2Priority := int64(1) tx3GasLimit := ethermint.BlockGasLimit(suite.ctx) + uint64(1) @@ -196,7 +196,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() { new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap evmtypes.DefaultPriorityReduction.BigInt(), // gasTipCap nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}}) - dynamicFeeTx.From = addr.Hex() + dynamicFeeTx.From = addr.Bytes() dynamicFeeTxPriority := int64(1) var vmdb *statedb.StateDB @@ -354,7 +354,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() { ðtypes.AccessList{}, ) - tx.From = addr.Hex() + tx.From = addr.Bytes() err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) @@ -413,18 +413,18 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() { addr, privKey := tests.NewAddrKey() contract := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 0, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - contract.From = addr.Hex() + contract.From = addr.Bytes() err := contract.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) to := tests.GenerateAddress() tx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 0, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - tx.From = addr.Hex() + tx.From = addr.Bytes() err = tx.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) tx2 := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - tx2.From = addr.Hex() + tx2.From = addr.Bytes() err = tx2.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) diff --git a/app/ante/fee_checker.go b/app/ante/fee_checker.go index ba0b2112e6..3e4560c5f0 100644 --- a/app/ante/fee_checker.go +++ b/app/ante/fee_checker.go @@ -111,9 +111,17 @@ func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker { // checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per // unit of gas is fixed and set by each validator, and the tx priority is computed from the gas price. -func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, int64, error) { - feeCoins := tx.GetFee() - gas := tx.GetGas() +func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, 0, errorsmod.Wrap(errortypes.ErrTxDecode, "Tx must be a FeeTx") + } + + feeCoins := feeTx.GetFee() + gas, err := ethermint.SafeInt64(feeTx.GetGas()) + if err != nil { + return nil, 0, err + } minGasPrices := ctx.MinGasPrices() // Ensure that the provided fees meet a minimum threshold for the validator, diff --git a/app/ante/fee_market.go b/app/ante/fee_market.go deleted file mode 100644 index d92261bb36..0000000000 --- a/app/ante/fee_market.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Evmos Foundation -// This file is part of Evmos' Ethermint library. -// -// The Ethermint library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The Ethermint library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE -package ante - -import ( - "math/big" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store -// for BaseFee calculation. -// NOTE: This decorator does not perform any validation -type GasWantedDecorator struct { - evmKeeper EVMKeeper - feeMarketKeeper FeeMarketKeeper -} - -// NewGasWantedDecorator creates a new NewGasWantedDecorator -func NewGasWantedDecorator( - evmKeeper EVMKeeper, - feeMarketKeeper FeeMarketKeeper, -) GasWantedDecorator { - return GasWantedDecorator{ - evmKeeper, - feeMarketKeeper, - } -} - -func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - evmParams := gwd.evmKeeper.GetParams(ctx) - chainCfg := evmParams.GetChainConfig() - ethCfg := chainCfg.EthereumConfig(gwd.evmKeeper.ChainID()) - - blockHeight := big.NewInt(ctx.BlockHeight()) - isLondon := ethCfg.IsLondon(blockHeight) - - feeTx, ok := tx.(sdk.FeeTx) - if !ok || !isLondon { - return next(ctx, tx, simulate) - } - - gasWanted := feeTx.GetGas() - isBaseFeeEnabled := gwd.feeMarketKeeper.GetBaseFeeEnabled(ctx) - - // Add total gasWanted to cumulative in block transientStore in FeeMarket module - if isBaseFeeEnabled { - if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil { - return ctx, errorsmod.Wrapf(err, "failed to add gas wanted to transient store") - } - } - - return next(ctx, tx, simulate) -} diff --git a/app/ante/fee_market_test.go b/app/ante/fee_market_test.go deleted file mode 100644 index 48a765ca4c..0000000000 --- a/app/ante/fee_market_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package ante_test - -import ( - "math/big" - - sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/evmos/ethermint/app/ante" - "github.com/evmos/ethermint/tests" - evmtypes "github.com/evmos/ethermint/x/evm/types" -) - -func (suite AnteTestSuite) TestGasWantedDecorator() { - suite.enableFeemarket = true - suite.SetupTest() - dec := ante.NewGasWantedDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper) - from, fromPrivKey := tests.NewAddrKey() - to := tests.GenerateAddress() - - testCases := []struct { - name string - expectedGasWanted uint64 - malleate func() sdk.Tx - }{ - { - "Cosmos Tx", - TestGasLimit, - func() sdk.Tx { - denom := evmtypes.DefaultEVMDenom - testMsg := banktypes.MsgSend{ - FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp", - ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn", - Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}}, - } - txBuilder := suite.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), "stake", &testMsg) - return txBuilder.GetTx() - }, - }, - { - "Ethereum Legacy Tx", - TestGasLimit, - func() sdk.Tx { - msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil) - return suite.CreateTestTx(msg, fromPrivKey, 1, false) - }, - }, - { - "Ethereum Access List Tx", - TestGasLimit, - func() sdk.Tx { - emptyAccessList := ethtypes.AccessList{} - msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, &emptyAccessList) - return suite.CreateTestTx(msg, fromPrivKey, 1, false) - }, - }, - { - "Ethereum Dynamic Fee Tx (EIP1559)", - TestGasLimit, - func() sdk.Tx { - emptyAccessList := ethtypes.AccessList{} - msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), big.NewInt(100), big.NewInt(50), &emptyAccessList) - return suite.CreateTestTx(msg, fromPrivKey, 1, false) - }, - }, - { - "EIP712 message", - 200000, - func() sdk.Tx { - amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20))) - gas := uint64(200000) - acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, from.Bytes()) - suite.Require().NoError(acc.SetSequence(1)) - suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - tx := suite.CreateTestEIP712TxBuilderMsgSend(acc.GetAddress(), fromPrivKey, suite.ctx.ChainID(), gas, amount) - return tx.GetTx() - }, - }, - } - - // cumulative gas wanted from all test transactions in the same block - var expectedGasWanted uint64 - - for _, tc := range testCases { - suite.Run(tc.name, func() { - _, err := dec.AnteHandle(suite.ctx, tc.malleate(), false, NextFn) - suite.Require().NoError(err) - - gasWanted := suite.app.FeeMarketKeeper.GetTransientGasWanted(suite.ctx) - expectedGasWanted += tc.expectedGasWanted - suite.Require().Equal(expectedGasWanted, gasWanted) - }) - } -} diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index d541ebfc03..0b5105b1c0 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -79,8 +79,7 @@ func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { NewCanTransferDecorator(options.EvmKeeper), NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted), NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator. - NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), - NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler. + NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler. ) } @@ -96,7 +95,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), + NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), @@ -104,6 +103,5 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), ) } diff --git a/app/ante/interfaces.go b/app/ante/interfaces.go index e48e0a50a4..d931089cea 100644 --- a/app/ante/interfaces.go +++ b/app/ante/interfaces.go @@ -46,10 +46,6 @@ type EVMKeeper interface { NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error - GetBalance(ctx sdk.Context, addr common.Address) *big.Int - ResetTransientGasUsed(ctx sdk.Context) - GetTxIndexTransient(ctx sdk.Context) uint64 - GetParams(ctx sdk.Context) evmtypes.Params } type protoTxProvider interface { @@ -59,6 +55,4 @@ type protoTxProvider interface { // FeeMarketKeeper defines the expected keeper interface used on the AnteHandler type FeeMarketKeeper interface { GetParams(ctx sdk.Context) (params feemarkettypes.Params) - AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error) - GetBaseFeeEnabled(ctx sdk.Context) bool } diff --git a/app/ante/nativefee.go b/app/ante/nativefee.go new file mode 100644 index 0000000000..50d05af04c --- /dev/null +++ b/app/ante/nativefee.go @@ -0,0 +1,127 @@ +package ante + +import ( + "bytes" + "fmt" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/types" + + evmkeeper "github.com/evmos/ethermint/x/evm/keeper" + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +// DeductFeeDecorator deducts fees from the fee payer. The fee payer is the fee granter (if specified) or first signer of the tx. +// If the fee payer does not have the funds to pay for the fees, return an InsufficientFunds error. +// Call next AnteHandler if fees successfully deducted. +// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator +type DeductFeeDecorator struct { + accountKeeper ante.AccountKeeper + bankKeeper evmtypes.BankKeeper + feegrantKeeper ante.FeegrantKeeper + txFeeChecker ante.TxFeeChecker +} + +func NewDeductFeeDecorator(ak ante.AccountKeeper, bk evmtypes.BankKeeper, fk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { + if tfc == nil { + tfc = checkTxFeeWithValidatorMinGasPrices + } + + return DeductFeeDecorator{ + accountKeeper: ak, + bankKeeper: bk, + feegrantKeeper: fk, + txFeeChecker: tfc, + } +} + +func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + } + + var ( + priority int64 + err error + ) + + fee := feeTx.GetFee() + if !simulate { + fee, priority, err = dfd.txFeeChecker(ctx, tx) + if err != nil { + return ctx, err + } + } + if err := dfd.checkDeductFee(ctx, tx, fee); err != nil { + return ctx, err + } + + newCtx := ctx.WithPriority(priority) + + return next(newCtx, tx, simulate) +} + +func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error { + feeTx, ok := sdkTx.(sdk.FeeTx) + if !ok { + return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil { + return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) + } + + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + deductFeesFrom := feePayer + + // if feegranter set deduct fee from feegranter account. + // this works with only when feegrant enabled. + if feeGranter != nil { + feeGranterAddr := sdk.AccAddress(feeGranter) + + if dfd.feegrantKeeper == nil { + return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") + } else if !bytes.Equal(feeGranterAddr, feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranterAddr, feePayer, fee, sdkTx.GetMsgs()) + if err != nil { + return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranterAddr + } + + deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) + } + + // deduct the fees + if !fee.IsZero() { + err := evmkeeper.DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + if err != nil { + return err + } + } + + events := sdk.Events{ + sdk.NewEvent( + sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), + sdk.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()), + ), + } + ctx.EventManager().EmitEvents(events) + + return nil +} diff --git a/app/ante/setup.go b/app/ante/setup.go index 43c07927fe..137acea4fe 100644 --- a/app/ante/setup.go +++ b/app/ante/setup.go @@ -17,7 +17,6 @@ package ante import ( "errors" - "strconv" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" @@ -53,9 +52,6 @@ func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul WithKVGasConfig(storetypes.GasConfig{}). WithTransientKVGasConfig(storetypes.GasConfig{}) - // Reset transient gas used to prepare the execution of current cosmos tx. - // Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs. - esc.evmKeeper.ResetTransientGasUsed(ctx) return next(newCtx, tx, simulate) } @@ -73,8 +69,7 @@ func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator { func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { // After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc, // we need to emit some basic events at the very end of ante handler to be indexed by tendermint. - txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx) - for i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) @@ -85,7 +80,6 @@ func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat ctx.EventManager().EmitEvent(sdk.NewEvent( evmtypes.EventTypeEthereumTx, sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash), - sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)), //#nosec G115 )) } @@ -172,11 +166,6 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) } - // Validate `From` field - if msgEthTx.From != "" { - return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From) - } - txGasLimit += msgEthTx.GetGas() txData, err := evmtypes.UnpackTxData(msgEthTx.Data) diff --git a/app/ante/signverify_test.go b/app/ante/signverify_test.go index 6dd8b2dd2b..51b56e58dc 100644 --- a/app/ante/signverify_test.go +++ b/app/ante/signverify_test.go @@ -14,12 +14,12 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() { addr, privKey := tests.NewAddrKey() signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - signedTx.From = addr.Hex() + signedTx.From = addr.Bytes() err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) unprotectedTx := evmtypes.NewTxContract(nil, 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) - unprotectedTx.From = addr.Hex() + unprotectedTx.From = addr.Bytes() err = unprotectedTx.Sign(ethtypes.HomesteadSigner{}, tests.NewSigner(privKey)) suite.Require().NoError(err) diff --git a/app/ante/sigs_test.go b/app/ante/sigs_test.go index 0c7b0539c8..22a5bebe52 100644 --- a/app/ante/sigs_test.go +++ b/app/ante/sigs_test.go @@ -17,11 +17,12 @@ func (suite AnteTestSuite) TestSignatures() { acc := statedb.NewEmptyAccount() acc.Nonce = 1 - acc.Balance = big.NewInt(10000000000) + balance := big.NewInt(10000000000) suite.app.EvmKeeper.SetAccount(suite.ctx, addr, *acc) + suite.app.EvmKeeper.SetBalance(suite.ctx, addr, balance, evmtypes.DefaultEVMDenom) msgEthereumTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil) - msgEthereumTx.From = addr.Hex() + msgEthereumTx.From = addr.Bytes() // CreateTestTx will sign the msgEthereumTx but not sign the cosmos tx since we have signCosmosTx as false tx := suite.CreateTestTx(msgEthereumTx, privKey, 1, false) diff --git a/app/ante/sigverify.go b/app/ante/sigverify.go index bf590496db..c187c46f2f 100644 --- a/app/ante/sigverify.go +++ b/app/ante/sigverify.go @@ -16,15 +16,14 @@ package ante import ( - "math/big" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" - ethtypes "github.com/ethereum/go-ethereum/core/types" evmtypes "github.com/evmos/ethermint/x/evm/types" ) +const EthSigVerificationResultCacheKey = "ante:EthSigVerificationResult" + // EthSigVerificationDecorator validates an ethereum signatures type EthSigVerificationDecorator struct { evmKeeper EVMKeeper @@ -37,45 +36,60 @@ func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator { } } +// if v, ok := ctx.GetIncarnationCache(EthSigVerificationResultCacheKey); ok { +// if v != nil { +// err = v.(error) +// } +// } else { +// ethSigner := ethtypes.MakeSigner(blockCfg.ChainConfig, blockCfg.BlockNumber) +// err = VerifyEthSig(tx, ethSigner) +// ctx.SetIncarnationCache(EthSigVerificationResultCacheKey, err) +// } + // AnteHandle validates checks that the registered chain id is the same as the one on the message, and // that the signer address matches the one defined on the message. // It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work. // Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user // won't see the error message. -func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { +func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + var err error + + if v, ok := ctx.GetIncarnationCache(EthSigVerificationResultCacheKey); ok { + if v != nil { + err = v.(error) + } + } else { + err = esvd.VerifyEthSig(ctx, tx) + ctx.SetIncarnationCache(EthSigVerificationResultCacheKey, err) + } + if err != nil { + return ctx, err + } + + return next(ctx, tx, simulate) +} + +func (esvd EthSigVerificationDecorator) VerifyEthSig(ctx sdk.Context, tx sdk.Tx) error { chainID := esvd.evmKeeper.ChainID() evmParams := esvd.evmKeeper.GetParams(ctx) - chainCfg := evmParams.GetChainConfig() - ethCfg := chainCfg.EthereumConfig(chainID) - blockNum := big.NewInt(ctx.BlockHeight()) - signer := ethtypes.MakeSigner(ethCfg, blockNum) - for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) + return errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) } allowUnprotectedTxs := evmParams.GetAllowUnprotectedTxs() ethTx := msgEthTx.AsTransaction() if !allowUnprotectedTxs && !ethTx.Protected() { - return ctx, errorsmod.Wrapf( + return errorsmod.Wrapf( errortypes.ErrNotSupported, "rejected unprotected Ethereum transaction. Please EIP155 sign your transaction to protect it against replay-attacks") } - sender, err := signer.Sender(ethTx) - if err != nil { - return ctx, errorsmod.Wrapf( - errortypes.ErrorInvalidSigner, - "couldn't retrieve sender address from the ethereum transaction: %s", - err.Error(), - ) + if err := msgEthTx.VerifySender(chainID); err != nil { + return errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "signature verification failed: %s", err.Error()) } - - // set up the sender to the transaction field if not already - msgEthTx.From = sender.Hex() } - return next(ctx, tx, simulate) + return nil } diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index 124078e951..2596269122 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -9,28 +9,23 @@ import ( protov2 "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/staking" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/evmos/ethermint/ethereum/eip712" - "github.com/evmos/ethermint/testutil" - utiltx "github.com/evmos/ethermint/testutil/tx" - "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" sdkmath "cosmossdk.io/math" "cosmossdk.io/simapp" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/evidence" + evtypes "cosmossdk.io/x/evidence/types" + "cosmossdk.io/x/feegrant" txsigning "cosmossdk.io/x/tx/signing" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" @@ -38,31 +33,28 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" sdkante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authz "github.com/cosmos/cosmos-sdk/x/authz" - authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" - "github.com/evmos/ethermint/crypto/ethsecp256k1" - - evtypes "cosmossdk.io/x/evidence/types" - "cosmossdk.io/x/feegrant" - feegrantmodule "cosmossdk.io/x/feegrant/module" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/bank" + authz "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/evmos/ethermint/app" ante "github.com/evmos/ethermint/app/ante" - "github.com/evmos/ethermint/encoding" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/ethereum/eip712" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/x/evm" + "github.com/evmos/ethermint/testutil" + "github.com/evmos/ethermint/testutil/config" + utiltx "github.com/evmos/ethermint/testutil/tx" "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" ) type AnteTestSuite struct { @@ -134,7 +126,7 @@ func (suite *AnteTestSuite) SetupTest() { acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - encodingConfig := encoding.MakeTestEncodingConfig(auth.AppModuleBasic{}, authzmodule.AppModuleBasic{}, bank.AppModuleBasic{}, evidence.AppModuleBasic{}, evm.AppModuleBasic{}, feegrantmodule.AppModuleBasic{}, gov.AppModuleBasic{}, staking.AppModuleBasic{}) + encodingConfig := config.MakeConfigForTest(suite.app.BasicModuleManager) // We're using TestMsg amino encoding in some tests, so register it here. encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) eip712.SetEncodingConfig(encodingConfig) @@ -206,7 +198,7 @@ func (s *AnteTestSuite) BuildTestEthTx( input, accesses, ) - msgEthereumTx.From = from.String() + msgEthereumTx.From = from.Bytes() return msgEthereumTx } @@ -241,7 +233,6 @@ func (suite *AnteTestSuite) CreateTestTxBuilder( err = msg.Sign(suite.ethSigner, tests.NewSigner(priv)) suite.Require().NoError(err) - msg.From = "" err = builder.SetMsgs(msg) suite.Require().NoError(err) @@ -573,7 +564,7 @@ func (suite *AnteTestSuite) RegisterAccount(pubKey cryptotypes.PubKey, balance * acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, sdk.AccAddress(pubKey.Address())) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.EvmKeeper.SetBalance(suite.ctx, common.BytesToAddress(pubKey.Address()), balance) + suite.app.EvmKeeper.SetBalance(suite.ctx, common.BytesToAddress(pubKey.Address()), balance, evmtypes.DefaultEVMDenom) } // createSignerBytes generates sign doc bytes using the given parameters diff --git a/app/app.go b/app/app.go index f99ec18648..c4a1b9172a 100644 --- a/app/app.go +++ b/app/app.go @@ -21,6 +21,7 @@ import ( "io" "os" "path/filepath" + "sort" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" @@ -134,6 +135,7 @@ import ( "github.com/evmos/ethermint/app/ante" enccodec "github.com/evmos/ethermint/encoding/codec" "github.com/evmos/ethermint/ethereum/eip712" + srvconfig "github.com/evmos/ethermint/server/config" srvflags "github.com/evmos/ethermint/server/flags" ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" @@ -193,6 +195,7 @@ type EthermintApp struct { keys map[string]*storetypes.KVStoreKey tkeys map[string]*storetypes.TransientStoreKey memKeys map[string]*storetypes.MemoryStoreKey + okeys map[string]*storetypes.ObjectStoreKey // keepers AccountKeeper authkeeper.AccountKeeper @@ -307,6 +310,7 @@ func NewEthermintApp( bApp.SetVersion(version.Version) bApp.SetInterfaceRegistry(interfaceRegistry) bApp.SetTxEncoder(txConfig.TxEncoder()) + bApp.SetDisableBlockGasMeter(true) keys := storetypes.NewKVStoreKeys( // SDK keys @@ -326,8 +330,9 @@ func NewEthermintApp( } // Add the EVM transient store key - tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey) + tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey, evmtypes.ObjectStoreKey) app := &EthermintApp{ BaseApp: bApp, legacyAmino: legacyAmino, @@ -337,6 +342,7 @@ func NewEthermintApp( keys: keys, tkeys: tkeys, memKeys: memKeys, + okeys: okeys, } // init params keeper and subspaces @@ -378,6 +384,7 @@ func NewEthermintApp( app.BankKeeper = bankkeeper.NewBaseKeeper( appCodec, runtime.NewKVStoreService(keys[banktypes.StoreKey]), + okeys[banktypes.ObjectStoreKey], app.AccountKeeper, app.BlockedAddrs(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), @@ -561,7 +568,7 @@ func NewEthermintApp( feeMarketSs := app.GetSubspace(feemarkettypes.ModuleName) app.FeeMarketKeeper = feemarketkeeper.NewKeeper( appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - runtime.NewKVStoreService(keys[feemarkettypes.StoreKey]), tkeys[feemarkettypes.TransientKey], feeMarketSs, + runtime.NewKVStoreService(keys[feemarkettypes.StoreKey]), feeMarketSs, ) // Set authority to x/gov module account to only expect the module account to update params @@ -570,7 +577,7 @@ func NewEthermintApp( app.EvmKeeper = evmkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evmtypes.StoreKey]), - tkeys[evmtypes.TransientKey], + okeys[evmtypes.ObjectStoreKey], authtypes.NewModuleAddress(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, @@ -684,6 +691,7 @@ func NewEthermintApp( // NOTE: fee market module must go last in order to retrieve the block gas used. app.ModuleManager.SetOrderEndBlockers( + banktypes.ModuleName, crisistypes.ModuleName, govtypes.ModuleName, evmtypes.ModuleName, @@ -695,7 +703,6 @@ func NewEthermintApp( ibctransfertypes.ModuleName, capabilitytypes.ModuleName, authtypes.ModuleName, - banktypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, minttypes.ModuleName, @@ -785,6 +792,7 @@ func NewEthermintApp( app.MountKVStores(keys) app.MountTransientStores(tkeys) app.MountMemoryStores(memKeys) + app.MountObjectStores(okeys) // initialize BaseApp app.SetInitChainer(app.InitChainer) @@ -830,6 +838,19 @@ func NewEthermintApp( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper + executor := cast.ToString(appOpts.Get(srvflags.EVMBlockExecutor)) + switch executor { + case srvconfig.BlockExecutorBlockSTM: + sdk.SetAddrCacheEnabled(false) + workers := cast.ToInt(appOpts.Get(srvflags.EVMBlockSTMWorkers)) + preEstimate := cast.ToBool(appOpts.Get(srvflags.EVMBlockSTMPreEstimate)) + app.SetTxExecutor(STMTxExecutor(app.GetStoreKeys(), workers, preEstimate, app.EvmKeeper, txConfig.TxDecoder())) + case "", srvconfig.BlockExecutorSequential: + app.SetTxExecutor(DefaultTxExecutor) + default: + panic(fmt.Errorf("unknown EVM block executor: %s", executor)) + } + return app } @@ -982,16 +1003,6 @@ func (app *EthermintApp) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } -// GetStoreKeys returns all the stored store keys. -func (app *EthermintApp) GetStoreKeys() []storetypes.StoreKey { - keys := make([]storetypes.StoreKey, len(app.keys)) - for _, key := range app.keys { - keys = append(keys, key) - } - - return keys -} - // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. @@ -1006,6 +1017,25 @@ func (app *EthermintApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } +// GetStoreKeys returns all the stored store keys. +func (app *EthermintApp) GetStoreKeys() []storetypes.StoreKey { + keys := make([]storetypes.StoreKey, 0, len(app.keys)) + for _, key := range app.keys { + keys = append(keys, key) + } + for _, key := range app.tkeys { + keys = append(keys, key) + } + for _, key := range app.memKeys { + keys = append(keys, key) + } + for _, key := range app.okeys { + keys = append(keys, key) + } + sort.SliceStable(keys, func(i, j int) bool { return keys[i].Name() < keys[j].Name() }) + return keys +} + // GetSubspace returns a param subspace for a given module name. // // NOTE: This is solely to be used for testing purposes. diff --git a/app/executor.go b/app/executor.go new file mode 100644 index 0000000000..1cff225d61 --- /dev/null +++ b/app/executor.go @@ -0,0 +1,256 @@ +package app + +import ( + "context" + "io" + "sync" + "sync/atomic" + + "cosmossdk.io/collections" + "cosmossdk.io/log" + "cosmossdk.io/store/cachemulti" + storetypes "cosmossdk.io/store/types" + abci "github.com/cometbft/cometbft/abci/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + + blockstm "github.com/crypto-org-chain/go-block-stm" +) + +const MinimalParallelPreEstimate = 16 + +func DefaultTxExecutor(_ context.Context, + txs [][]byte, + ms storetypes.MultiStore, + deliverTxWithMultiStore func(int, sdk.Tx, storetypes.MultiStore, map[string]any) *abci.ExecTxResult, +) ([]*abci.ExecTxResult, error) { + blockSize := len(txs) + results := make([]*abci.ExecTxResult, blockSize) + for i := 0; i < blockSize; i++ { + results[i] = deliverTxWithMultiStore(i, nil, ms, nil) + } + return evmtypes.PatchTxResponses(results), nil +} + +type evmKeeper interface { + GetParams(ctx sdk.Context) evmtypes.Params +} + +func STMTxExecutor( + stores []storetypes.StoreKey, + workers int, + estimate bool, + evmKeeper evmKeeper, + txDecoder sdk.TxDecoder, +) baseapp.TxExecutor { + var authStore, bankStore int + index := make(map[storetypes.StoreKey]int, len(stores)) + for i, k := range stores { + switch k.Name() { + case authtypes.StoreKey: + authStore = i + case banktypes.StoreKey: + bankStore = i + } + index[k] = i + } + return func( + ctx context.Context, + txs [][]byte, + ms storetypes.MultiStore, + deliverTxWithMultiStore func(int, sdk.Tx, storetypes.MultiStore, map[string]any) *abci.ExecTxResult, + ) ([]*abci.ExecTxResult, error) { + blockSize := len(txs) + if blockSize == 0 { + return nil, nil + } + results := make([]*abci.ExecTxResult, blockSize) + incarnationCache := make([]atomic.Pointer[map[string]any], blockSize) + for i := 0; i < blockSize; i++ { + m := make(map[string]any) + incarnationCache[i].Store(&m) + } + + var ( + estimates []blockstm.MultiLocations + memTxs []sdk.Tx + ) + if estimate { + // pre-estimation + evmDenom := evmKeeper.GetParams(sdk.NewContext(ms, cmtproto.Header{}, false, log.NewNopLogger())).EvmDenom + memTxs, estimates = preEstimates(txs, workers, authStore, bankStore, evmDenom, txDecoder) + } + + if err := blockstm.ExecuteBlockWithEstimates( + ctx, + blockSize, + index, + stmMultiStoreWrapper{ms}, + workers, + estimates, + func(txn blockstm.TxnIndex, ms blockstm.MultiStore) { + var cache map[string]any + + // only one of the concurrent incarnations gets the cache if there are any, otherwise execute without + // cache, concurrent incarnations should be rare. + v := incarnationCache[txn].Swap(nil) + if v != nil { + cache = *v + } + + var memTx sdk.Tx + if memTxs != nil { + memTx = memTxs[txn] + } + results[txn] = deliverTxWithMultiStore(int(txn), memTx, msWrapper{ms}, cache) + + if v != nil { + incarnationCache[txn].Store(v) + } + }, + ); err != nil { + return nil, err + } + + return evmtypes.PatchTxResponses(results), nil + } +} + +type msWrapper struct { + blockstm.MultiStore +} + +var _ storetypes.MultiStore = msWrapper{} + +func (ms msWrapper) getCacheWrapper(key storetypes.StoreKey) storetypes.CacheWrapper { + return ms.GetStore(key) +} + +func (ms msWrapper) GetStore(key storetypes.StoreKey) storetypes.Store { + return ms.MultiStore.GetStore(key) +} + +func (ms msWrapper) GetKVStore(key storetypes.StoreKey) storetypes.KVStore { + return ms.MultiStore.GetKVStore(key) +} + +func (ms msWrapper) GetObjKVStore(key storetypes.StoreKey) storetypes.ObjKVStore { + return ms.MultiStore.GetObjKVStore(key) +} + +func (ms msWrapper) CacheMultiStore() storetypes.CacheMultiStore { + return cachemulti.NewFromParent(ms.getCacheWrapper, nil, nil) +} + +// Implements CacheWrapper. +func (ms msWrapper) CacheWrap() storetypes.CacheWrap { + return ms.CacheMultiStore().(storetypes.CacheWrap) +} + +// GetStoreType returns the type of the store. +func (ms msWrapper) GetStoreType() storetypes.StoreType { + return storetypes.StoreTypeMulti +} + +// Implements interface MultiStore +func (ms msWrapper) SetTracer(io.Writer) storetypes.MultiStore { + return nil +} + +// Implements interface MultiStore +func (ms msWrapper) SetTracingContext(storetypes.TraceContext) storetypes.MultiStore { + return nil +} + +// Implements interface MultiStore +func (ms msWrapper) TracingEnabled() bool { + return false +} + +type stmMultiStoreWrapper struct { + storetypes.MultiStore +} + +var _ blockstm.MultiStore = stmMultiStoreWrapper{} + +func (ms stmMultiStoreWrapper) GetStore(key storetypes.StoreKey) storetypes.Store { + return ms.MultiStore.GetStore(key) +} + +func (ms stmMultiStoreWrapper) GetKVStore(key storetypes.StoreKey) storetypes.KVStore { + return ms.MultiStore.GetKVStore(key) +} + +func (ms stmMultiStoreWrapper) GetObjKVStore(key storetypes.StoreKey) storetypes.ObjKVStore { + return ms.MultiStore.GetObjKVStore(key) +} + +// preEstimates returns a static estimation of the written keys for each transaction. +// NOTE: make sure it sync with the latest sdk logic when sdk upgrade. +func preEstimates(txs [][]byte, workers, authStore, bankStore int, evmDenom string, txDecoder sdk.TxDecoder) ([]sdk.Tx, []blockstm.MultiLocations) { + memTxs := make([]sdk.Tx, len(txs)) + estimates := make([]blockstm.MultiLocations, len(txs)) + + job := func(start, end int) { + for i := start; i < end; i++ { + rawTx := txs[i] + tx, err := txDecoder(rawTx) + if err != nil { + continue + } + memTxs[i] = tx + + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + continue + } + feePayer := sdk.AccAddress(feeTx.FeePayer()) + + // account key + accKey, err := collections.EncodeKeyWithPrefix( + authtypes.AddressStoreKeyPrefix, + sdk.AccAddressKey, + feePayer, + ) + if err != nil { + continue + } + + // balance key + balanceKey, err := collections.EncodeKeyWithPrefix( + banktypes.BalancesPrefix, + collections.PairKeyCodec(sdk.AccAddressKey, collections.StringKey), + collections.Join(feePayer, evmDenom), + ) + if err != nil { + continue + } + + estimates[i] = blockstm.MultiLocations{ + authStore: {accKey}, + bankStore: {balanceKey}, + } + } + } + + blockSize := len(txs) + chunk := (blockSize + workers - 1) / workers + var wg sync.WaitGroup + for i := 0; i < blockSize; i += chunk { + start := i + end := min(i+chunk, blockSize) + wg.Add(1) + go func() { + defer wg.Done() + job(start, end) + }() + } + wg.Wait() + + return memTxs, estimates +} diff --git a/encoding/config_test.go b/encoding/config_test.go index abfb364a6a..3372c8e61f 100644 --- a/encoding/config_test.go +++ b/encoding/config_test.go @@ -19,7 +19,7 @@ func TestTxEncoding(t *testing.T) { signer := tests.NewSigner(key) msg := evmtypes.NewTxContract(big.NewInt(1), 1, big.NewInt(10), 100000, nil, big.NewInt(1), big.NewInt(1), []byte{}, nil) - msg.From = addr.Hex() + msg.From = addr.Bytes() ethSigner := ethtypes.LatestSignerForChainID(big.NewInt(1)) err := msg.Sign(ethSigner, signer) diff --git a/ethereum/eip712/eip712_test.go b/ethereum/eip712/eip712_test.go index b7ee6720d6..2ff76be2d4 100644 --- a/ethereum/eip712/eip712_test.go +++ b/ethereum/eip712/eip712_test.go @@ -6,43 +6,39 @@ import ( "fmt" "testing" - "cosmossdk.io/math" + "github.com/stretchr/testify/suite" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" "google.golang.org/protobuf/types/known/anypb" - chainparams "cosmossdk.io/simapp/params" - "github.com/cosmos/cosmos-sdk/client" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/evmos/ethermint/ethereum/eip712" - "github.com/tidwall/gjson" - "github.com/tidwall/sjson" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/evmos/ethermint/crypto/ethsecp256k1" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + "cosmossdk.io/math" + chainparams "cosmossdk.io/simapp/params" txsigning "cosmossdk.io/x/tx/signing" + + "github.com/cosmos/cosmos-sdk/client" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/evmos/ethermint/cmd/config" - "github.com/evmos/ethermint/encoding" - "github.com/evmos/ethermint/testutil" - evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - "github.com/cosmos/cosmos-sdk/x/bank" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/distribution" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/gov" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/suite" + + "github.com/evmos/ethermint/cmd/config" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/ethereum/eip712" + "github.com/evmos/ethermint/testutil" + testutilconfig "github.com/evmos/ethermint/testutil/config" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) // Unit tests for single-signer EIP-712 signature verification. Multi-signature key verification tests are out-of-scope @@ -79,7 +75,7 @@ func TestEIP712TestSuite(t *testing.T) { } func (suite *EIP712TestSuite) SetupTest() { - suite.config = encoding.MakeTestEncodingConfig(bank.AppModuleBasic{}, distribution.AppModuleBasic{}, gov.AppModuleBasic{}, staking.AppModuleBasic{}) + suite.config = testutilconfig.MakeConfigForTest(nil) suite.clientCtx = client.Context{}.WithTxConfig(suite.config.TxConfig) suite.denom = evmtypes.DefaultEVMDenom diff --git a/go.mod b/go.mod index 9d58996446..395c271091 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.21.1 require ( cosmossdk.io/api v0.7.5 cosmossdk.io/client/v2 v2.0.0-beta.1 + cosmossdk.io/collections v0.4.0 cosmossdk.io/core v0.12.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 @@ -30,6 +31,7 @@ require ( github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ibc-go/v8 v8.3.2 github.com/cosmos/rosetta v0.0.0-20231205133638-3bc76705a1c6 + github.com/crypto-org-chain/go-block-stm v0.0.0-20240912024944-1cd89976aa5e github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/ethereum/go-ethereum v1.10.26 github.com/gogo/protobuf v1.3.2 @@ -69,7 +71,6 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/storage v1.38.0 // indirect - cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/x/nft v0.0.0-20231023160833-026631cd833c // indirect filippo.io/edwards25519 v1.0.0 // indirect @@ -247,13 +248,15 @@ require ( replace ( cosmossdk.io/core => cosmossdk.io/core v0.11.0 - cosmossdk.io/store => github.com/b-harvest/cosmos-sdk/store v0.0.0-20240925105008-8cc581adc6ab + cosmossdk.io/store => github.com/b-harvest/cosmos-sdk/store v0.0.0-20241023051620-117b11194645 // use cosmos keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 - + github.com/cometbft/cometbft => github.com/b-harvest/cometbft v0.0.0-20241021060352-7d9f293f8c5a + github.com/cosmos/cosmos-sdk => github.com/b-harvest/cosmos-sdk v0.0.0-20241021060906-7eff48e2b5b9 github.com/ethereum/go-ethereum => github.com/b-harvest/go-ethereum v0.0.0-20240925105515-5fa8b7772734 // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/tidwall/btree => github.com/crypto-org-chain/btree v0.0.0-20240406140148-2687063b042c ) diff --git a/go.sum b/go.sum index dcae4d5c79..0c5c3eb10b 100644 --- a/go.sum +++ b/go.sum @@ -265,8 +265,12 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.224 h1:09CiaaF35nRmxrzWZ2uRq5v6Ghg/d2RiPjZnSgtt+RQ= github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/b-harvest/cosmos-sdk/store v0.0.0-20240925105008-8cc581adc6ab h1:IuA4JC3sPwBW7mg3CIEZMLUDq8hx4Kv0Ljp+r+XtAt4= -github.com/b-harvest/cosmos-sdk/store v0.0.0-20240925105008-8cc581adc6ab/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= +github.com/b-harvest/cometbft v0.0.0-20241021060352-7d9f293f8c5a h1:tnnn4OXbZH3hAdb/tT8imSCAzjxxgIe4s4YwZujkiFA= +github.com/b-harvest/cometbft v0.0.0-20241021060352-7d9f293f8c5a/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o= +github.com/b-harvest/cosmos-sdk v0.0.0-20241021060906-7eff48e2b5b9 h1:Qfnl4hukT93/QkkNkgaRXytlUg2In1oJBoZTBKA/Nbw= +github.com/b-harvest/cosmos-sdk v0.0.0-20241021060906-7eff48e2b5b9/go.mod h1:seWWi+rIN4sSTYy/kJ771yxR2drgeEDvblJPdrd1ckM= +github.com/b-harvest/cosmos-sdk/store v0.0.0-20241023051620-117b11194645 h1:V9/zJ1nZkO1iKkuUrQ/bKvS1ZfZDr7mObUODKKP/b4E= +github.com/b-harvest/cosmos-sdk/store v0.0.0-20241023051620-117b11194645/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= github.com/b-harvest/go-ethereum v0.0.0-20240925105515-5fa8b7772734 h1:7uYMhLMyZgyEuulnqAVaD5wWua66nbY3kS62fFQaoeE= github.com/b-harvest/go-ethereum v0.0.0-20240925105515-5fa8b7772734/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -367,8 +371,6 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg= -github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o= github.com/cometbft/cometbft-db v0.11.0 h1:M3Lscmpogx5NTbb1EGyGDaFRdsoLWrUWimFEyf7jej8= github.com/cometbft/cometbft-db v0.11.0/go.mod h1:GDPJAC/iFHNjmZZPN8V8C1yr/eyityhi2W1hz2MGKSc= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -385,8 +387,6 @@ github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAK github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.50.8 h1:2UJHssUaGHTl4/dFp8xyREKAnfiRU6VVfqtKG9n8w5g= -github.com/cosmos/cosmos-sdk v0.50.8/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= @@ -421,6 +421,10 @@ github.com/creachadair/tomledit v0.0.24 h1:5Xjr25R2esu1rKCbQEmjZYlrhFkDspoAbAKb6 github.com/creachadair/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/crypto-org-chain/btree v0.0.0-20240406140148-2687063b042c h1:MOgfS4+FBB8cMkDE2j2VBVsbY+HCkPIu0YsJ/9bbGeQ= +github.com/crypto-org-chain/btree v0.0.0-20240406140148-2687063b042c/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/crypto-org-chain/go-block-stm v0.0.0-20240912024944-1cd89976aa5e h1:FFpE6+Y4o5GxkeGwUcETM6amgohh7msWvWf1MDqueVc= +github.com/crypto-org-chain/go-block-stm v0.0.0-20240912024944-1cd89976aa5e/go.mod h1:iwQTX9xMX8NV9k3o2BiWXA0SswpsZrDk5q3gA7nWYiE= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= @@ -1106,8 +1110,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= -github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= diff --git a/indexer/kv_indexer_test.go b/indexer/kv_indexer_test.go index 202ddc6d8a..0e80058153 100644 --- a/indexer/kv_indexer_test.go +++ b/indexer/kv_indexer_test.go @@ -4,21 +4,28 @@ import ( "math/big" "testing" - "cosmossdk.io/log" - "cosmossdk.io/simapp/params" + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/types" + + "cosmossdk.io/log" + "cosmossdk.io/simapp/params" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/client" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/ethermint/crypto/ethsecp256k1" evmenc "github.com/evmos/ethermint/encoding" "github.com/evmos/ethermint/indexer" "github.com/evmos/ethermint/tests" + "github.com/evmos/ethermint/testutil/config" "github.com/evmos/ethermint/x/evm" "github.com/evmos/ethermint/x/evm/types" - "github.com/stretchr/testify/require" ) func TestKVIndexer(t *testing.T) { @@ -32,11 +39,11 @@ func TestKVIndexer(t *testing.T) { tx := types.NewTx( nil, 0, &to, big.NewInt(1000), 21000, nil, nil, nil, nil, nil, ) - tx.From = from.Hex() + tx.From = from.Bytes() require.NoError(t, tx.Sign(ethSigner, signer)) txHash := tx.AsTransaction().Hash() - encodingConfig := MakeEncodingConfig() + encodingConfig := config.MakeConfigForTest(nil) clientCtx := client.Context{}.WithTxConfig(encodingConfig.TxConfig).WithCodec(encodingConfig.Codec) // build cosmos-sdk wrapper tx diff --git a/proto/ethermint/evm/v1/tx.proto b/proto/ethermint/evm/v1/tx.proto index 1ec22a84cc..49a228e888 100644 --- a/proto/ethermint/evm/v1/tx.proto +++ b/proto/ethermint/evm/v1/tx.proto @@ -38,10 +38,11 @@ message MsgEthereumTx { double size = 2 [(gogoproto.jsontag) = "-"]; // hash of the transaction in hex format string hash = 3 [(gogoproto.moretags) = "rlp:\"-\""]; - // from is the ethereum signer address in hex format. This address value is checked + string deprecated_from = 4 [deprecated = true]; + // from is the bytes of ethereum signer address. This address value is checked // against the address derived from the signature (V, R, S) using the // secp256k1 elliptic curve - string from = 4; + bytes from = 5; } // LegacyTx is the transaction data of regular Ethereum transactions. diff --git a/rpc/backend/backend_suite_test.go b/rpc/backend/backend_suite_test.go index 0a230937e1..fba76ac8c0 100644 --- a/rpc/backend/backend_suite_test.go +++ b/rpc/backend/backend_suite_test.go @@ -7,15 +7,19 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/suite" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/suite" "github.com/evmos/ethermint/crypto/ethsecp256k1" "github.com/evmos/ethermint/crypto/hd" @@ -24,15 +28,16 @@ import ( "github.com/evmos/ethermint/rpc/backend/mocks" rpctypes "github.com/evmos/ethermint/rpc/types" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/x/evm" + "github.com/evmos/ethermint/testutil/config" evmtypes "github.com/evmos/ethermint/x/evm/types" ) type BackendTestSuite struct { suite.Suite - backend *Backend - acc sdk.AccAddress - signer keyring.Signer + backend *Backend + acc sdk.AccAddress + signer keyring.Signer + signerAddress sdk.AccAddress } func TestBackendTestSuite(t *testing.T) { @@ -66,8 +71,9 @@ func (suite *BackendTestSuite) SetupTest() { priv, err := ethsecp256k1.GenerateKey() suite.signer = tests.NewSigner(priv) suite.Require().NoError(err) + suite.signerAddress = sdk.AccAddress(priv.PubKey().Address().Bytes()) - encodingConfig := encoding.MakeTestEncodingConfig(evm.AppModuleBasic{}) + encodingConfig := config.MakeConfigForTest(nil) clientCtx := client.Context{}.WithChainID(ChainID). WithHeight(1). WithTxConfig(encodingConfig.TxConfig). @@ -102,12 +108,12 @@ func (suite *BackendTestSuite) buildEthereumTx() (*evmtypes.MsgEthereumTx, []byt nil, nil, ) - - // A valid msg should have empty `From` - msgEthereumTx.From = "" + msgEthereumTx.From = suite.signerAddress + err := msgEthereumTx.Sign(ethtypes.LatestSignerForChainID(suite.backend.chainID), suite.signer) + suite.Require().NoError(err) txBuilder := suite.backend.clientCtx.TxConfig.NewTxBuilder() - err := txBuilder.SetMsgs(msgEthereumTx) + err = txBuilder.SetMsgs(msgEthereumTx) suite.Require().NoError(err) bz, err := suite.backend.clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) @@ -176,7 +182,7 @@ func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEth RegisterParamsWithoutHeader(queryClient, 1) ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig()) - msgEthereumTx.From = from.String() + msgEthereumTx.From = from.Bytes() err := msgEthereumTx.Sign(ethSigner, signer) suite.Require().NoError(err) diff --git a/rpc/backend/call_tx.go b/rpc/backend/call_tx.go index 7967d06fe2..eaca9087cb 100644 --- a/rpc/backend/call_tx.go +++ b/rpc/backend/call_tx.go @@ -131,7 +131,7 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { } ethereumTx := &evmtypes.MsgEthereumTx{} - if err := ethereumTx.FromEthereumTx(tx); err != nil { + if err := ethereumTx.FromSignedEthereumTx(tx, b.chainID); err != nil { b.logger.Error("transaction converting failed", "error", err.Error()) return common.Hash{}, err } diff --git a/rpc/backend/call_tx_test.go b/rpc/backend/call_tx_test.go index 88f7faeb4f..d480d491df 100644 --- a/rpc/backend/call_tx_test.go +++ b/rpc/backend/call_tx_test.go @@ -300,6 +300,8 @@ func (suite *BackendTestSuite) TestSendRawTransaction() { "fail - unprotected transactions", func() { suite.backend.allowUnprotectedTxs = false + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParamsWithoutHeaderError(queryClient, 1) }, rlpEncodedBz, common.Hash{}, diff --git a/rpc/backend/tracing_test.go b/rpc/backend/tracing_test.go index 308ee1b61a..bb47757138 100644 --- a/rpc/backend/tracing_test.go +++ b/rpc/backend/tracing_test.go @@ -37,12 +37,12 @@ func (suite *BackendTestSuite) TestTraceTransaction() { txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder() - msgEthereumTx.From = from.String() + msgEthereumTx.From = from.Bytes() msgEthereumTx.Sign(ethSigner, suite.signer) tx, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") txBz, _ := txEncoder(tx) - msgEthereumTx2.From = from.String() + msgEthereumTx2.From = from.Bytes() msgEthereumTx2.Sign(ethSigner, suite.signer) tx2, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton") txBz2, _ := txEncoder(tx2) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index b2ad8d3207..961bb77e90 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -194,7 +194,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } - from, err := ethMsg.GetSender(chainID.ToInt()) + from, err := ethMsg.GetSenderLegacy(chainID.ToInt()) if err != nil { return nil, err } diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index 61c2abdb63..fac86b9204 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -103,7 +103,7 @@ func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height i break } - sender, err := ethMsg.GetSender(b.chainID) + sender, err := ethMsg.GetSenderLegacy(b.chainID) if err != nil { continue } diff --git a/server/cmt_abci.go b/server/cmt_abci.go index 74040f2451..8222baff17 100644 --- a/server/cmt_abci.go +++ b/server/cmt_abci.go @@ -24,8 +24,20 @@ func (w cometABCIWrapper) Query(ctx context.Context, req *abci.RequestQuery) (*a return w.app.Query(ctx, req) } -func (w cometABCIWrapper) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { - return w.app.CheckTx(req) +func (w cometABCIWrapper) CheckTxSyncForApp(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { + return w.app.CheckTxSync(req) +} + +func (w cometABCIWrapper) CheckTxAsyncForApp(_ context.Context, req *abci.RequestCheckTx, cb abci.CheckTxCallback) { + w.app.CheckTxAsync(req, cb) +} + +func (w cometABCIWrapper) BeginRecheckTx(_ context.Context, req *abci.RequestBeginRecheckTx) (*abci.ResponseBeginRecheckTx, error) { + return w.app.BeginRecheckTx(req) +} + +func (w cometABCIWrapper) EndRecheckTx(_ context.Context, req *abci.RequestEndRecheckTx) (*abci.ResponseEndRecheckTx, error) { + return w.app.EndRecheckTx(req) } func (w cometABCIWrapper) InitChain(_ context.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { diff --git a/server/config/config.go b/server/config/config.go index c30d72a1b7..4d1ec14e15 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -75,9 +75,16 @@ const ( // DefaultMaxOpenConnections represents the amount of open connections (unlimited = 0) DefaultMaxOpenConnections = 0 + + BlockExecutorSequential = "sequential" + BlockExecutorBlockSTM = "block-stm" ) -var evmTracers = []string{"json", "markdown", "struct", "access_list"} +var ( + evmTracers = []string{"json", "markdown", "struct", "access_list"} + + blockExecutors = []string{BlockExecutorSequential, BlockExecutorBlockSTM} +) // Config defines the server's top level configuration. It includes the default app config // from the SDK as well as the EVM configuration to enable the JSON-RPC APIs. @@ -96,6 +103,12 @@ type EVMConfig struct { Tracer string `mapstructure:"tracer"` // MaxTxGasWanted defines the gas wanted for each eth tx returned in ante handler in check tx mode. MaxTxGasWanted uint64 `mapstructure:"max-tx-gas-wanted"` + // BlockExecutor set block executor type, "block-stm" for parallel execution, "sequential" for sequential execution. + BlockExecutor string `mapstructure:"block-executor"` + // BlockSTMWorkers is the number of workers for block-stm execution, `0` means using all available CPUs. + BlockSTMWorkers int `mapstructure:"block-stm-workers"` + // BlockSTMPreEstimate is the flag to enable pre-estimation for block-stm execution. + BlockSTMPreEstimate bool `mapstructure:"block-stm-pre-estimate"` } // JSONRPCConfig defines configuration for the EVM RPC server. @@ -198,6 +211,7 @@ func DefaultEVMConfig() *EVMConfig { return &EVMConfig{ Tracer: DefaultEVMTracer, MaxTxGasWanted: DefaultMaxTxGasWanted, + BlockExecutor: BlockExecutorSequential, } } @@ -207,6 +221,10 @@ func (c EVMConfig) Validate() error { return fmt.Errorf("invalid tracer type %s, available types: %v", c.Tracer, evmTracers) } + if c.BlockExecutor != "" && !strings.StringInSlice(c.BlockExecutor, blockExecutors) { + return fmt.Errorf("invalid block executor type %s, available types: %v", c.BlockExecutor, blockExecutors) + } + return nil } @@ -330,8 +348,11 @@ func GetConfig(v *viper.Viper) (Config, error) { return Config{ Config: cfg, EVM: EVMConfig{ - Tracer: v.GetString("evm.tracer"), - MaxTxGasWanted: v.GetUint64("evm.max-tx-gas-wanted"), + Tracer: v.GetString("evm.tracer"), + MaxTxGasWanted: v.GetUint64("evm.max-tx-gas-wanted"), + BlockExecutor: v.GetString("evm.block-executor"), + BlockSTMWorkers: v.GetInt("evm.block-stm-workers"), + BlockSTMPreEstimate: v.GetBool("evm.block-stm-pre-estimate"), }, JSONRPC: JSONRPCConfig{ Enable: v.GetBool("json-rpc.enable"), diff --git a/server/config/toml.go b/server/config/toml.go index a61f110dc7..a9c60e5094 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -31,6 +31,13 @@ tracer = "{{ .EVM.Tracer }}" # MaxTxGasWanted defines the gas wanted for each eth tx returned in ante handler in check tx mode. max-tx-gas-wanted = {{ .EVM.MaxTxGasWanted }} +# BlockExecutor set block executor type, "block-stm" for parallel execution, "sequential" for sequential execution. +block-executor = "{{ .EVM.BlockExecutor }}" +# BlockSTMWorkers is the number of workers for block-stm execution, 0 means using all available CPUs. +block-stm-workers = {{ .EVM.BlockSTMWorkers }} +# BlockSTMPreEstimate is the flag to enable pre-estimation for block-stm execution. +block-stm-pre-estimate = {{ .EVM.BlockSTMPreEstimate }} + ############################################################################### ### JSON RPC Configuration ### ############################################################################### diff --git a/server/flags/flags.go b/server/flags/flags.go index 015f5f02da..d61329a753 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -75,6 +75,10 @@ const ( const ( EVMTracer = "evm.tracer" EVMMaxTxGasWanted = "evm.max-tx-gas-wanted" + + EVMBlockExecutor = "evm.block-executor" + EVMBlockSTMWorkers = "evm.block-stm-workers" + EVMBlockSTMPreEstimate = "evm.block-stm-pre-estimate" ) // TLS flags diff --git a/tests/importer/importer_test.go b/tests/importer/importer_test.go index 285300b265..3bb8263bb1 100644 --- a/tests/importer/importer_test.go +++ b/tests/importer/importer_test.go @@ -148,10 +148,9 @@ func (suite *ImporterTestSuite) TestImportBlocks() { applyDAOHardFork(vmdb) } - for _, tx := range block.Transactions() { - + for i, tx := range block.Transactions() { receipt, gas, err := applyTransaction( - ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig, + ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig, uint(i), ) suite.Require().NoError(err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt) suite.Require().NotNil(receipt) @@ -230,7 +229,7 @@ func applyDAOHardFork(vmdb ethvm.StateDB) { func applyTransaction( ctx sdk.Context, config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address, gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb *statedb.StateDB, header *ethtypes.Header, - tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, + tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, index uint, ) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number), sdkmath.ZeroInt().BigInt()) if err != nil { @@ -263,7 +262,7 @@ func applyTransaction( // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { - receipt.ContractAddress = crypto.CreateAddress(vmenv.TxContext.Origin, tx.Nonce()) + receipt.ContractAddress = crypto.CreateAddress(vmenv.Origin, tx.Nonce()) } // Set the receipt logs and create a bloom for filtering @@ -271,7 +270,7 @@ func applyTransaction( receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt}) receipt.BlockHash = header.Hash() receipt.BlockNumber = header.Number - receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient(ctx)) + receipt.TransactionIndex = index return receipt, execResult.UsedGas, err } diff --git a/tests/integration_tests/configs/default.jsonnet b/tests/integration_tests/configs/default.jsonnet index 32d116c86a..6ae48d796c 100644 --- a/tests/integration_tests/configs/default.jsonnet +++ b/tests/integration_tests/configs/default.jsonnet @@ -6,6 +6,9 @@ 'app-config': { 'minimum-gas-prices': '0aphoton', 'index-events': ['ethereum_tx.ethereumTxHash'], + evm: { + 'block-executor': 'block-stm', + }, 'json-rpc': { address: '127.0.0.1:{EVMRPC_PORT}', 'ws-address': '127.0.0.1:{EVMRPC_PORT_WS}', diff --git a/testutil/config/encoding.go b/testutil/config/encoding.go new file mode 100644 index 0000000000..de21b95183 --- /dev/null +++ b/testutil/config/encoding.go @@ -0,0 +1,35 @@ +package config + +import ( + "cosmossdk.io/simapp/params" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/evmos/ethermint/encoding" + "github.com/evmos/ethermint/x/evm" + "github.com/evmos/ethermint/x/feemarket" +) + +func MakeConfigForTest(moduleManager module.BasicManager) params.EncodingConfig { + config := encoding.MakeTestEncodingConfig() + if moduleManager == nil { + moduleManager = module.NewBasicManager( + auth.AppModuleBasic{}, + bank.AppModuleBasic{}, + distr.AppModuleBasic{}, + gov.NewAppModuleBasic([]govclient.ProposalHandler{paramsclient.ProposalHandler}), + staking.AppModuleBasic{}, + // Ethermint modules + evm.AppModuleBasic{}, + feemarket.AppModuleBasic{}, + ) + } + moduleManager.RegisterLegacyAminoCodec(config.Amino) + moduleManager.RegisterInterfaces(config.InterfaceRegistry) + return config +} diff --git a/types/block.go b/types/block.go index 5d0db44b9e..6c5558cbd3 100644 --- a/types/block.go +++ b/types/block.go @@ -21,13 +21,6 @@ import sdk "github.com/cosmos/cosmos-sdk/types" // set, it returns the max gas from the application consensus params. // NOTE: see https://github.com/cosmos/cosmos-sdk/issues/9514 for full reference func BlockGasLimit(ctx sdk.Context) uint64 { - blockGasMeter := ctx.BlockGasMeter() - - // Get the limit from the gas meter only if its not null and not an InfiniteGasMeter - if blockGasMeter != nil && blockGasMeter.Limit() != 0 { - return blockGasMeter.Limit() - } - // Otherwise get from the consensus parameters cp := ctx.ConsensusParams() if cp.Block == nil { diff --git a/types/int.go b/types/int.go index 4098d4105d..908a253134 100644 --- a/types/int.go +++ b/types/int.go @@ -36,6 +36,13 @@ func SafeInt64(value uint64) (int64, error) { return int64(value), nil //#nosec G115 } +func SafeIntToUint64(value int) (uint64, error) { + if value < 0 { + return 0, fmt.Errorf("invalid value: %d", value) + } + return uint64(value), nil +} + // SafeNewIntFromBigInt constructs Int from big.Int, return error if more than 256bits func SafeNewIntFromBigInt(i *big.Int) (sdkmath.Int, error) { if !IsValidInt256(i) { diff --git a/x/evm/client/cli/tx.go b/x/evm/client/cli/tx.go index 8f33d36c1e..eb34fc5d4d 100644 --- a/x/evm/client/cli/tx.go +++ b/x/evm/client/cli/tx.go @@ -28,6 +28,7 @@ import ( "github.com/spf13/cobra" rpctypes "github.com/evmos/ethermint/rpc/types" + ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm/types" ) @@ -51,22 +52,27 @@ func NewRawTxCmd() *cobra.Command { Short: "Build cosmos transaction from raw ethereum transaction", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + data, err := hexutil.Decode(args[0]) if err != nil { return errors.Wrap(err, "failed to decode ethereum tx hex bytes") } - msg := &types.MsgEthereumTx{} - if err := msg.UnmarshalBinary(data); err != nil { + eip155ChainID, err := ethermint.ParseChainID(clientCtx.ChainID) + if err != nil { return err } - if err := msg.ValidateBasic(); err != nil { + msg := &types.MsgEthereumTx{} + if err := msg.UnmarshalBinary(data, eip155ChainID); err != nil { return err } - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index a21dbe4137..5e0067d620 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -179,7 +179,7 @@ func (suite *EvmTestSuite) SetupTest() { } func (suite *EvmTestSuite) SignTx(tx *types.MsgEthereumTx) { - tx.From = suite.from.String() + tx.From = suite.from.Bytes() err := tx.Sign(suite.ethSigner, suite.signer) suite.Require().NoError(err) } @@ -575,7 +575,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() { k.SetHooks(tc.hooks) // add some fund to pay gas fee - k.SetBalance(suite.ctx, suite.from, big.NewInt(1000000000000000)) + k.SetBalance(suite.ctx, suite.from, big.NewInt(1000000000000000), types.DefaultEVMDenom) contract := suite.deployERC20Contract() @@ -598,7 +598,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() { ) suite.SignTx(tx) - before := k.GetBalance(suite.ctx, suite.from) + before := k.GetEVMDenomBalance(suite.ctx, suite.from) evmParams := suite.app.EvmKeeper.GetParams(suite.ctx) ethCfg := evmParams.GetChainConfig().EthereumConfig(nil) @@ -608,7 +608,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() { suite.Require().NoError(err) fees, err := keeper.VerifyFee(txData, "aphoton", baseFee, true, true, suite.ctx.IsCheckTx()) suite.Require().NoError(err) - err = k.DeductTxCostsFromUserBalance(suite.ctx, fees, common.HexToAddress(tx.From)) + err = k.DeductTxCostsFromUserBalance(suite.ctx, fees, tx.GetSender()) suite.Require().NoError(err) res, err := k.EthereumTx(suite.ctx, tx) @@ -618,7 +618,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() { suite.Require().Equal(tc.expErr, res.VmError) suite.Require().Empty(res.Logs) - after := k.GetBalance(suite.ctx, suite.from) + after := k.GetEVMDenomBalance(suite.ctx, suite.from) if tc.expErr == "out of gas" { suite.Require().Equal(tc.gasLimit, res.GasUsed) diff --git a/x/evm/keeper/abci.go b/x/evm/keeper/abci.go index cb00b761a8..f9f10d5bcd 100644 --- a/x/evm/keeper/abci.go +++ b/x/evm/keeper/abci.go @@ -18,16 +18,17 @@ package keeper import ( "context" - storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - - ethtypes "github.com/ethereum/go-ethereum/core/types" ) // BeginBlock sets the sdk Context and EIP155 chain id to the Keeper. func (k *Keeper) BeginBlock(ctx context.Context) error { sdkCtx := sdk.UnwrapSDKContext(ctx) k.WithChainID(sdkCtx) + + // cache params object + _ = k.GetParams(sdkCtx) + return nil } @@ -37,11 +38,6 @@ func (k *Keeper) BeginBlock(ctx context.Context) error { func (k *Keeper) EndBlock(ctx context.Context) error { sdkCtx := sdk.UnwrapSDKContext(ctx) - // Gas costs are handled within msg handler so costs should be ignored - infCtx := sdkCtx.WithGasMeter(storetypes.NewInfiniteGasMeter()) - - bloom := ethtypes.BytesToBloom(k.GetBlockBloomTransient(infCtx).Bytes()) - k.EmitBlockBloomEvent(infCtx, bloom) - + k.CollectTxBloom(sdkCtx) return nil } diff --git a/x/evm/keeper/benchmark_test.go b/x/evm/keeper/benchmark_test.go index 8866c8c589..8836e8dd4e 100644 --- a/x/evm/keeper/benchmark_test.go +++ b/x/evm/keeper/benchmark_test.go @@ -54,7 +54,7 @@ func DoBenchmark(b *testing.B, txBuilder TxBuilder) { suite, contractAddr := SetupContract(b) msg := txBuilder(suite, contractAddr) - msg.From = suite.address.Hex() + msg.From = suite.address.Bytes() err := msg.Sign(ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()), suite.signer) require.NoError(b, err) @@ -121,7 +121,7 @@ func BenchmarkMessageCall(b *testing.B) { nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address) msg := types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 25000000, big.NewInt(1), nil, nil, input, nil) - msg.From = suite.address.Hex() + msg.From = suite.address.Bytes() err = msg.Sign(ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()), suite.signer) require.NoError(b, err) diff --git a/x/evm/keeper/bloom.go b/x/evm/keeper/bloom.go new file mode 100644 index 0000000000..193e20a1b9 --- /dev/null +++ b/x/evm/keeper/bloom.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "math/big" + + "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/evmos/ethermint/x/evm/types" +) + +func (k Keeper) SetTxBloom(ctx sdk.Context, bloom *big.Int) { + store := ctx.ObjectStore(k.objectKey) + store.Set(types.ObjectBloomKey(ctx.TxIndex(), ctx.MsgIndex()), bloom) +} + +func (k Keeper) CollectTxBloom(ctx sdk.Context) { + store := prefix.NewObjStore(ctx.ObjectStore(k.objectKey), types.KeyPrefixObjectBloom) + it := store.Iterator(nil, nil) + defer it.Close() + + bloom := new(big.Int) + for ; it.Valid(); it.Next() { + bloom.Or(bloom, it.Value().(*big.Int)) + } + + k.EmitBlockBloomEvent(ctx, bloom.Bytes()) +} diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 584463a56e..a7a558105c 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -52,8 +52,7 @@ func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig return statedb.NewTxConfig( common.BytesToHash(ctx.HeaderHash()), // BlockHash txHash, // TxHash - uint(k.GetTxIndexTransient(ctx)), // TxIndex - uint(k.GetLogSizeTransient(ctx)), // LogIndex + 0, 0, ) } diff --git a/x/evm/keeper/gas.go b/x/evm/keeper/gas.go index e6518cc83b..7bbb3a9fda 100644 --- a/x/evm/keeper/gas.go +++ b/x/evm/keeper/gas.go @@ -56,8 +56,7 @@ func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64 refundedCoins := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(remaining))} // refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees - - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins) + err := k.bankKeeper.SendCoinsFromModuleToAccountVirtual(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins) if err != nil { err = errorsmod.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) return errorsmod.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 41d7a8c2f2..6eca7aa026 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -66,9 +66,10 @@ func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ ctx := sdk.UnwrapSDKContext(c) acct := k.GetAccountOrEmpty(ctx, addr) + balance := k.GetEVMDenomBalance(ctx, addr) return &types.QueryAccountResponse{ - Balance: acct.Balance.String(), + Balance: balance.String(), CodeHash: common.BytesToHash(acct.CodeHash).Hex(), Nonce: acct.Nonce, }, nil @@ -157,7 +158,7 @@ func (k Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*typ ctx := sdk.UnwrapSDKContext(c) - balanceInt := k.GetBalance(ctx, common.HexToAddress(req.Address)) + balanceInt := k.GetEVMDenomBalance(ctx, common.HexToAddress(req.Address)) return &types.QueryBalanceResponse{ Balance: balanceInt.String(), diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index c36559733b..1f78d5c08f 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -364,7 +364,7 @@ func (suite *KeeperTestSuite) TestQueryTxLogs() { func(vmdb vm.StateDB) { expLogs = []*types.Log{ { - Address: suite.address.String(), + Address: types.HexAddress(suite.address.Bytes()), Topics: []string{common.BytesToHash([]byte("topic")).String()}, Data: []byte("data"), BlockNumber: 1, diff --git a/x/evm/keeper/integration_test.go b/x/evm/keeper/integration_test.go index 2bf2ccba20..48728a709c 100644 --- a/x/evm/keeper/integration_test.go +++ b/x/evm/keeper/integration_test.go @@ -243,7 +243,7 @@ func buildEthTx( data, accesses, ) - msgEthereumTx.From = from.String() + msgEthereumTx.From = from.Bytes() return msgEthereumTx } @@ -260,8 +260,6 @@ func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereu err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv)) s.Require().NoError(err) - // A valid msg should have empty `From` - msgEthereumTx.From = "" err = txBuilder.SetMsgs(msgEthereumTx) s.Require().NoError(err) @@ -283,7 +281,7 @@ func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereu func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) *abci.ResponseCheckTx { bz := prepareEthTx(priv, msgEthereumTx) req := abci.RequestCheckTx{Tx: bz} - res, _ := s.app.CheckTx(&req) + res, _ := s.app.CheckTxSync(&req) return res } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 9e684f6531..e4d1111113 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -22,7 +22,6 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" sdkmath "cosmossdk.io/math" - "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -50,8 +49,8 @@ type Keeper struct { // - storing Bloom filters by block height. Needed for the Web3 API. storeService store.KVStoreService - // key to access the transient store, which is reset on every block during Commit - transientKey storetypes.StoreKey + // key to access the object store, which is reset on every block during Commit + objectKey storetypes.StoreKey // the address capable of executing a MsgUpdateParams message. Typically, this should be the x/gov module account. authority sdk.AccAddress @@ -86,7 +85,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, storeService store.KVStoreService, - transientKey storetypes.StoreKey, + objectKey storetypes.StoreKey, authority sdk.AccAddress, ak types.AccountKeeper, bankKeeper types.BankKeeper, @@ -116,7 +115,7 @@ func NewKeeper( stakingKeeper: sk, feeMarketKeeper: fmk, storeService: storeService, - transientKey: transientKey, + objectKey: objectKey, customPrecompiles: customPrecompiles, evmConstructor: evmConstructor, tracer: tracer, @@ -154,11 +153,11 @@ func (k Keeper) ChainID() *big.Int { // ---------------------------------------------------------------------------- // EmitBlockBloomEvent emit block bloom events -func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom ethtypes.Bloom) { +func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom []byte) { ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeBlockBloom, - sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom.Bytes())), + sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom)), ), ) } @@ -168,69 +167,6 @@ func (k Keeper) GetAuthority() sdk.AccAddress { return k.authority } -// GetBlockBloomTransient returns bloom bytes for the current block height -func (k Keeper) GetBlockBloomTransient(ctx sdk.Context) *big.Int { - store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom) - heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) //#nosec G115 - bz := store.Get(heightBz) - if len(bz) == 0 { - return big.NewInt(0) - } - - return new(big.Int).SetBytes(bz) -} - -// SetBlockBloomTransient sets the given bloom bytes to the transient store. This value is reset on -// every block. -func (k Keeper) SetBlockBloomTransient(ctx sdk.Context, bloom *big.Int) { - store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom) - heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) //#nosec G115 - store.Set(heightBz, bloom.Bytes()) -} - -// ---------------------------------------------------------------------------- -// Tx -// ---------------------------------------------------------------------------- - -// SetTxIndexTransient set the index of processing transaction -func (k Keeper) SetTxIndexTransient(ctx sdk.Context, index uint64) { - store := ctx.TransientStore(k.transientKey) - store.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(index)) -} - -// GetTxIndexTransient returns EVM transaction index on the current block. -func (k Keeper) GetTxIndexTransient(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientTxIndex) - if len(bz) == 0 { - return 0 - } - - return sdk.BigEndianToUint64(bz) -} - -// ---------------------------------------------------------------------------- -// Log -// ---------------------------------------------------------------------------- - -// GetLogSizeTransient returns EVM log index on the current block. -func (k Keeper) GetLogSizeTransient(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientLogSize) - if len(bz) == 0 { - return 0 - } - - return sdk.BigEndianToUint64(bz) -} - -// SetLogSizeTransient fetches the current EVM log index from the transient store, increases its -// value by one and then sets the new index back to the transient store. -func (k Keeper) SetLogSizeTransient(ctx sdk.Context, logSize uint64) { - store := ctx.TransientStore(k.transientKey) - store.Set(types.KeyPrefixTransientLogSize, sdk.Uint64ToBigEndian(logSize)) -} - // ---------------------------------------------------------------------------- // Storage // ---------------------------------------------------------------------------- @@ -305,7 +241,6 @@ func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb // empty account return statedb.Account{ - Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } } @@ -321,8 +256,8 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 { return acct.GetSequence() } -// GetBalance load account's balance of gas token -func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int { +// GetEVMDenomBalance returns the balance of evm denom +func (k *Keeper) GetEVMDenomBalance(ctx sdk.Context, addr common.Address) *big.Int { cosmosAddr := sdk.AccAddress(addr.Bytes()) evmParams := k.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() @@ -330,8 +265,12 @@ func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int { if evmDenom == "" { return big.NewInt(-1) } - coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, evmDenom) - return coin.Amount.BigInt() + return k.GetBalance(ctx, cosmosAddr, evmDenom) +} + +// GetBalance load account's balance of gas token +func (k *Keeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) *big.Int { + return k.bankKeeper.GetBalance(ctx, addr, denom).Amount.BigInt() } // GetBaseFee returns current base fee, return values: @@ -364,27 +303,20 @@ func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdkmath.LegacyDec { return fmkParmas.MinGasMultiplier } -// ResetTransientGasUsed reset gas used to prepare for execution of current cosmos tx, called in ante handler. -func (k Keeper) ResetTransientGasUsed(ctx sdk.Context) { - store := ctx.TransientStore(k.transientKey) - store.Delete(types.KeyPrefixTransientGasUsed) -} - // GetTransientGasUsed returns the gas used by current cosmos tx. func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientGasUsed) - if len(bz) == 0 { + store := ctx.ObjectStore(k.objectKey) + v := store.Get(types.ObjectGasUsedKey(ctx.TxIndex())) + if v == nil { return 0 } - return sdk.BigEndianToUint64(bz) + return v.(uint64) } // SetTransientGasUsed sets the gas used by current cosmos tx. func (k Keeper) SetTransientGasUsed(ctx sdk.Context, gasUsed uint64) { - store := ctx.TransientStore(k.transientKey) - bz := sdk.Uint64ToBigEndian(gasUsed) - store.Set(types.KeyPrefixTransientGasUsed, bz) + store := ctx.ObjectStore(k.objectKey) + store.Set(types.ObjectGasUsedKey(ctx.TxIndex()), gasUsed) } // AddTransientGasUsed accumulate gas used by each eth msgs included in current cosmos tx. diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index f61bf68a5c..dd1c0f1366 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -32,7 +32,6 @@ import ( "github.com/evmos/ethermint/crypto/ethsecp256k1" "github.com/evmos/ethermint/server/config" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/testutil" ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" @@ -306,7 +305,7 @@ func (suite *KeeperTestSuite) DeployTestContract(t require.TestingT, owner commo ) } - erc20DeployTx.From = suite.address.Hex() + erc20DeployTx.From = suite.address.Bytes() err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) require.NoError(t, err) rsp, err := suite.app.EvmKeeper.EthereumTx(suite.ctx, erc20DeployTx) @@ -359,7 +358,7 @@ func (suite *KeeperTestSuite) TransferERC20Token(t require.TestingT, contractAdd ) } - ercTransferTx.From = suite.address.Hex() + ercTransferTx.From = suite.address.Bytes() err = ercTransferTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) require.NoError(t, err) rsp, err := suite.app.EvmKeeper.EthereumTx(suite.ctx, ercTransferTx) @@ -414,7 +413,7 @@ func (suite *KeeperTestSuite) DeployTestMessageCall(t require.TestingT) common.A ) } - erc20DeployTx.From = suite.address.Hex() + erc20DeployTx.From = suite.address.Bytes() err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) require.NoError(t, err) rsp, err := suite.app.EvmKeeper.EthereumTx(suite.ctx, erc20DeployTx) @@ -498,7 +497,6 @@ func (suite *KeeperTestSuite) TestGetAccountStorage() { func (suite *KeeperTestSuite) TestGetAccountOrEmpty() { empty := statedb.Account{ - Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } @@ -533,58 +531,3 @@ func (suite *KeeperTestSuite) TestGetAccountOrEmpty() { }) } } - -func (suite *KeeperTestSuite) TestRevertByPrecompileSnapshot() { - db := suite.StateDB() - - // snapshot id for journal - rev := db.Snapshot() - - ctx, err := db.GetCacheContext() - suite.NoError(err) - - snapshotMultiStore, err := db.MultiStoreSnapshot() - suite.NoError(err) - snapshotEvents := suite.ctx.EventManager().Events() - db.AddPrecompileSnapshot(snapshotMultiStore, snapshotEvents) - - // manipulate statedb(evm) - evmAddr, priv := tests.NewAddrKey() - key1 := common.BigToHash(big.NewInt(1)) - value1 := common.BigToHash(big.NewInt(2)) - key2 := common.BigToHash(big.NewInt(3)) - value2 := common.BigToHash(big.NewInt(4)) - db.SetState(evmAddr, key1, value1) - db.SetState(evmAddr, key2, value2) - - suite.Equal(value1, db.GetState(evmAddr, key1)) - suite.Equal(value2, db.GetState(evmAddr, key2)) - - // manipulate bank keeper(sdk) - addr1 := sdk.AccAddress(priv.PubKey().Address().Bytes()) - denom := "testdenom" - testutil.FundAccount(suite.app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewCoin(denom, sdkmath.NewInt(1000000)))) - addr2 := sdk.AccAddress(tests.GenerateAddress().Bytes()) - suite.app.BankKeeper.SendCoins(ctx, addr1, addr2, sdk.NewCoins(sdk.NewCoin(denom, sdkmath.NewInt(1000)))) - - suite.Equal(sdk.NewCoin(denom, sdkmath.NewInt(999000)), suite.app.BankKeeper.GetBalance(ctx, addr1, denom)) - suite.Equal(sdk.NewCoin(denom, sdkmath.NewInt(1000)), suite.app.BankKeeper.GetBalance(ctx, addr2, denom)) - - // revert to snapshot - db.RevertToSnapshot(rev) - - suite.Equal(common.Hash{}, db.GetState(evmAddr, key1)) - suite.Equal(common.Hash{}, db.GetState(evmAddr, key2)) - - suite.Equal(sdk.NewCoin(denom, sdkmath.NewInt(999000)), suite.app.BankKeeper.GetBalance(ctx, addr1, denom)) - suite.Equal(sdk.NewCoin(denom, sdkmath.NewInt(1000)), suite.app.BankKeeper.GetBalance(ctx, addr2, denom)) - - // commit changes(revert sdk state) - db.Commit() - - suite.Equal(common.Hash{}, db.GetState(evmAddr, key1)) - suite.Equal(common.Hash{}, db.GetState(evmAddr, key2)) - - suite.Equal(sdk.NewCoin(denom, sdkmath.ZeroInt()), suite.app.BankKeeper.GetBalance(suite.ctx, addr1, denom)) - suite.Equal(sdk.NewCoin(denom, sdkmath.ZeroInt()), suite.app.BankKeeper.GetBalance(suite.ctx, addr2, denom)) -} diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 3d9fd8867e..66eb4896e2 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -44,9 +44,7 @@ var _ types.MsgServer = &Keeper{} func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - sender := msg.From tx := msg.AsTransaction() - txIndex := k.GetTxIndexTransient(ctx) labels := []metrics.Label{ telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())), @@ -94,8 +92,6 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()), // add event for ethereum transaction hash format sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash), - // add event for index of valid ethereum tx - sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(txIndex, 10)), // add event for eth tx gas used, we can't get it from cosmos tx result when it contains multiple eth tx msgs. sdk.NewAttribute(types.AttributeKeyTxGasUsed, strconv.FormatUint(response.GasUsed, 10)), } @@ -107,7 +103,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t } if to := tx.To(); to != nil { - attrs = append(attrs, sdk.NewAttribute(types.AttributeKeyRecipient, to.Hex())) + attrs = append(attrs, sdk.NewAttribute(types.AttributeKeyRecipient, types.HexAddress(to.Bytes()))) } if response.Failed() { @@ -136,8 +132,8 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, sender), - sdk.NewAttribute(types.AttributeKeyTxType, fmt.Sprintf("%d", tx.Type())), + sdk.NewAttribute(sdk.AttributeKeySender, types.HexAddress(msg.From)), + sdk.NewAttribute(types.AttributeKeyTxType, strconv.Itoa(int(tx.Type()))), ), }) diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index b17f437ee0..0f5b3763d1 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -21,14 +21,16 @@ import ( ) // GetParams returns the total set of evm parameters. -func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { +func (k Keeper) GetParams(ctx sdk.Context) types.Params { store := k.storeService.OpenKVStore(ctx) bz, _ := store.Get(types.KeyPrefixParams) if len(bz) == 0 { return k.GetLegacyParams(ctx) } + + var params types.Params k.cdc.MustUnmarshal(bz, ¶ms) - return + return params } // SetParams sets the EVM params each in their individual key for better get performance diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index c54aedf4d4..ba2d4f3c20 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -57,7 +57,7 @@ func (k *Keeper) NewEVM( ) evm.EVM { blockCtx := vm.BlockContext{ CanTransfer: core.CanTransfer, - Transfer: core.Transfer, + Transfer: statedb.Transfer, GetHash: k.GetHashFn(ctx), Coinbase: cfg.CoinBase, GasLimit: ethermint.BlockGasLimit(ctx), @@ -166,11 +166,6 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { // // For relevant discussion see: https://github.com/cosmos/cosmos-sdk/discussions/9072 func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) { - var ( - bloom *big.Int - bloomReceipt ethtypes.Bloom - ) - cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID) if err != nil { return nil, errorsmod.Wrap(err, "failed to load evm config") @@ -178,9 +173,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) ethTx := msgEth.AsTransaction() txConfig := k.TxConfig(ctx, ethTx.Hash()) - // get the signer according to the chain rules from the config and block height - signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) - msg, err := msgEth.AsMessage(signer, cfg.BaseFee) + msg, err := msgEth.AsMessage(cfg.BaseFee) if err != nil { return nil, errorsmod.Wrap(err, "failed to return ethereum transaction as core message") } @@ -206,18 +199,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) // Compute block bloom filter if len(logs) > 0 { - bloom = k.GetBlockBloomTransient(ctx) - bloom.Or(bloom, big.NewInt(0).SetBytes(ethtypes.LogsBloom(logs))) - bloomReceipt = ethtypes.BytesToBloom(bloom.Bytes()) - } - - cumulativeGasUsed := res.GasUsed - if ctx.BlockGasMeter() != nil { - limit := ctx.BlockGasMeter().Limit() - cumulativeGasUsed += ctx.BlockGasMeter().GasConsumed() - if cumulativeGasUsed > limit { - cumulativeGasUsed = limit - } + k.SetTxBloom(tmpCtx, new(big.Int).SetBytes(ethtypes.LogsBloom(logs))) } var contractAddr common.Address @@ -226,17 +208,14 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) } receipt := ðtypes.Receipt{ - Type: ethTx.Type(), - PostState: nil, // TODO: intermediate state root - CumulativeGasUsed: cumulativeGasUsed, - Bloom: bloomReceipt, - Logs: logs, - TxHash: txConfig.TxHash, - ContractAddress: contractAddr, - GasUsed: res.GasUsed, - BlockHash: txConfig.BlockHash, - BlockNumber: big.NewInt(ctx.BlockHeight()), - TransactionIndex: txConfig.TxIndex, + Type: ethTx.Type(), + PostState: nil, // TODO: intermediate state root + Logs: logs, + TxHash: txConfig.TxHash, + ContractAddress: contractAddr, + GasUsed: res.GasUsed, + BlockHash: txConfig.BlockHash, + BlockNumber: big.NewInt(ctx.BlockHeight()), } if !res.Failed() { @@ -263,14 +242,6 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) return nil, errorsmod.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From()) } - if len(receipt.Logs) > 0 { - // Update transient block bloom filter - k.SetBlockBloomTransient(ctx, receipt.Bloom.Big()) - k.SetLogSizeTransient(ctx, uint64(txConfig.LogIndex)+uint64(len(receipt.Logs))) - } - - k.SetTxIndexTransient(ctx, uint64(txConfig.TxIndex)+1) - totalGasUsed, err := k.AddTransientGasUsed(ctx, res.GasUsed) if err != nil { return nil, errorsmod.Wrap(err, "failed to add transient gas used") diff --git a/x/evm/keeper/state_transition_benchmark_test.go b/x/evm/keeper/state_transition_benchmark_test.go index 66f7a132ab..93449a9df5 100644 --- a/x/evm/keeper/state_transition_benchmark_test.go +++ b/x/evm/keeper/state_transition_benchmark_test.go @@ -74,7 +74,7 @@ func newSignedEthTx( } var msg evmtypes.MsgEthereumTx - if err := msg.FromEthereumTx(ethTx); err != nil { + if err := msg.FromSignedEthereumTx(ethTx, ethSigner.ChainID()); err != nil { return nil, err } return &msg, nil @@ -129,7 +129,7 @@ func newEthMsgTx( msg := &evmtypes.MsgEthereumTx{} msg.FromEthereumTx(ethTx) - msg.From = address.Hex() + msg.From = address.Bytes() return msg, baseFee, msg.Sign(ethSigner, krSigner) } @@ -145,14 +145,12 @@ func newNativeMessage( data []byte, accessList ethtypes.AccessList, ) (core.Message, error) { - msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(blockHeight)) - msg, baseFee, err := newEthMsgTx(nonce, blockHeight, address, cfg, krSigner, ethSigner, txType, data, accessList) if err != nil { return nil, err } - m, err := msg.AsMessage(msgSigner, baseFee) + m, err := msg.AsMessage(baseFee) if err != nil { return nil, err } diff --git a/x/evm/keeper/state_transition_test.go b/x/evm/keeper/state_transition_test.go index 62f6544e6d..ee58b624c3 100644 --- a/x/evm/keeper/state_transition_test.go +++ b/x/evm/keeper/state_transition_test.go @@ -669,8 +669,7 @@ func (suite *KeeperTestSuite) createContractGethMsg(nonce uint64, signer ethtype return nil, err } - msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(suite.ctx.BlockHeight())) - return ethMsg.AsMessage(msgSigner, nil) + return ethMsg.AsMessage(nil) } func (suite *KeeperTestSuite) createContractMsgTx(nonce uint64, signer ethtypes.Signer, cfg *params.ChainConfig, gasPrice *big.Int) (*types.MsgEthereumTx, error) { @@ -684,7 +683,7 @@ func (suite *KeeperTestSuite) createContractMsgTx(nonce uint64, signer ethtypes. ethTx := ethtypes.NewTx(contractCreateTx) ethMsg := &types.MsgEthereumTx{} ethMsg.FromEthereumTx(ethTx) - ethMsg.From = suite.address.Hex() + ethMsg.From = suite.address.Bytes() return ethMsg, ethMsg.Sign(signer, suite.signer) } diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index b882078461..e3d054e978 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -16,7 +16,6 @@ package keeper import ( - "fmt" "math/big" errorsmod "cosmossdk.io/errors" @@ -44,7 +43,6 @@ func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Accou return nil } - acct.Balance = k.GetBalance(ctx, addr) return acct } @@ -87,33 +85,38 @@ func (k *Keeper) ForEachStorage(ctx sdk.Context, addr common.Address, cb func(ke } } +func (k *Keeper) Transfer(ctx sdk.Context, sender, recipient sdk.AccAddress, coins sdk.Coins) error { + return k.bankKeeper.SendCoins(ctx, sender, recipient, coins) +} + +func (k *Keeper) AddBalance(ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) error { + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { + return err + } + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, coins) +} + +func (k *Keeper) SubBalance(ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) error { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, coins); err != nil { + return err + } + return k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins) +} + // SetBalance update account's balance, compare with current balance first, then decide to mint or burn. -func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.Int) error { +func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.Int, evmDenom string) error { cosmosAddr := sdk.AccAddress(addr.Bytes()) - - params := k.GetParams(ctx) - coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, params.EvmDenom) - balance := coin.Amount.BigInt() + balance := k.GetBalance(ctx, cosmosAddr, evmDenom) delta := new(big.Int).Sub(amount, balance) switch delta.Sign() { case 1: // mint - coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(delta))) - if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { - return err - } - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, cosmosAddr, coins); err != nil { - return err - } + coins := sdk.NewCoins(sdk.NewCoin(evmDenom, sdkmath.NewIntFromBigInt(delta))) + return k.AddBalance(ctx, cosmosAddr, coins) case -1: // burn - coins := sdk.NewCoins(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(new(big.Int).Neg(delta)))) - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, cosmosAddr, types.ModuleName, coins); err != nil { - return err - } - if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil { - return err - } + coins := sdk.NewCoins(sdk.NewCoin(evmDenom, sdkmath.NewIntFromBigInt(new(big.Int).Neg(delta)))) + return k.SubBalance(ctx, cosmosAddr, coins) default: // not changed } @@ -143,16 +146,11 @@ func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account stated k.accountKeeper.SetAccount(ctx, acct) - if err := k.SetBalance(ctx, addr, account.Balance); err != nil { - return err - } - k.Logger(ctx).Debug( "account updated", - "ethereum-address", addr.Hex(), + "ethereum-address", addr, "nonce", account.Nonce, - "codeHash", codeHash.Hex(), - "balance", account.Balance, + "codeHash", codeHash, ) return nil } @@ -168,10 +166,10 @@ func (k *Keeper) SetState(ctx sdk.Context, addr common.Address, key common.Hash, } else { prefixStore.Set(key.Bytes(), value) } - k.Logger(ctx).Debug( - fmt.Sprintf("state %s", action), - "ethereum-address", addr.Hex(), - "key", key.Hex(), + k.Logger(ctx).Debug("state", + "action", action, + "ethereum-address", addr, + "key", key, ) } @@ -188,9 +186,9 @@ func (k *Keeper) SetCode(ctx sdk.Context, codeHash, code []byte) { } else { prefixStore.Set(codeHash, code) } - k.Logger(ctx).Debug( - fmt.Sprintf("code %s", action), - "code-hash", common.BytesToHash(codeHash).Hex(), + k.Logger(ctx).Debug("code", + "action", action, + "code-hash", codeHash, ) } @@ -212,11 +210,6 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error { return errorsmod.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr) } - // clear balance - if err := k.SetBalance(ctx, addr, new(big.Int)); err != nil { - return err - } - // clear storage k.ForEachStorage(ctx, addr, func(key, _ common.Hash) bool { k.SetState(ctx, addr, key, nil) @@ -226,10 +219,9 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error { // remove auth account k.accountKeeper.RemoveAccount(ctx, acct) - k.Logger(ctx).Debug( - "account suicided", - "ethereum-address", addr.Hex(), - "cosmos-address", cosmosAddr.String(), + k.Logger(ctx).Debug("account suicided", + "ethereum-address", addr, + "cosmos-address", cosmosAddr, ) return nil diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 21534f17c1..1a92e99ea1 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -64,23 +64,27 @@ func (suite *KeeperTestSuite) TestCreateAccount() { func (suite *KeeperTestSuite) TestAddBalance() { testCases := []struct { - name string - amount *big.Int - isNoOp bool + name string + amount *big.Int + isPanic bool + isNoOp bool }{ { "positive amount", big.NewInt(100), false, + false, }, { "zero amount", big.NewInt(0), + false, true, }, { "negative amount", big.NewInt(-1), + true, false, // seems to be consistent with go-ethereum's implementation }, } @@ -89,13 +93,16 @@ func (suite *KeeperTestSuite) TestAddBalance() { suite.Run(tc.name, func() { vmdb := suite.StateDB() prev := vmdb.GetBalance(suite.address) - vmdb.AddBalance(suite.address, tc.amount) - post := vmdb.GetBalance(suite.address) - - if tc.isNoOp { - suite.Require().Equal(prev.Int64(), post.Int64()) + if tc.isPanic { + suite.Require().Panics(func() { vmdb.AddBalance(suite.address, tc.amount) }) } else { - suite.Require().Equal(new(big.Int).Add(prev, tc.amount).Int64(), post.Int64()) + vmdb.AddBalance(suite.address, tc.amount) + post := vmdb.GetBalance(suite.address) + if tc.isNoOp { + suite.Require().Equal(prev.Int64(), post.Int64()) + } else { + suite.Require().Equal(new(big.Int).Add(prev, tc.amount).Int64(), post.Int64()) + } } }) } @@ -106,6 +113,7 @@ func (suite *KeeperTestSuite) TestSubBalance() { name string amount *big.Int malleate func(vm.StateDB) + isPanic bool isNoOp bool }{ { @@ -113,6 +121,7 @@ func (suite *KeeperTestSuite) TestSubBalance() { big.NewInt(100), func(vm.StateDB) {}, false, + true, }, { "positive amount, above zero", @@ -121,17 +130,20 @@ func (suite *KeeperTestSuite) TestSubBalance() { vmdb.AddBalance(suite.address, big.NewInt(100)) }, false, + false, }, { "zero amount", big.NewInt(0), func(vm.StateDB) {}, + false, true, }, { "negative amount", big.NewInt(-1), func(vm.StateDB) {}, + true, false, }, } @@ -142,13 +154,16 @@ func (suite *KeeperTestSuite) TestSubBalance() { tc.malleate(vmdb) prev := vmdb.GetBalance(suite.address) - vmdb.SubBalance(suite.address, tc.amount) - post := vmdb.GetBalance(suite.address) - - if tc.isNoOp { - suite.Require().Equal(prev.Int64(), post.Int64()) + if tc.isPanic { + suite.Require().Panics(func() { vmdb.SubBalance(suite.address, tc.amount) }) } else { - suite.Require().Equal(new(big.Int).Sub(prev, tc.amount).Int64(), post.Int64()) + vmdb.SubBalance(suite.address, tc.amount) + post := vmdb.GetBalance(suite.address) + if tc.isNoOp { + suite.Require().Equal(prev.Int64(), post.Int64()) + } else { + suite.Require().Equal(new(big.Int).Sub(prev, tc.amount).Int64(), post.Int64()) + } } }) } @@ -636,27 +651,27 @@ func (suite *KeeperTestSuite) CreateTestTx(msg *types.MsgEthereumTx, priv crypto func (suite *KeeperTestSuite) TestAddLog() { addr, privKey := tests.NewAddrKey() msg := types.NewTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, big.NewInt(1), nil, nil, []byte("test"), nil) - msg.From = addr.Hex() + msg.From = addr.Bytes() tx := suite.CreateTestTx(msg, privKey) msg, _ = tx.GetMsgs()[0].(*types.MsgEthereumTx) txHash := msg.AsTransaction().Hash() msg2 := types.NewTx(big.NewInt(1), 1, &suite.address, big.NewInt(1), 100000, big.NewInt(1), nil, nil, []byte("test"), nil) - msg2.From = addr.Hex() + msg2.From = addr.Bytes() tx2 := suite.CreateTestTx(msg2, privKey) msg2, _ = tx2.GetMsgs()[0].(*types.MsgEthereumTx) msg3 := types.NewTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, nil, big.NewInt(1), big.NewInt(1), []byte("test"), nil) - msg3.From = addr.Hex() + msg3.From = addr.Bytes() tx3 := suite.CreateTestTx(msg3, privKey) msg3, _ = tx3.GetMsgs()[0].(*types.MsgEthereumTx) txHash3 := msg3.AsTransaction().Hash() msg4 := types.NewTx(big.NewInt(1), 1, &suite.address, big.NewInt(1), 100000, nil, big.NewInt(1), big.NewInt(1), []byte("test"), nil) - msg4.From = addr.Hex() + msg4.From = addr.Bytes() tx4 := suite.CreateTestTx(msg4, privKey) msg4, _ = tx4.GetMsgs()[0].(*types.MsgEthereumTx) @@ -899,11 +914,11 @@ func (suite *KeeperTestSuite) TestSetBalance() { suite.Run(tc.name, func() { suite.SetupTest() tc.malleate() - err := suite.app.EvmKeeper.SetBalance(suite.ctx, tc.addr, amount) + err := suite.app.EvmKeeper.SetBalance(suite.ctx, tc.addr, amount, types.DefaultEVMDenom) if tc.expErr { suite.Require().Error(err) } else { - balance := suite.app.EvmKeeper.GetBalance(suite.ctx, tc.addr) + balance := suite.app.EvmKeeper.GetEVMDenomBalance(suite.ctx, tc.addr) suite.Require().NoError(err) suite.Require().Equal(amount, balance) } @@ -945,7 +960,7 @@ func (suite *KeeperTestSuite) TestDeleteAccount() { suite.Require().Error(err) } else { suite.Require().NoError(err) - balance := suite.app.EvmKeeper.GetBalance(suite.ctx, tc.addr) + balance := suite.app.EvmKeeper.GetEVMDenomBalance(suite.ctx, tc.addr) suite.Require().Equal(new(big.Int), balance) } }) diff --git a/x/evm/keeper/utils.go b/x/evm/keeper/utils.go index e44ba62f21..e71c851fe0 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -27,6 +27,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/evmos/ethermint/x/evm/types" ) @@ -73,7 +74,7 @@ func (k *Keeper) DeductTxCostsFromUserBalance( } // deduct the full gas cost from the user balance - if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil { + if err := DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil { return errorsmod.Wrapf(err, "failed to deduct full gas cost %s from the user %s balance", fees, from) } @@ -154,3 +155,16 @@ func CheckSenderBalance( } return nil } + +// DeductFees deducts fees from the given account. +func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc sdk.AccountI, fees sdk.Coins) error { + if !fees.IsValid() { + return errorsmod.Wrapf(errortypes.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + if ctx.BlockHeight() > 0 { + if err := bankKeeper.SendCoinsFromAccountToModuleVirtual(ctx, acc.GetAddress(), authtypes.FeeCollectorName, fees); err != nil { + return errorsmod.Wrap(errortypes.ErrInsufficientFunds, err.Error()) + } + } + return nil +} diff --git a/x/evm/keeper/utils_test.go b/x/evm/keeper/utils_test.go index c59463ed70..8e455a97f8 100644 --- a/x/evm/keeper/utils_test.go +++ b/x/evm/keeper/utils_test.go @@ -233,13 +233,13 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() { } tx := evmtypes.NewTx(zeroInt.BigInt(), 1, &to, amount, tc.gasLimit, gasPrice, gasFeeCap, gasTipCap, nil, tc.accessList) - tx.From = tc.from + tx.From = common.HexToAddress(tc.from).Bytes() txData, _ := evmtypes.UnpackTxData(tx.Data) - acct := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, suite.address) + balance := suite.app.EvmKeeper.GetEVMDenomBalance(suite.ctx, suite.address) err := keeper.CheckSenderBalance( - sdkmath.NewIntFromBigInt(acct.Balance), + sdkmath.NewIntFromBigInt(balance), txData, ) @@ -471,7 +471,7 @@ func (suite *KeeperTestSuite) TestVerifyFeeAndDeductTxCostsFromUserBalance() { suite.Require().NoError(err, "Unexpected error while committing to vmdb: %d", err) tx := evmtypes.NewTx(zeroInt.BigInt(), 1, &suite.address, amount, tc.gasLimit, gasPrice, gasFeeCap, gasTipCap, nil, tc.accessList) - tx.From = tc.from + tx.From = common.HexToAddress(tc.from).Bytes() txData, _ := evmtypes.UnpackTxData(tx.Data) @@ -507,7 +507,7 @@ func (suite *KeeperTestSuite) TestVerifyFeeAndDeductTxCostsFromUserBalance() { suite.Require().Nil(fees, "invalid test %d passed. fees value must be nil - '%s'", i, tc.name) } - err = suite.app.EvmKeeper.DeductTxCostsFromUserBalance(suite.ctx, fees, common.HexToAddress(tx.From)) + err = suite.app.EvmKeeper.DeductTxCostsFromUserBalance(suite.ctx, fees, common.BytesToAddress(tx.From)) if tc.expectPassDeduct { suite.Require().NoError(err, "valid test %d failed - '%s'", i, tc.name) } else { diff --git a/x/evm/migrations/v4/migrate_test.go b/x/evm/migrations/v4/migrate_test.go index 5c56925123..4e17e574df 100644 --- a/x/evm/migrations/v4/migrate_test.go +++ b/x/evm/migrations/v4/migrate_test.go @@ -33,7 +33,7 @@ func TestMigrate(t *testing.T) { cdc := encCfg.Codec storeKey := storetypes.NewKVStoreKey(types.ModuleName) - tKey := storetypes.NewTransientStoreKey(types.TransientKey) + tKey := storetypes.NewTransientStoreKey("transient_test") ctx := testutil.DefaultContext(storeKey, tKey) storeService := runtime.NewKVStoreService(storeKey) diff --git a/x/evm/statedb/interfaces.go b/x/evm/statedb/interfaces.go index e4e83e09c3..d49989052f 100644 --- a/x/evm/statedb/interfaces.go +++ b/x/evm/statedb/interfaces.go @@ -16,9 +16,12 @@ package statedb import ( + "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) // ExtStateDB defines an extension to the interface provided by the go-ethereum @@ -33,6 +36,14 @@ type ExtStateDB interface { // Keeper provide underlying storage of StateDB type Keeper interface { + GetParams(sdk.Context) evmtypes.Params + + Transfer(ctx sdk.Context, sender, recipient sdk.AccAddress, coins sdk.Coins) error + AddBalance(ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) error + SubBalance(ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) error + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) *big.Int + SetBalance(ctx sdk.Context, addr common.Address, amount *big.Int, denom string) error + // Read methods GetAccount(ctx sdk.Context, addr common.Address) *Account GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash diff --git a/x/evm/statedb/journal.go b/x/evm/statedb/journal.go index a67143585d..3ed2e753c5 100644 --- a/x/evm/statedb/journal.go +++ b/x/evm/statedb/journal.go @@ -18,12 +18,9 @@ package statedb import ( "bytes" - "math/big" "sort" - storetypes "cosmossdk.io/store/types" - - sdk "github.com/cosmos/cosmos-sdk/types" + "cosmossdk.io/store/cachemulti" "github.com/ethereum/go-ethereum/common" ) @@ -106,16 +103,10 @@ type ( prev *stateObject } suicideChange struct { - account *common.Address - prev bool // whether account had already suicided - prevbalance *big.Int - } - - // Changes to individual accounts. - balanceChange struct { account *common.Address - prev *big.Int + prev bool // whether account had already suicided } + nonceChange struct { account *common.Address prev uint64 @@ -144,9 +135,9 @@ type ( slot *common.Hash } - precompileChange struct { - ms storetypes.MultiStore - es sdk.Events + nativeChange struct { + snapshot cachemulti.Store + events int // native events index } ) @@ -170,7 +161,6 @@ func (ch suicideChange) Revert(s *StateDB) { obj := s.getStateObject(*ch.account) if obj != nil { obj.suicided = ch.prev - obj.setBalance(ch.prevbalance) } } @@ -178,14 +168,6 @@ func (ch suicideChange) Dirtied() *common.Address { return ch.account } -func (ch balanceChange) Revert(s *StateDB) { - s.getStateObject(*ch.account).setBalance(ch.prev) -} - -func (ch balanceChange) Dirtied() *common.Address { - return ch.account -} - func (ch nonceChange) Revert(s *StateDB) { s.getStateObject(*ch.account).setNonce(ch.prev) } @@ -251,16 +233,11 @@ func (ch accessListAddSlotChange) Dirtied() *common.Address { return nil } -func (ch precompileChange) Revert(s *StateDB) { - s.cacheCtx = s.cacheCtx.WithMultiStore(ch.ms) - - // Necessary to revert the sdk state - s.writeCache = func() { - s.cacheCtx.EventManager().EmitEvents(ch.es) - ch.ms.CacheMultiStore().Write() - } +func (ch nativeChange) Revert(s *StateDB) { + s.cacheMS.Restore(ch.snapshot) + s.nativeEvents = s.nativeEvents[:len(s.nativeEvents)-ch.events] } -func (ch precompileChange) Dirtied() *common.Address { +func (ch nativeChange) Dirtied() *common.Address { return nil } diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go deleted file mode 100644 index 544cbfa1b4..0000000000 --- a/x/evm/statedb/mock_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package statedb_test - -import ( - "bytes" - "errors" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/evmos/ethermint/x/evm/statedb" -) - -var ( - _ statedb.Keeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) -) - -type MockAcount struct { - account statedb.Account - states statedb.Storage -} - -type MockKeeper struct { - accounts map[common.Address]MockAcount - codes map[common.Hash][]byte -} - -func NewMockKeeper() *MockKeeper { - return &MockKeeper{ - accounts: make(map[common.Address]MockAcount), - codes: make(map[common.Hash][]byte), - } -} - -func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { - acct, ok := k.accounts[addr] - if !ok { - return nil - } - return &acct.account -} - -func (k MockKeeper) GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash { - return k.accounts[addr].states[key] -} - -func (k MockKeeper) GetCode(ctx sdk.Context, codeHash common.Hash) []byte { - return k.codes[codeHash] -} - -func (k MockKeeper) ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) { - if acct, ok := k.accounts[addr]; ok { - for k, v := range acct.states { - if !cb(k, v) { - return - } - } - } -} - -func (k MockKeeper) SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error { - if addr == errAddress { - return errors.New("mock db error") - } - acct, exists := k.accounts[addr] - if exists { - // update - acct.account = account - k.accounts[addr] = acct - } else { - k.accounts[addr] = MockAcount{account: account, states: make(statedb.Storage)} - } - return nil -} - -func (k MockKeeper) SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) { - if acct, ok := k.accounts[addr]; ok { - if len(value) == 0 { - delete(acct.states, key) - } else { - acct.states[key] = common.BytesToHash(value) - } - } -} - -func (k MockKeeper) SetCode(ctx sdk.Context, codeHash []byte, code []byte) { - k.codes[common.BytesToHash(codeHash)] = code -} - -func (k MockKeeper) DeleteAccount(ctx sdk.Context, addr common.Address) error { - if addr == errAddress { - return errors.New("mock db error") - } - old := k.accounts[addr] - delete(k.accounts, addr) - if !bytes.Equal(old.account.CodeHash, emptyCodeHash) { - delete(k.codes, common.BytesToHash(old.account.CodeHash)) - } - return nil -} - -func (k MockKeeper) Clone() *MockKeeper { - accounts := make(map[common.Address]MockAcount, len(k.accounts)) - for k, v := range k.accounts { - accounts[k] = v - } - codes := make(map[common.Hash][]byte, len(k.codes)) - for k, v := range k.codes { - codes[k] = v - } - return &MockKeeper{accounts, codes} -} diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index dd344dfadb..46cdb8f206 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -17,7 +17,6 @@ package statedb import ( "bytes" - "math/big" "sort" "github.com/ethereum/go-ethereum/common" @@ -30,14 +29,12 @@ var emptyCodeHash = crypto.Keccak256(nil) // These objects are stored in the storage of auth module. type Account struct { Nonce uint64 - Balance *big.Int CodeHash []byte } // NewEmptyAccount returns an empty account. func NewEmptyAccount() *Account { return &Account{ - Balance: new(big.Int), CodeHash: emptyCodeHash, } } @@ -84,9 +81,6 @@ type stateObject struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, account Account) *stateObject { - if account.Balance == nil { - account.Balance = new(big.Int) - } if account.CodeHash == nil { account.CodeHash = emptyCodeHash } @@ -101,44 +95,13 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec // empty returns whether the account is considered empty. func (s *stateObject) empty() bool { - return s.account.Nonce == 0 && s.account.Balance.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) + return s.account.Nonce == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) } func (s *stateObject) markSuicided() { s.suicided = true } -// AddBalance adds amount to s's balance. -// It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *big.Int) { - if amount.Sign() == 0 { - return - } - s.SetBalance(new(big.Int).Add(s.Balance(), amount)) -} - -// SubBalance removes amount from s's balance. -// It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *big.Int) { - if amount.Sign() == 0 { - return - } - s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) -} - -// SetBalance update account balance. -func (s *stateObject) SetBalance(amount *big.Int) { - s.db.journal.append(balanceChange{ - account: &s.address, - prev: new(big.Int).Set(s.account.Balance), - }) - s.setBalance(amount) -} - -func (s *stateObject) setBalance(amount *big.Int) { - s.account.Balance = amount -} - // // Attribute accessors // @@ -156,7 +119,7 @@ func (s *stateObject) Code() []byte { if bytes.Equal(s.CodeHash(), emptyCodeHash) { return nil } - code := s.db.keeper.GetCode(s.db.ctx, common.BytesToHash(s.CodeHash())) + code := s.db.keeper.GetCode(s.db.cacheCtx, common.BytesToHash(s.CodeHash())) s.code = code return code } @@ -202,11 +165,6 @@ func (s *stateObject) CodeHash() []byte { return s.account.CodeHash } -// Balance returns the balance of account -func (s *stateObject) Balance() *big.Int { - return s.account.Balance -} - // Nonce returns the nonce of account func (s *stateObject) Nonce() uint64 { return s.account.Nonce @@ -218,7 +176,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { return value } // If no live objects are available, load it from keeper - value := s.db.keeper.GetState(s.db.ctx, s.Address(), key) + value := s.db.keeper.GetState(s.db.cacheCtx, s.Address(), key) s.originStorage[key] = value return value } diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index b91ebb4108..7278a1a154 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -16,13 +16,13 @@ package statedb import ( - "errors" "fmt" "math/big" "sort" errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" + sdkmath "cosmossdk.io/math" + "cosmossdk.io/store/cachemulti" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,6 +32,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +const StateDBContextKey = "statedb" + type EventConverter = func(sdk.Event) (*ethtypes.Log, error) // revision is the identifier of a version of state. @@ -42,6 +44,10 @@ type revision struct { journalIndex int } +func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + db.(*StateDB).Transfer(sender, recipient, amount) +} + var _ vm.StateDB = &StateDB{} // StateDB structs within the ethereum protocol are used to store anything @@ -54,6 +60,7 @@ type StateDB struct { ctx sdk.Context cacheCtx sdk.Context + cacheMS cachemulti.Store writeCache func() // Journal of state modifications. This is the backbone of @@ -74,11 +81,18 @@ type StateDB struct { // Per-transaction access list accessList *accessList + + // events emitted by native action + nativeEvents sdk.Events + + // handle balances natively + evmDenom string + err error } // New creates a new state from a given trie. func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { - return &StateDB{ + db := &StateDB{ keeper: keeper, ctx: ctx, stateObjects: make(map[common.Address]*stateObject), @@ -87,6 +101,26 @@ func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { txConfig: txConfig, } + + if parentCacheMS, ok := ctx.MultiStore().(cachemulti.Store); ok { + db.cacheMS = parentCacheMS.Clone() + db.writeCache = func() { parentCacheMS.Restore(db.cacheMS) } + } else { + // in unit test, it could be run with a uncached multistore + if db.cacheMS, ok = ctx.MultiStore().CacheWrap().(cachemulti.Store); !ok { + panic("expect the CacheWrap result to be cachemulti.Store") + } + db.writeCache = db.cacheMS.Write + } + db.cacheCtx = ctx.WithValue(StateDBContextKey, db).WithMultiStore(db.cacheMS) + + db.evmDenom = keeper.GetParams(ctx).EvmDenom + + return db +} + +func (s *StateDB) NativeEvents() sdk.Events { + return s.nativeEvents } // Keeper returns the underlying `Keeper` @@ -136,16 +170,15 @@ func (s *StateDB) Exist(addr common.Address) bool { // or empty according to the EIP161 specification (balance = nonce = code = 0) func (s *StateDB) Empty(addr common.Address) bool { so := s.getStateObject(addr) - return so == nil || so.empty() + if so == nil { + return true + } + return so.empty() && s.GetBalance(addr).Sign() == 0 } // GetBalance retrieves the balance from the given address or 0 if object not found func (s *StateDB) GetBalance(addr common.Address) *big.Int { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.Balance() - } - return common.Big0 + return s.keeper.GetBalance(s.cacheCtx, sdk.AccAddress(addr.Bytes()), s.evmDenom) } // GetNonce returns the nonce of account, 0 if not exists. @@ -231,7 +264,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return obj } // If no live objects are available, load it from keeper - account := s.keeper.GetAccount(s.ctx, addr) + account := s.keeper.GetAccount(s.cacheCtx, addr) if account == nil { return nil } @@ -279,10 +312,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) // // Carrying over the balance ensures that Ether doesn't disappear. func (s *StateDB) CreateAccount(addr common.Address) { - newObj, prev := s.createObject(addr) - if prev != nil { - newObj.setBalance(prev.account.Balance) - } + s.createObject(addr) } // ForEachStorage iterate the contract storage, the iteration order is not defined. @@ -307,29 +337,23 @@ func (s *StateDB) setStateObject(object *stateObject) { s.stateObjects[object.Address()] = object } -func (s *StateDB) GetCacheContext() (sdk.Context, error) { - if s.writeCache == nil { - if s.ctx.MultiStore() == nil { - return s.ctx, errors.New("ctx has no multi store") - } - s.cacheCtx, s.writeCache = s.ctx.CacheContext() - } +func (s *StateDB) GetCacheContext() sdk.Context { + return s.cacheCtx +} - return s.cacheCtx, nil +func (s *StateDB) MultiStoreSnapshot() cachemulti.Store { + return s.cacheMS.Clone() } -func (s *StateDB) MultiStoreSnapshot() (storetypes.CacheMultiStore, error) { - ctx, err := s.GetCacheContext() - if err != nil { // means s.ctx.MultiStore() == nil - return nil, err +func (s *StateDB) emitNativeEvents(contract common.Address, events sdk.Events, converter EventConverter) { + if converter == nil { + return } - cms := ctx.MultiStore().(storetypes.CacheMultiStore) - snapshot := cms.Copy() - return snapshot, nil -} + if len(events) == 0 { + return + } -func (s *StateDB) ProcessPrecompileEvents(contract common.Address, events sdk.Events, converter EventConverter) { // convert native events to evm logs for _, event := range events { log, err := converter(event) @@ -346,28 +370,86 @@ func (s *StateDB) ProcessPrecompileEvents(contract common.Address, events sdk.Ev } } -// If revert is occurred, the snapshot of journal is overwritten. -func (s *StateDB) AddPrecompileSnapshot(snapshot storetypes.MultiStore, events sdk.Events) { - s.journal.append(precompileChange{snapshot, events}) +// ExecuteNativeAction executes native action in isolate, +// the writes will be revert when either the native action itself fail +// or the wrapping message call reverted. +func (s *StateDB) ExecuteNativeAction(contract common.Address, converter EventConverter, action func(ctx sdk.Context) error) error { + snapshot := s.MultiStoreSnapshot() + eventManager := sdk.NewEventManager() + + if err := action(s.cacheCtx.WithEventManager(eventManager)); err != nil { + s.cacheMS.Restore(snapshot) + return err + } + + events := eventManager.Events() + s.emitNativeEvents(contract, events, converter) + s.nativeEvents = s.nativeEvents.AppendEvents(events) + s.journal.append(nativeChange{snapshot: snapshot, events: len(events)}) + return nil } /* * SETTERS */ +// Transfer from one account to another +func (s *StateDB) Transfer(sender, recipient common.Address, amount *big.Int) { + if amount.Sign() == 0 { + return + } + if amount.Sign() < 0 { + panic("negative amount") + } + + coins := sdk.NewCoins(sdk.NewCoin(s.evmDenom, sdkmath.NewIntFromBigIntMut(amount))) + senderAddr := sdk.AccAddress(sender.Bytes()) + recipientAddr := sdk.AccAddress(recipient.Bytes()) + if err := s.ExecuteNativeAction(common.Address{}, nil, func(ctx sdk.Context) error { + return s.keeper.Transfer(ctx, senderAddr, recipientAddr, coins) + }); err != nil { + s.err = err + } +} + // AddBalance adds amount to the account associated with addr. func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.AddBalance(amount) + if amount.Sign() == 0 { + return + } + if amount.Sign() < 0 { + panic("negative amount") + } + coins := sdk.Coins{sdk.NewCoin(s.evmDenom, sdkmath.NewIntFromBigInt(amount))} + if err := s.ExecuteNativeAction(common.Address{}, nil, func(ctx sdk.Context) error { + return s.keeper.AddBalance(ctx, sdk.AccAddress(addr.Bytes()), coins) + }); err != nil { + s.err = err } } // SubBalance subtracts amount from the account associated with addr. func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SubBalance(amount) + if amount.Sign() == 0 { + return + } + if amount.Sign() < 0 { + panic("negative amount") + } + coins := sdk.Coins{sdk.NewCoin(s.evmDenom, sdkmath.NewIntFromBigInt(amount))} + if err := s.ExecuteNativeAction(common.Address{}, nil, func(ctx sdk.Context) error { + return s.keeper.SubBalance(ctx, sdk.AccAddress(addr.Bytes()), coins) + }); err != nil { + s.err = err + } +} + +// SetBalance is called by state override +func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) { + if err := s.ExecuteNativeAction(common.Address{}, nil, func(ctx sdk.Context) error { + return s.keeper.SetBalance(ctx, addr, amount, s.evmDenom) + }); err != nil { + s.err = err } } @@ -406,12 +488,16 @@ func (s *StateDB) Suicide(addr common.Address) bool { return false } s.journal.append(suicideChange{ - account: &addr, - prev: stateObject.suicided, - prevbalance: new(big.Int).Set(stateObject.Balance()), + account: &addr, + prev: stateObject.suicided, }) stateObject.markSuicided() - stateObject.account.Balance = new(big.Int) + + // clear balance + balance := s.GetBalance(addr) + if balance.Sign() > 0 { + s.SubBalance(addr, balance) + } return true } @@ -504,9 +590,15 @@ func (s *StateDB) RevertToSnapshot(revid int) { // Commit writes the dirty states to keeper // the StateDB object should be discarded after committed. func (s *StateDB) Commit() error { - // write all store updates from precompile - if s.writeCache != nil { - s.writeCache() + // if there's any errors during the execution, abort + // TODO(dudong2): Consider to move this codes under writeCache + if s.err != nil { + return s.err + } + + s.writeCache() + if len(s.nativeEvents) > 0 { + s.ctx.EventManager().EmitEvents(s.nativeEvents) } for _, addr := range s.journal.sortedDirties() { diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 3a491aa8cc..7e9d142003 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -1,22 +1,50 @@ package statedb_test import ( + "errors" "math/big" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + dbm "github.com/cosmos/cosmos-db" + + "cosmossdk.io/log" + "cosmossdk.io/store/metrics" + "cosmossdk.io/store/rootmulti" + storetypes "cosmossdk.io/store/types" + + sdkaddress "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + + "github.com/evmos/ethermint/testutil/config" + ethermint "github.com/evmos/ethermint/types" + evmkeeper "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" - "github.com/stretchr/testify/suite" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) var ( + emptyCodeHash = crypto.Keccak256(nil) address common.Address = common.BigToAddress(big.NewInt(101)) address2 common.Address = common.BigToAddress(big.NewInt(102)) - address3 common.Address = common.BigToAddress(big.NewInt(103)) blockHash common.Hash = common.BigToHash(big.NewInt(9999)) emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig(blockHash) ) @@ -30,11 +58,13 @@ func (suite *StateDBTestSuite) TestAccount() { value1 := common.BigToHash(big.NewInt(2)) key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) + txConfig := emptyTxConfig + txConfig.TxHash = common.BigToHash(big.NewInt(100)) testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(*statedb.StateDB, storetypes.MultiStore) }{ - {"non-exist account", func(db *statedb.StateDB) { + {"non-exist account", func(db *statedb.StateDB, cms storetypes.MultiStore) { suite.Require().Equal(false, db.Exist(address)) suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) @@ -42,17 +72,16 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.Hash{}, db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"empty account", func(db *statedb.StateDB) { + {"empty account", func(db *statedb.StateDB, cms storetypes.MultiStore) { db.CreateAccount(address) suite.Require().NoError(db.Commit()) - keeper := db.Keeper().(*MockKeeper) - acct := keeper.accounts[address] - suite.Require().Equal(statedb.NewEmptyAccount(), &acct.account) - suite.Require().Empty(acct.states) - suite.Require().False(acct.account.IsContract()) + ctx, keeper := newTestKeeper(suite.T(), cms) + acct := keeper.GetAccount(ctx, address) + suite.Require().Equal(statedb.NewEmptyAccount(), acct) + suite.Require().False(acct.IsContract()) - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = statedb.New(ctx, keeper, txConfig) suite.Require().Equal(true, db.Exist(address)) suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) @@ -60,7 +89,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"suicide", func(db *statedb.StateDB) { + {"suicide", func(db *statedb.StateDB, cms storetypes.MultiStore) { // non-exist account. suite.Require().False(db.Suicide(address)) suite.Require().False(db.HasSuicided(address)) @@ -71,10 +100,15 @@ func (suite *StateDBTestSuite) TestAccount() { db.AddBalance(address, big.NewInt(100)) db.SetState(address, key1, value1) db.SetState(address, key2, value2) + codeHash := db.GetCodeHash(address) suite.Require().NoError(db.Commit()) + ctx, keeper := newTestKeeper(suite.T(), cms) + + suite.Require().NotEmpty(keeper.GetCode(ctx, codeHash)) + // suicide - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(ctx, keeper, txConfig) suite.Require().False(db.HasSuicided(address)) suite.Require().True(db.Suicide(address)) @@ -88,28 +122,30 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) + ctx, keeper = newTestKeeper(suite.T(), cms) + // not accessible from StateDB anymore - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(ctx, keeper, txConfig) suite.Require().False(db.Exist(address)) // and cleared in keeper too - keeper := db.Keeper().(*MockKeeper) - suite.Require().Empty(keeper.accounts) - suite.Require().Empty(keeper.codes) + suite.Require().Nil(keeper.GetAccount(ctx, address)) + // code is not deleted when contract suicided. + suite.Require().NotEmpty(keeper.GetCode(ctx, codeHash)) }}, } for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) - tc.malleate(db) + raw, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, txConfig) + tc.malleate(db, raw) }) } } func (suite *StateDBTestSuite) TestAccountOverride() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) // test balance carry over when overwritten amount := big.NewInt(1) @@ -131,16 +167,13 @@ func (suite *StateDBTestSuite) TestDBError() { name string malleate func(vm.StateDB) }{ - {"set account", func(db vm.StateDB) { - db.SetNonce(errAddress, 1) - }}, - {"delete account", func(db vm.StateDB) { - db.SetNonce(errAddress, 1) - suite.Require().True(db.Suicide(errAddress)) + {"negative balance", func(db vm.StateDB) { + db.SubBalance(address, big.NewInt(10)) }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) tc.malleate(db) suite.Require().Error(db.Commit()) } @@ -168,19 +201,26 @@ func (suite *StateDBTestSuite) TestBalance() { {"sub zero balance", func(db *statedb.StateDB) { db.SubBalance(address, big.NewInt(0)) }, big.NewInt(0)}, + {"transfer", func(db *statedb.StateDB) { + db.AddBalance(address, big.NewInt(10)) + db.Transfer(address, address2, big.NewInt(10)) + suite.Require().Equal(big.NewInt(10), db.GetBalance(address2)) + }, big.NewInt(0)}, } for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + raw, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) tc.malleate(db) // check dirty state suite.Require().Equal(tc.expBalance, db.GetBalance(address)) suite.Require().NoError(db.Commit()) + + ctx, keeper = newTestKeeper(suite.T(), raw) // check committed balance too - suite.Require().Equal(tc.expBalance, keeper.accounts[address].account.Balance) + suite.Require().Equal(tc.expBalance, keeper.GetEVMDenomBalance(ctx, address)) }) } } @@ -224,16 +264,19 @@ func (suite *StateDBTestSuite) TestState() { for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + raw, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) tc.malleate(db) suite.Require().NoError(db.Commit()) // check committed states in keeper - suite.Require().Equal(tc.expStates, keeper.accounts[address].states) + ctx, keeper = newTestKeeper(suite.T(), raw) + for k, v := range tc.expStates { + suite.Require().Equal(v, keeper.GetState(ctx, address, k)) + } // check ForEachStorage - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = statedb.New(ctx, keeper, emptyTxConfig) collected := CollectContractStorage(db) if len(tc.expStates) > 0 { suite.Require().Equal(tc.expStates, collected) @@ -265,8 +308,8 @@ func (suite *StateDBTestSuite) TestCode() { for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + raw, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) tc.malleate(db) // check dirty state @@ -276,8 +319,9 @@ func (suite *StateDBTestSuite) TestCode() { suite.Require().NoError(db.Commit()) - // check again - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + // check the committed state + ctx, keeper = newTestKeeper(suite.T(), raw) + db = statedb.New(ctx, keeper, emptyTxConfig) suite.Require().Equal(tc.expCode, db.GetCode(address)) suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) @@ -330,8 +374,8 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { } for _, tc := range testCases { suite.Run(tc.name, func() { - ctx := sdk.Context{} - keeper := NewMockKeeper() + raw, ctx, keeper := setupTestEnv(suite.T()) + ctx = ctx.WithEventManager(sdk.NewEventManager()) { // do some arbitrary changes to the storage @@ -344,7 +388,8 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { suite.Require().NoError(db.Commit()) } - originalKeeper := keeper.Clone() + originalState := cloneRawState(suite.T(), raw) + ctx, keeper = newTestKeeper(suite.T(), raw) // run test db := statedb.New(ctx, keeper, emptyTxConfig) @@ -358,8 +403,9 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { suite.Require().NoError(db.Commit()) - // check keeper should stay the same - suite.Require().Equal(originalKeeper, keeper) + newState := cloneRawState(suite.T(), raw) + // check the committed state stays the same + suite.Require().Equal(originalState, newState) }) } } @@ -369,7 +415,8 @@ func (suite *StateDBTestSuite) TestNestedSnapshot() { value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) rev1 := db.Snapshot() db.SetState(address, key, value1) @@ -386,7 +433,8 @@ func (suite *StateDBTestSuite) TestNestedSnapshot() { } func (suite *StateDBTestSuite) TestInvalidSnapshotId() { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) suite.Require().Panics(func() { db.RevertToSnapshot(1) }) @@ -434,31 +482,11 @@ func (suite *StateDBTestSuite) TestAccessList() { suite.Require().True(addrPresent) suite.Require().True(slotPresent) }}, - {"prepare access list", func(db vm.StateDB) { - al := ethtypes.AccessList{{ - Address: address3, - StorageKeys: []common.Hash{value1}, - }} - db.PrepareAccessList(address, &address2, vm.PrecompiledAddressesBerlin, al) - - // check sender and dst - suite.Require().True(db.AddressInAccessList(address)) - suite.Require().True(db.AddressInAccessList(address2)) - // check precompiles - suite.Require().True(db.AddressInAccessList(common.BytesToAddress([]byte{1}))) - // check AccessList - suite.Require().True(db.AddressInAccessList(address3)) - addrPresent, slotPresent := db.SlotInAccessList(address3, value1) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) - addrPresent, slotPresent = db.SlotInAccessList(address3, value2) - suite.Require().True(addrPresent) - suite.Require().False(slotPresent) - }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) tc.malleate(db) } } @@ -471,7 +499,8 @@ func (suite *StateDBTestSuite) TestLog() { txHash, 1, 1, ) - db := statedb.New(sdk.Context{}, NewMockKeeper(), txConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, txConfig) data := []byte("hello world") db.AddLog(ðtypes.Log{ Address: address, @@ -523,7 +552,8 @@ func (suite *StateDBTestSuite) TestRefund() { }, 0, true}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + _, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) if !tc.expPanic { tc.malleate(db) suite.Require().Equal(tc.expRefund, db.GetRefund()) @@ -541,8 +571,8 @@ func (suite *StateDBTestSuite) TestIterateStorage() { key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + raw, ctx, keeper := setupTestEnv(suite.T()) + db := statedb.New(ctx, keeper, emptyTxConfig) db.SetState(address, key1, value1) db.SetState(address, key2, value2) @@ -553,7 +583,11 @@ func (suite *StateDBTestSuite) TestIterateStorage() { storage := CollectContractStorage(db) suite.Require().Equal(2, len(storage)) - suite.Require().Equal(keeper.accounts[address].states, storage) + + ctx, keeper = newTestKeeper(suite.T(), raw) + for k, v := range storage { + suite.Require().Equal(v, keeper.GetState(ctx, address, k)) + } // break early iteration storage = make(statedb.Storage) @@ -565,6 +599,157 @@ func (suite *StateDBTestSuite) TestIterateStorage() { suite.Require().Equal(1, len(storage)) } +func (suite *StateDBTestSuite) TestNativeAction() { + _, ctx, keeper := setupTestEnv(suite.T()) + storeKey := testStoreKeys["testnative"] + objStoreKey := testObjKeys[evmtypes.ObjectStoreKey] + memKey := testMemKeys[capabilitytypes.MemStoreKey] + + eventConverter := func(event sdk.Event) (*ethtypes.Log, error) { + converters := map[string]statedb.EventConverter{ + "success1": func(event sdk.Event) (*ethtypes.Log, error) { + return ðtypes.Log{Data: []byte("success1")}, nil + }, + "success2": func(event sdk.Event) (*ethtypes.Log, error) { + return ðtypes.Log{Data: []byte("success2")}, nil + }, + } + converter, ok := converters[event.Type] + if !ok { + return nil, nil + } + return converter(event) + } + + stateDB := statedb.New(ctx, keeper, emptyTxConfig) + contract := common.BigToAddress(big.NewInt(101)) + + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + store.Set([]byte("success1"), []byte("value")) + ctx.EventManager().EmitEvent(sdk.NewEvent("success1")) + + objStore := ctx.ObjectStore(objStoreKey) + objStore.Set([]byte("transient"), "value") + + mem := ctx.KVStore(memKey) + mem.Set([]byte("mem"), []byte("value")) + + return nil + }) + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + store.Set([]byte("failure1"), []byte("value")) + ctx.EventManager().EmitEvent(sdk.NewEvent("failure1")) + + objStore := ctx.ObjectStore(objStoreKey) + suite.Require().Equal("value", objStore.Get([]byte("transient")).(string)) + + mem := ctx.KVStore(memKey) + suite.Require().Equal([]byte("value"), mem.Get([]byte("mem"))) + return errors.New("failure") + }) + + // check events + suite.Require().Equal(sdk.Events{{Type: "success1"}}, stateDB.NativeEvents()) + suite.Require().Equal([]*ethtypes.Log{{ + Address: contract, + BlockHash: emptyTxConfig.BlockHash, + TxHash: emptyTxConfig.TxHash, + Data: []byte("success1"), + }}, stateDB.Logs()) + + // test query + stateDB.ExecuteNativeAction(contract, nil, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + suite.Require().Equal([]byte("value"), store.Get([]byte("success1"))) + suite.Require().Nil(store.Get([]byte("failure1"))) + return nil + }) + + rev1 := stateDB.Snapshot() + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + store.Set([]byte("success2"), []byte("value")) + ctx.EventManager().EmitEvent(sdk.NewEvent("success2")) + return nil + }) + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + store.Set([]byte("failure2"), []byte("value")) + ctx.EventManager().EmitEvent(sdk.NewEvent("failure2")) + return errors.New("failure") + }) + + // check events + suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success2"}}, stateDB.NativeEvents()) + suite.Require().Equal([]*ethtypes.Log{{ + Address: contract, + BlockHash: emptyTxConfig.BlockHash, + TxHash: emptyTxConfig.TxHash, + Data: []byte("success1"), + }, { + Index: 1, + Address: contract, + BlockHash: emptyTxConfig.BlockHash, + TxHash: emptyTxConfig.TxHash, + Data: []byte("success2"), + }}, stateDB.Logs()) + + // test query + stateDB.ExecuteNativeAction(contract, nil, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + suite.Require().Equal([]byte("value"), store.Get([]byte("success1"))) + suite.Require().Equal([]byte("value"), store.Get([]byte("success2"))) + suite.Require().Nil(store.Get([]byte("failure2"))) + return nil + }) + + stateDB.RevertToSnapshot(rev1) + + // check events + suite.Require().Equal(sdk.Events{{Type: "success1"}}, stateDB.NativeEvents()) + suite.Require().Equal([]*ethtypes.Log{{ + Address: contract, + BlockHash: emptyTxConfig.BlockHash, + TxHash: emptyTxConfig.TxHash, + Data: []byte("success1"), + }}, stateDB.Logs()) + + _ = stateDB.Snapshot() + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + store.Set([]byte("success3"), []byte("value")) + ctx.EventManager().EmitEvent(sdk.NewEvent("success3")) + return nil + }) + + // check events + suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success3"}}, stateDB.NativeEvents()) + + // test query + stateDB.ExecuteNativeAction(contract, eventConverter, func(ctx sdk.Context) error { + store := ctx.KVStore(storeKey) + suite.Require().Equal([]byte("value"), store.Get([]byte("success1"))) + suite.Require().Nil(store.Get([]byte("success2"))) + suite.Require().Equal([]byte("value"), store.Get([]byte("success3"))) + return nil + }) + + suite.Require().NoError(stateDB.Commit()) + + // query committed state + store := ctx.KVStore(storeKey) + suite.Require().Equal([]byte("value"), store.Get([]byte("success1"))) + suite.Require().Nil(store.Get([]byte("success2"))) + suite.Require().Equal([]byte("value"), store.Get([]byte("success3"))) + suite.Require().Nil(store.Get([]byte("failure1"))) + suite.Require().Nil(store.Get([]byte("failure2"))) + + // check events + suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success3"}}, ctx.EventManager().Events()) +} + func CollectContractStorage(db vm.StateDB) statedb.Storage { storage := make(statedb.Storage) db.ForEachStorage(address, func(k, v common.Hash) bool { @@ -574,6 +759,94 @@ func CollectContractStorage(db vm.StateDB) statedb.Storage { return storage } +var ( + testStoreKeys = storetypes.NewKVStoreKeys(authtypes.StoreKey, banktypes.StoreKey, evmtypes.StoreKey, "testnative") + testObjKeys = storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey, evmtypes.ObjectStoreKey) + testMemKeys = storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) +) + +func cloneRawState(_ *testing.T, cms storetypes.MultiStore) map[string]map[string][]byte { + result := make(map[string]map[string][]byte) + + for name, key := range testStoreKeys { + store := cms.GetKVStore(key) + itr := store.Iterator(nil, nil) + defer itr.Close() + + state := make(map[string][]byte) + for ; itr.Valid(); itr.Next() { + state[string(itr.Key())] = itr.Value() + } + + result[name] = state + } + + return result +} + +func newTestKeeper(_ *testing.T, cms storetypes.MultiStore) (sdk.Context, *evmkeeper.Keeper) { + appCodec := config.MakeConfigForTest(nil).Codec + authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + accountKeeper := authkeeper.NewAccountKeeper( + appCodec, + runtime.NewKVStoreService(testStoreKeys[authtypes.StoreKey]), + ethermint.ProtoAccount, + map[string][]string{ + evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + }, + sdkaddress.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), + sdk.GetConfig().GetBech32AccountAddrPrefix(), + authAddr, + ) + bankKeeper := bankkeeper.NewBaseKeeper( + appCodec, + runtime.NewKVStoreService(testStoreKeys[banktypes.StoreKey]), + testObjKeys[banktypes.ObjectStoreKey], + accountKeeper, + map[string]bool{}, + authAddr, + log.NewNopLogger(), + ) + evmKeeper := evmkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(testStoreKeys[banktypes.StoreKey]), + testStoreKeys[evmtypes.StoreKey], + authtypes.NewModuleAddress(govtypes.ModuleName), + accountKeeper, + bankKeeper, + nil, + nil, + nil, + nil, + "", + paramstypes.Subspace{}, + ) + + ctx := sdk.NewContext(cms, tmproto.Header{}, false, log.NewNopLogger()) + return ctx, evmKeeper +} + +func setupTestEnv(t *testing.T) (storetypes.MultiStore, sdk.Context, *evmkeeper.Keeper) { + db := dbm.NewMemDB() + cms := rootmulti.NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + for _, key := range testStoreKeys { + cms.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) + } + for _, key := range testMemKeys { + cms.MountStoreWithDB(key, storetypes.StoreTypeMemory, nil) + } + for _, key := range testObjKeys { + cms.MountStoreWithDB(key, storetypes.StoreTypeObject, nil) + } + require.NoError(t, cms.LoadLatestVersion()) + + ctx, keeper := newTestKeeper(t, cms) + require.NoError(t, keeper.SetParams(ctx, evmtypes.Params{ + EvmDenom: "uphoton", + })) + return cms, ctx, keeper +} + func TestStateDBTestSuite(t *testing.T) { suite.Run(t, &StateDBTestSuite{}) } diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index a0c6de2868..63d58cfb1c 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -104,7 +104,7 @@ func getBlockValue(block *sdkmath.Int) *big.Int { return nil } - return block.BigInt() + return block.BigIntMut() } // Validate performs a basic validation of the ChainConfig params. The function will return an error diff --git a/x/evm/types/interfaces.go b/x/evm/types/interfaces.go index a75d61a63d..441817a3a8 100644 --- a/x/evm/types/interfaces.go +++ b/x/evm/types/interfaces.go @@ -50,6 +50,8 @@ type BankKeeper interface { authtypes.BankKeeper GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToAccountVirtual(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModuleVirtual(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error } @@ -65,7 +67,6 @@ type StakingKeeper interface { type FeeMarketKeeper interface { GetBaseFee(ctx sdk.Context) *big.Int GetParams(ctx sdk.Context) feemarkettypes.Params - AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error) } // Event Hooks diff --git a/x/evm/types/key.go b/x/evm/types/key.go index f8d768fc85..b3b7173ba9 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -16,7 +16,10 @@ package types import ( + "encoding/binary" + "github.com/ethereum/go-ethereum/common" + ethermint "github.com/evmos/ethermint/types" ) const ( @@ -28,9 +31,9 @@ const ( // The EVM module should use a prefix store. StoreKey = ModuleName - // TransientKey is the key to access the EVM transient store, that is reset + // ObjectStoreKey is the key to access the EVM object store, that is reset // during the Commit phase. - TransientKey = "transient_" + ModuleName + ObjectStoreKey = "object:" + ModuleName // RouterKey uses module name for routing RouterKey = ModuleName @@ -43,12 +46,11 @@ const ( prefixParams ) -// prefix bytes for the EVM transient store +// prefix bytes for the EVM object store const ( - prefixTransientBloom = iota + 1 - prefixTransientTxIndex - prefixTransientLogSize - prefixTransientGasUsed + prefixObjectBloom = iota + 1 + prefixObjectGasUsed + prefixObjectParams ) // KVStore key prefixes @@ -58,12 +60,12 @@ var ( KeyPrefixParams = []byte{prefixParams} ) -// Transient Store key prefixes +// Object Store key prefixes var ( - KeyPrefixTransientBloom = []byte{prefixTransientBloom} - KeyPrefixTransientTxIndex = []byte{prefixTransientTxIndex} - KeyPrefixTransientLogSize = []byte{prefixTransientLogSize} - KeyPrefixTransientGasUsed = []byte{prefixTransientGasUsed} + KeyPrefixObjectBloom = []byte{prefixObjectBloom} + KeyPrefixObjectGasUsed = []byte{prefixObjectGasUsed} + // cache the `EVMBlockConfig` during the whole block execution + KeyPrefixObjectParams = []byte{prefixObjectParams} ) // AddressStoragePrefix returns a prefix to iterate over a given account storage. @@ -75,3 +77,36 @@ func AddressStoragePrefix(address common.Address) []byte { func StateKey(address common.Address, key []byte) []byte { return append(AddressStoragePrefix(address), key...) } + +func ObjectGasUsedKey(txIndex int) []byte { + var key [1 + 8]byte + key[0] = prefixObjectGasUsed + if txIndex < 0 { + return key[:] + } + idx, err := ethermint.SafeIntToUint64(txIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[1:], idx) + return key[:] +} + +func ObjectBloomKey(txIndex, msgIndex int) []byte { + var key [1 + 8 + 8]byte + key[0] = prefixObjectBloom + if txIndex < 0 || msgIndex < 0 { + return key[:] + } + value, err := ethermint.SafeIntToUint64(txIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[1:], value) + value, err = ethermint.SafeIntToUint64(msgIndex) + if err != nil { + panic(err) + } + binary.BigEndian.PutUint64(key[9:], value) + return key[:] +} diff --git a/x/evm/types/logs.go b/x/evm/types/logs.go index fece366e9b..0289d88bdc 100644 --- a/x/evm/types/logs.go +++ b/x/evm/types/logs.go @@ -129,7 +129,7 @@ func NewLogFromEth(log *ethtypes.Log) *Log { } return &Log{ - Address: log.Address.String(), + Address: HexAddress(log.Address.Bytes()), Topics: topics, Data: log.Data, BlockNumber: log.BlockNumber, diff --git a/x/evm/types/msg.go b/x/evm/types/msg.go index 7d52548c13..7448cf9606 100644 --- a/x/evm/types/msg.go +++ b/x/evm/types/msg.go @@ -16,6 +16,7 @@ package types import ( + "bytes" "errors" "fmt" "math/big" @@ -36,8 +37,6 @@ import ( authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" evmapi "github.com/evmos/ethermint/api/ethermint/evm/v1" - "github.com/evmos/ethermint/types" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" @@ -170,13 +169,30 @@ func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error { return nil } +// FromSignedEthereumTx populates the message fields from the given signed ethereum transaction, and set From field. +func (msg *MsgEthereumTx) FromSignedEthereumTx(tx *ethtypes.Transaction, chainID *big.Int) error { + if err := msg.FromEthereumTx(tx); err != nil { + return err + } + + from, err := msg.recoverSender(chainID) + if err != nil { + return err + } + + msg.From = from.Bytes() + return nil +} + // ValidateBasic implements the sdk.Msg interface. It performs basic validation // checks of a Transaction. If returns an error if validation fails. func (msg MsgEthereumTx) ValidateBasic() error { - if msg.From != "" { - if err := types.ValidateAddress(msg.From); err != nil { - return errorsmod.Wrap(err, "invalid from address") - } + if len(msg.DeprecatedFrom) != 0 { + return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "deprecated From field is not empty") + } + + if len(msg.From) == 0 { + return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "sender address is missing") } // Validate Size_ field, should be kept empty @@ -227,25 +243,35 @@ func (msg *MsgEthereumTx) GetMsgsV2() ([]protov2.Message, error) { // GetSigners returns the expected signers for an Ethereum transaction message. // For such a message, there should exist only a single 'signer'. -// -// NOTE: This method panics if 'Sign' hasn't been called first. func (msg *MsgEthereumTx) GetSigners() []sdk.AccAddress { - if len(msg.From) > 0 { - return []sdk.AccAddress{common.HexToAddress(msg.From).Bytes()} + if len(msg.From) == 0 { + return nil } + return []sdk.AccAddress{msg.GetFrom()} +} - data, err := UnpackTxData(msg.Data) - if err != nil { - panic(err) - } +// GetSender convert the From field to common.Address +// From should always be set, which is validated in ValidateBasic +func (msg *MsgEthereumTx) GetSender() common.Address { + return common.BytesToAddress(msg.From) +} - sender, err := msg.GetSender(data.GetChainID()) +// GetSenderLegacy fallbacks to old behavior if From is empty, should be used by json-rpc +func (msg *MsgEthereumTx) GetSenderLegacy(chainID *big.Int) (common.Address, error) { + if len(msg.From) > 0 { + return msg.GetSender(), nil + } + sender, err := msg.recoverSender(chainID) if err != nil { - panic(err) + return common.Address{}, err } + msg.From = sender.Bytes() + return sender, nil +} - signer := sdk.AccAddress(sender.Bytes()) - return []sdk.AccAddress{signer} +// recoverSender recovers the sender address from the transaction signature. +func (msg *MsgEthereumTx) recoverSender(chainID *big.Int) (common.Address, error) { + return ethtypes.LatestSignerForChainID(chainID).Sender(msg.AsTransaction()) } // GetSignBytes returns the Amino bytes of an Ethereum transaction message used @@ -316,11 +342,7 @@ func (msg MsgEthereumTx) GetEffectiveFee(baseFee *big.Int) *big.Int { // GetFrom loads the ethereum sender address from the sigcache and returns an // sdk.AccAddress from its bytes func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress { - if msg.From == "" { - return nil - } - - return common.HexToAddress(msg.From).Bytes() + return sdk.AccAddress(msg.From) } // AsTransaction creates an Ethereum Transaction type from the msg fields @@ -334,7 +356,7 @@ func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction { } // AsMessage creates an Ethereum core.Message from the msg fields -func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (core.Message, error) { +func (msg MsgEthereumTx) AsMessage(baseFee *big.Int) (core.Message, error) { txData, err := UnpackTxData(msg.Data) if err != nil { return nil, err @@ -344,22 +366,8 @@ func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (co if baseFee != nil { gasPrice = math.BigMin(gasPrice.Add(gasTipCap, baseFee), gasFeeCap) } - var from common.Address - if len(msg.From) > 0 { - // user can't set arbitrary value in `From` field in transaction, - // the SigVerify ante handler will verify the signature and recover - // the sender address and populate the `From` field, so the other code can - // use it directly when available. - from = common.HexToAddress(msg.From) - } else { - // heavy path - from, err = signer.Sender(msg.AsTransaction()) - if err != nil { - return nil, err - } - } ethMsg := ethtypes.NewMessage( - from, + msg.GetSender(), txData.GetTo(), txData.GetNonce(), txData.GetValue(), @@ -373,16 +381,17 @@ func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (co return ethMsg, nil } -// GetSender extracts the sender address from the signature values using the latest signer for the given chainID. -func (msg *MsgEthereumTx) GetSender(chainID *big.Int) (common.Address, error) { - signer := ethtypes.LatestSignerForChainID(chainID) - from, err := signer.Sender(msg.AsTransaction()) +// VerifySender verify the sender address against the signature values using the latest signer for the given chainID. +func (msg *MsgEthereumTx) VerifySender(chainID *big.Int) error { + from, err := msg.recoverSender(chainID) if err != nil { - return common.Address{}, err + return err } - msg.From = from.Hex() - return from, nil + if !bytes.Equal(msg.From, from.Bytes()) { + return fmt.Errorf("sender verification failed. got %s, expected %s", HexAddress(from.Bytes()), HexAddress(msg.From)) + } + return nil } // UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces @@ -391,12 +400,12 @@ func (msg MsgEthereumTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error } // UnmarshalBinary decodes the canonical encoding of transactions. -func (msg *MsgEthereumTx) UnmarshalBinary(b []byte) error { +func (msg *MsgEthereumTx) UnmarshalBinary(b []byte, chainID *big.Int) error { tx := ðtypes.Transaction{} if err := tx.UnmarshalBinary(b); err != nil { return err } - return msg.FromEthereumTx(tx) + return msg.FromSignedEthereumTx(tx, chainID) } // BuildTx builds the canonical cosmos tx from ethereum msg @@ -423,9 +432,6 @@ func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (authsign builder.SetExtensionOptions(option) - // A valid msg should have empty `From` - msg.From = "" - err = builder.SetMsgs(msg) if err != nil { return nil, err diff --git a/x/evm/types/msg_test.go b/x/evm/types/msg_test.go index d929f17ae8..b09e6e0083 100644 --- a/x/evm/types/msg_test.go +++ b/x/evm/types/msg_test.go @@ -63,7 +63,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_Constructor() { suite.Require().Equal(sdk.MsgTypeURL(msg), "/ethermint.evm.v1.MsgEthereumTx") // suite.Require().NotNil(msg.To()) suite.Require().Equal(msg.GetMsgs(), []sdk.Msg{msg}) - suite.Require().Panics(func() { msg.GetSigners() }) + suite.Require().Empty(msg.GetSigners()) suite.Require().Panics(func() { msg.GetSignBytes() }) msg = types.NewTxContract(nil, 0, nil, 100000, nil, nil, nil, []byte("test"), nil) @@ -114,6 +114,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { zeroInt := big.NewInt(0) minusOneInt := big.NewInt(-1) exp_2_255 := new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil) + validFrom := common.BigToAddress(big.NewInt(1)).Bytes() testCases := []struct { msg string @@ -123,7 +124,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { gasPrice *big.Int gasFeeCap *big.Int gasTipCap *big.Int - from string + from []byte accessList *ethtypes.AccessList chainID *big.Int expectPass bool @@ -131,6 +132,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "pass with recipient - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: hundredInt, @@ -141,6 +143,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "pass with recipient - AccessList Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -153,6 +156,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "pass with recipient - DynamicFee Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -165,6 +169,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "pass contract - Legacy Tx", to: "", + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: hundredInt, @@ -175,6 +180,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "invalid recipient", to: invalidFromAddress, + from: validFrom, amount: minusOneInt, gasLimit: 1000, gasPrice: hundredInt, @@ -183,6 +189,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "nil amount - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: nil, gasLimit: 1000, gasPrice: hundredInt, @@ -193,6 +200,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "negative amount - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: minusOneInt, gasLimit: 1000, gasPrice: hundredInt, @@ -203,6 +211,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "zero gas limit - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 0, gasPrice: hundredInt, @@ -213,6 +222,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "nil gas price - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: nil, @@ -223,6 +233,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "negative gas price - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: minusOneInt, @@ -233,6 +244,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "zero gas price - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -248,12 +260,13 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { gasPrice: zeroInt, gasFeeCap: nil, gasTipCap: nil, - from: invalidFromAddress, + from: nil, expectPass: false, }, { msg: "out of bound gas fee - Legacy Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: exp_2_255, @@ -264,6 +277,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "nil amount - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: nil, gasLimit: 1000, gasPrice: hundredInt, @@ -276,6 +290,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "negative amount - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: minusOneInt, gasLimit: 1000, gasPrice: hundredInt, @@ -288,6 +303,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "zero gas limit - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 0, gasPrice: zeroInt, @@ -300,6 +316,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "nil gas price - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: nil, @@ -312,6 +329,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "negative gas price - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: minusOneInt, @@ -324,6 +342,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "zero gas price - AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -341,7 +360,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { gasPrice: zeroInt, gasFeeCap: nil, gasTipCap: nil, - from: invalidFromAddress, + from: nil, accessList: ðtypes.AccessList{}, chainID: hundredInt, expectPass: false, @@ -349,6 +368,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "chain ID not set on AccessListTx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -361,6 +381,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { { msg: "nil tx.Data - AccessList Tx", to: suite.to.Hex(), + from: validFrom, amount: hundredInt, gasLimit: 1000, gasPrice: zeroInt, @@ -374,7 +395,7 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { for _, tc := range testCases { suite.Run(tc.msg, func() { - to := common.HexToAddress(tc.from) + to := common.HexToAddress(tc.to) tx := types.NewTx(tc.chainID, 1, &to, tc.amount, tc.gasLimit, tc.gasPrice, tc.gasFeeCap, tc.gasTipCap, nil, tc.accessList) tx.From = tc.from @@ -466,42 +487,42 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_Sign() { "pass - EIP2930 signer", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), ðtypes.AccessList{}), ethtypes.NewEIP2930Signer(suite.chainID), - func(tx *types.MsgEthereumTx) { tx.From = suite.from.Hex() }, + func(tx *types.MsgEthereumTx) { tx.From = suite.from.Bytes() }, true, }, { "pass - EIP155 signer", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), nil), ethtypes.NewEIP155Signer(suite.chainID), - func(tx *types.MsgEthereumTx) { tx.From = suite.from.Hex() }, + func(tx *types.MsgEthereumTx) { tx.From = suite.from.Bytes() }, true, }, { "pass - Homestead signer", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), nil), ethtypes.HomesteadSigner{}, - func(tx *types.MsgEthereumTx) { tx.From = suite.from.Hex() }, + func(tx *types.MsgEthereumTx) { tx.From = suite.from.Bytes() }, true, }, { "pass - Frontier signer", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), nil), ethtypes.FrontierSigner{}, - func(tx *types.MsgEthereumTx) { tx.From = suite.from.Hex() }, + func(tx *types.MsgEthereumTx) { tx.From = suite.from.Bytes() }, true, }, { "no from address ", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), ðtypes.AccessList{}), ethtypes.NewEIP2930Signer(suite.chainID), - func(tx *types.MsgEthereumTx) { tx.From = "" }, + func(tx *types.MsgEthereumTx) { tx.From = nil }, false, }, { "from address ≠ signer address", types.NewTx(suite.chainID, 0, &suite.to, nil, 100000, nil, nil, nil, []byte("test"), ðtypes.AccessList{}), ethtypes.NewEIP2930Signer(suite.chainID), - func(tx *types.MsgEthereumTx) { tx.From = suite.to.Hex() }, + func(tx *types.MsgEthereumTx) { tx.From = suite.to.Bytes() }, false, }, } @@ -513,9 +534,8 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_Sign() { if tc.expectPass { suite.Require().NoError(err, "valid test %d failed: %s", i, tc.msg) - sender, err := tc.tx.GetSender(suite.chainID) suite.Require().NoError(err, tc.msg) - suite.Require().Equal(tc.tx.From, sender.Hex(), tc.msg) + suite.Require().NoError(tc.tx.VerifySender(suite.chainID)) } else { suite.Require().Error(err, "invalid test %d passed: %s", i, tc.msg) } @@ -761,7 +781,7 @@ func (suite *MsgsTestSuite) TestTransactionCoding() { suite.T().Fatalf("could not sign transaction: %v", err) } // RLP - parsedTx, err := encodeDecodeBinary(tx) + parsedTx, err := encodeDecodeBinary(tx, signer.ChainID()) if err != nil { suite.T().Fatal(err) } @@ -769,13 +789,13 @@ func (suite *MsgsTestSuite) TestTransactionCoding() { } } -func encodeDecodeBinary(tx *ethtypes.Transaction) (*types.MsgEthereumTx, error) { +func encodeDecodeBinary(tx *ethtypes.Transaction, chainID *big.Int) (*types.MsgEthereumTx, error) { data, err := tx.MarshalBinary() if err != nil { return nil, fmt.Errorf("rlp encoding failed: %v", err) } parsedTx := &types.MsgEthereumTx{} - if err := parsedTx.UnmarshalBinary(data); err != nil { + if err := parsedTx.UnmarshalBinary(data, chainID); err != nil { return nil, fmt.Errorf("rlp decoding failed: %v", err) } return parsedTx, nil diff --git a/x/evm/types/response.go b/x/evm/types/response.go new file mode 100644 index 0000000000..8166405783 --- /dev/null +++ b/x/evm/types/response.go @@ -0,0 +1,89 @@ +package types + +import ( + "strconv" + + abci "github.com/cometbft/cometbft/abci/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + proto "github.com/cosmos/gogoproto/proto" +) + +// PatchTxResponses fills the evm tx index and log indexes in the tx result +func PatchTxResponses(input []*abci.ExecTxResult) []*abci.ExecTxResult { + var ( + txIndex uint64 + logIndex uint64 + ) + for _, res := range input { + // assume no error result in msg handler + if res.Code != 0 { + continue + } + + var txMsgData sdk.TxMsgData + if err := proto.Unmarshal(res.Data, &txMsgData); err != nil { + panic(err) + } + + var ( + anteEvents []abci.Event + // if the response data is modified and need to be marshaled back + dataDirty bool + ) + for i, rsp := range txMsgData.MsgResponses { + var response MsgEthereumTxResponse + if rsp.TypeUrl != "/"+proto.MessageName(&response) { + continue + } + + if err := proto.Unmarshal(rsp.Value, &response); err != nil { + panic(err) + } + + anteEvents = append(anteEvents, abci.Event{ + Type: EventTypeEthereumTx, + Attributes: []abci.EventAttribute{ + {Key: AttributeKeyEthereumTxHash, Value: response.Hash}, + {Key: AttributeKeyTxIndex, Value: strconv.FormatUint(txIndex, 10)}, + }, + }) + + if len(response.Logs) > 0 { + for _, log := range response.Logs { + log.TxIndex = txIndex + log.Index = logIndex + logIndex++ + } + + anyRsp, err := codectypes.NewAnyWithValue(&response) + if err != nil { + panic(err) + } + txMsgData.MsgResponses[i] = anyRsp + + dataDirty = true + } + + txIndex++ + } + + if len(anteEvents) > 0 { + // prepend ante events in front to emulate the side effect of `EthEmitEventDecorator` + events := make([]abci.Event, len(anteEvents)+len(res.Events)) + copy(events, anteEvents) + copy(events[len(anteEvents):], res.Events) + res.Events = events + + if dataDirty { + data, err := proto.Marshal(&txMsgData) + if err != nil { + panic(err) + } + + res.Data = data + } + } + } + return input +} diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go index 9e43b00994..f0cd3cdc3b 100644 --- a/x/evm/types/tx.pb.go +++ b/x/evm/types/tx.pb.go @@ -42,11 +42,12 @@ type MsgEthereumTx struct { // size is the encoded storage size of the transaction (DEPRECATED) Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"` // hash of the transaction in hex format - Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"` - // from is the ethereum signer address in hex format. This address value is checked + Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"` + DeprecatedFrom string `protobuf:"bytes,4,opt,name=deprecated_from,json=deprecatedFrom,proto3" json:"deprecated_from,omitempty"` // Deprecated: Do not use. + // from is the bytes of ethereum signer address. This address value is checked // against the address derived from the signature (V, R, S) using the // secp256k1 elliptic curve - From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` + From []byte `protobuf:"bytes,5,opt,name=from,proto3" json:"from,omitempty"` } func (m *MsgEthereumTx) Reset() { *m = MsgEthereumTx{} } @@ -455,72 +456,74 @@ func init() { func init() { proto.RegisterFile("ethermint/evm/v1/tx.proto", fileDescriptor_f75ac0a12d075f21) } var fileDescriptor_f75ac0a12d075f21 = []byte{ - // 1037 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x8b, 0x23, 0x45, - 0x18, 0x9e, 0x4e, 0x3a, 0x5f, 0x95, 0xa8, 0x6b, 0x33, 0xc3, 0x74, 0xa2, 0x9b, 0x8e, 0x2d, 0xba, - 0xb3, 0x03, 0xd3, 0xcd, 0x44, 0x10, 0x36, 0x5e, 0x9c, 0xec, 0xcc, 0x2e, 0x23, 0x33, 0xb8, 0xb4, - 0xd9, 0x8b, 0x0a, 0xa1, 0xa6, 0x53, 0xd3, 0x29, 0x4c, 0x77, 0x35, 0x5d, 0x95, 0x90, 0x08, 0x82, - 0xec, 0x49, 0x04, 0x41, 0xf0, 0x0f, 0x78, 0xf0, 0x20, 0x9e, 0xe6, 0x30, 0x27, 0x0f, 0x9e, 0x07, - 0x2f, 0x2e, 0xeb, 0x45, 0x3c, 0x44, 0xc9, 0x08, 0x83, 0x73, 0xf4, 0x17, 0x48, 0x55, 0x75, 0x26, - 0x5f, 0xce, 0x07, 0x82, 0x5e, 0x42, 0xbf, 0xf5, 0x7e, 0xd6, 0xf3, 0x3c, 0xbc, 0x15, 0x50, 0x44, - 0xac, 0x8d, 0x22, 0x1f, 0x07, 0xcc, 0x46, 0x3d, 0xdf, 0xee, 0x6d, 0xda, 0xac, 0x6f, 0x85, 0x11, - 0x61, 0x44, 0xbb, 0x75, 0xe1, 0xb2, 0x50, 0xcf, 0xb7, 0x7a, 0x9b, 0xa5, 0x55, 0x97, 0x50, 0x9f, - 0x50, 0xdb, 0xa7, 0x1e, 0x8f, 0xf4, 0xa9, 0x27, 0x43, 0x4b, 0x45, 0xe9, 0x68, 0x0a, 0xcb, 0x96, - 0x46, 0xec, 0x2a, 0x2d, 0x34, 0xe0, 0xc5, 0xa4, 0x6f, 0xd9, 0x23, 0x1e, 0x91, 0x39, 0xfc, 0x2b, - 0x3e, 0x7d, 0xd9, 0x23, 0xc4, 0xeb, 0x20, 0x1b, 0x86, 0xd8, 0x86, 0x41, 0x40, 0x18, 0x64, 0x98, - 0x04, 0xe3, 0x7a, 0xc5, 0xd8, 0x2b, 0xac, 0x83, 0xee, 0xa1, 0x0d, 0x83, 0x41, 0xec, 0x7a, 0x11, - 0xfa, 0x38, 0x20, 0xb6, 0xf8, 0x95, 0x47, 0xe6, 0x89, 0x02, 0x9e, 0xdb, 0xa7, 0xde, 0x0e, 0x9f, - 0x01, 0x75, 0xfd, 0x46, 0x5f, 0xdb, 0x01, 0x6a, 0x0b, 0x32, 0xa8, 0x2b, 0x15, 0x65, 0x2d, 0x5f, - 0x5d, 0xb6, 0x64, 0x39, 0x6b, 0x5c, 0xce, 0xda, 0x0a, 0x06, 0xf5, 0x97, 0x7e, 0x3c, 0xde, 0x58, - 0x9d, 0xbf, 0xbd, 0xd5, 0xe8, 0x6f, 0x43, 0x06, 0x1d, 0x91, 0xae, 0x15, 0x81, 0x4a, 0xf1, 0xc7, - 0x48, 0x4f, 0x54, 0x94, 0x35, 0xa5, 0x9e, 0x3a, 0x1f, 0x1a, 0xca, 0x86, 0x23, 0x8e, 0x34, 0x03, - 0xa8, 0x6d, 0x48, 0xdb, 0x7a, 0xb2, 0xa2, 0xac, 0xe5, 0xea, 0xf9, 0xbf, 0x86, 0x46, 0x26, 0xea, - 0x84, 0x35, 0x73, 0xc3, 0x74, 0x84, 0x43, 0xd3, 0x80, 0x7a, 0x18, 0x11, 0x5f, 0x57, 0x79, 0x80, - 0x23, 0xbe, 0x6b, 0x95, 0xcf, 0xbe, 0x36, 0x96, 0x3e, 0x3f, 0x3b, 0x5a, 0x9f, 0xf4, 0xb5, 0x67, - 0x06, 0x37, 0x7f, 0x48, 0x80, 0xec, 0x1e, 0xf2, 0xa0, 0x3b, 0x68, 0xf4, 0xb5, 0x65, 0x90, 0x0a, - 0x48, 0xe0, 0x22, 0x71, 0x0d, 0xd5, 0x91, 0x86, 0xb6, 0x0d, 0x72, 0x1e, 0xe4, 0x2c, 0x60, 0x57, - 0x4e, 0x96, 0xab, 0xdf, 0xf9, 0x75, 0x68, 0xac, 0x48, 0x42, 0x68, 0xeb, 0x23, 0x0b, 0x13, 0xdb, - 0x87, 0xac, 0x6d, 0xed, 0x06, 0xec, 0xd9, 0xf1, 0x06, 0x88, 0x99, 0xda, 0x0d, 0x98, 0x93, 0xf5, - 0x20, 0x7d, 0xc4, 0x13, 0xb5, 0x32, 0x48, 0x7a, 0x90, 0x8a, 0xf1, 0xd5, 0x7a, 0x61, 0x34, 0x34, - 0xb2, 0x0f, 0x21, 0xdd, 0xc3, 0x3e, 0x66, 0x0e, 0x77, 0x68, 0xcf, 0x83, 0x04, 0x23, 0xf1, 0xf0, - 0x09, 0x46, 0xb4, 0x87, 0x20, 0xd5, 0x83, 0x9d, 0x2e, 0xd2, 0x53, 0xa2, 0xe3, 0xe6, 0xa5, 0x1d, - 0x47, 0x43, 0x23, 0xbd, 0xe5, 0x93, 0xee, 0x42, 0x6f, 0x99, 0xcf, 0x71, 0x11, 0xd4, 0xa4, 0x2b, - 0xca, 0x5a, 0x21, 0xc6, 0xb9, 0x00, 0x94, 0x9e, 0x9e, 0x11, 0x07, 0x4a, 0x8f, 0x5b, 0x91, 0x9e, - 0x95, 0x56, 0xc4, 0x2d, 0xaa, 0xe7, 0xa4, 0x45, 0x6b, 0x06, 0x47, 0xf0, 0x0a, 0xe2, 0xcc, 0x9f, - 0x92, 0xa0, 0xb0, 0xe5, 0xba, 0x88, 0xd2, 0x3d, 0x4c, 0x59, 0xa3, 0xaf, 0xbd, 0x03, 0xb2, 0x6e, - 0x1b, 0xe2, 0xa0, 0x89, 0x5b, 0x02, 0xc7, 0x5c, 0xdd, 0xbe, 0x6a, 0xf6, 0xcc, 0x7d, 0x1e, 0xbc, - 0xbb, 0x7d, 0x3e, 0x34, 0x32, 0xae, 0xfc, 0x74, 0xe2, 0x8f, 0xd6, 0x84, 0x90, 0xc4, 0x34, 0x21, - 0x6f, 0x4e, 0x13, 0x22, 0xf5, 0x50, 0xbc, 0xb4, 0xc5, 0x22, 0x05, 0xea, 0xd5, 0x14, 0xa4, 0x2e, - 0x28, 0xb8, 0x37, 0xa6, 0x20, 0x2d, 0x7a, 0xbc, 0x7a, 0x03, 0x0a, 0xe6, 0x41, 0xcf, 0x4c, 0x81, - 0xfe, 0x01, 0xc8, 0x42, 0x01, 0x14, 0xa2, 0x7a, 0xb6, 0x92, 0x5c, 0xcb, 0x57, 0x6f, 0x5b, 0x0b, - 0xa8, 0x4a, 0x28, 0x1b, 0xdd, 0xb0, 0x83, 0xea, 0x95, 0x93, 0xa1, 0xb1, 0x74, 0x3e, 0x34, 0x00, - 0xbc, 0xc0, 0xf7, 0xbb, 0xdf, 0x0c, 0x30, 0x41, 0xdb, 0xb9, 0x28, 0x28, 0x19, 0xcd, 0xcd, 0x30, - 0x0a, 0x66, 0x18, 0xcd, 0xdf, 0x98, 0xd1, 0x2f, 0x54, 0x50, 0xd8, 0x1e, 0x04, 0xd0, 0xc7, 0xee, - 0x03, 0x84, 0xfe, 0x17, 0x46, 0xef, 0x81, 0x3c, 0x67, 0x94, 0xe1, 0xb0, 0xe9, 0xc2, 0xf0, 0x7a, - 0x4e, 0x39, 0xff, 0x0d, 0x1c, 0xde, 0x87, 0xe1, 0x38, 0xf5, 0x10, 0x21, 0x91, 0xaa, 0xde, 0x24, - 0xf5, 0x01, 0x42, 0x3c, 0x35, 0xd6, 0x43, 0xea, 0x6a, 0x3d, 0xa4, 0x17, 0xf5, 0x90, 0xf9, 0xd7, - 0x7a, 0xc8, 0x5e, 0xa2, 0x87, 0xdc, 0x7f, 0xa2, 0x07, 0x30, 0xa3, 0x87, 0xfc, 0x8c, 0x1e, 0x0a, - 0x37, 0xd6, 0x83, 0x09, 0x4a, 0x3b, 0x7d, 0x86, 0x02, 0x8a, 0x49, 0xf0, 0x6e, 0x28, 0x5e, 0x8d, - 0xc9, 0x02, 0xad, 0xa9, 0x3c, 0xdd, 0xfc, 0x46, 0x01, 0x2b, 0x33, 0x8b, 0xd5, 0x41, 0x34, 0x24, - 0x01, 0x15, 0x37, 0x17, 0x7b, 0x5b, 0x91, 0x6b, 0x59, 0xac, 0xea, 0xbb, 0x40, 0xed, 0x10, 0x8f, - 0xea, 0x09, 0x71, 0xeb, 0x95, 0xc5, 0x5b, 0xef, 0x11, 0xcf, 0x11, 0x21, 0xda, 0x2d, 0x90, 0x8c, - 0x10, 0x13, 0x8a, 0x28, 0x38, 0xfc, 0x53, 0x2b, 0x82, 0x6c, 0xcf, 0x6f, 0xa2, 0x28, 0x22, 0x51, - 0xbc, 0x2e, 0x33, 0x3d, 0x7f, 0x87, 0x9b, 0xdc, 0xc5, 0xb5, 0xd0, 0xa5, 0xa8, 0x25, 0x59, 0x75, - 0x32, 0x1e, 0xa4, 0x8f, 0x29, 0x6a, 0xc5, 0x63, 0x7e, 0xaf, 0x80, 0x17, 0xf6, 0xa9, 0xf7, 0x38, - 0x6c, 0x41, 0x86, 0x1e, 0xc1, 0x08, 0xfa, 0x94, 0x6f, 0x13, 0xd8, 0x65, 0x6d, 0x12, 0x61, 0x36, - 0x88, 0xe5, 0xad, 0x3f, 0x3b, 0xde, 0x58, 0x8e, 0x37, 0xe9, 0x56, 0xab, 0x15, 0x21, 0x4a, 0xdf, - 0x63, 0x11, 0x0e, 0x3c, 0x67, 0x12, 0xaa, 0xbd, 0x05, 0xd2, 0xa1, 0xa8, 0x20, 0xa4, 0x9c, 0xaf, - 0xea, 0x8b, 0xd7, 0x90, 0x1d, 0xea, 0x39, 0xce, 0xdb, 0xb7, 0x67, 0x47, 0xeb, 0x8a, 0x13, 0xa7, - 0xd4, 0xaa, 0x4f, 0xce, 0x8e, 0xd6, 0x27, 0xc5, 0xf8, 0x13, 0x65, 0x4c, 0x9e, 0xa8, 0xbe, 0x78, - 0xd4, 0xe7, 0x06, 0x35, 0x8b, 0x60, 0x75, 0xee, 0x68, 0x0c, 0x72, 0xf5, 0x4f, 0x05, 0x24, 0xf7, - 0xa9, 0xa7, 0x7d, 0x02, 0xc0, 0xd4, 0xa3, 0x6c, 0x2c, 0x4e, 0x34, 0xc3, 0x51, 0xe9, 0xce, 0x35, - 0x01, 0xe3, 0xfa, 0xe6, 0x6b, 0x4f, 0x7e, 0xfe, 0xe3, 0xab, 0x84, 0x61, 0xde, 0xb6, 0x17, 0xff, - 0x77, 0xc4, 0xd1, 0x4d, 0xd6, 0xd7, 0x3e, 0x04, 0x85, 0x19, 0x68, 0x5f, 0xf9, 0xc7, 0xfa, 0xd3, - 0x21, 0xa5, 0xbb, 0xd7, 0x86, 0x8c, 0x87, 0x28, 0xa5, 0x3e, 0xe5, 0x10, 0xd6, 0xdf, 0x3e, 0x19, - 0x95, 0x95, 0xa7, 0xa3, 0xb2, 0xf2, 0xfb, 0xa8, 0xac, 0x7c, 0x79, 0x5a, 0x5e, 0x7a, 0x7a, 0x5a, - 0x5e, 0xfa, 0xe5, 0xb4, 0xbc, 0xf4, 0xfe, 0xeb, 0x1e, 0x66, 0xed, 0xee, 0x81, 0xe5, 0x12, 0x9f, - 0x4f, 0x47, 0xa8, 0x3d, 0x0f, 0x29, 0x1b, 0x84, 0x88, 0x1e, 0xa4, 0xc5, 0xdf, 0x92, 0x37, 0xfe, - 0x0e, 0x00, 0x00, 0xff, 0xff, 0x3e, 0x96, 0x33, 0x9b, 0xa6, 0x09, 0x00, 0x00, + // 1065 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcb, 0x6b, 0x24, 0x45, + 0x18, 0x4f, 0xcf, 0xf4, 0xbc, 0x6a, 0xc6, 0xdd, 0xb5, 0x49, 0x48, 0xcf, 0xe8, 0x4e, 0x8f, 0x2d, + 0xba, 0xd9, 0x48, 0xba, 0x49, 0x04, 0x61, 0xc7, 0x8b, 0xe9, 0x4d, 0xb2, 0x44, 0x12, 0x5c, 0xda, + 0xd9, 0x8b, 0x0a, 0x43, 0xa5, 0xbb, 0xd2, 0xd3, 0x38, 0xdd, 0xd5, 0x74, 0xd5, 0x0c, 0x33, 0x82, + 0x20, 0x7b, 0x12, 0x41, 0x10, 0xfc, 0x07, 0x3c, 0x78, 0x10, 0x4f, 0x39, 0xe4, 0xe4, 0xc1, 0xf3, + 0xe2, 0xc5, 0x65, 0xbd, 0x88, 0x87, 0x51, 0x26, 0x42, 0x30, 0x47, 0xc1, 0xbb, 0x54, 0x55, 0x4f, + 0xe6, 0x65, 0x1e, 0x08, 0x7a, 0x69, 0xea, 0xab, 0xef, 0x51, 0xdf, 0xf7, 0xfb, 0xfd, 0xa8, 0x6a, + 0x50, 0x46, 0xb4, 0x85, 0xe2, 0xc0, 0x0f, 0xa9, 0x89, 0xba, 0x81, 0xd9, 0x5d, 0x37, 0x69, 0xcf, + 0x88, 0x62, 0x4c, 0xb1, 0x72, 0xeb, 0xdc, 0x65, 0xa0, 0x6e, 0x60, 0x74, 0xd7, 0x2b, 0xcb, 0x0e, + 0x26, 0x01, 0x26, 0x66, 0x40, 0x3c, 0x16, 0x19, 0x10, 0x4f, 0x84, 0x56, 0xca, 0xc2, 0xd1, 0xe4, + 0x96, 0x29, 0x8c, 0xc4, 0x55, 0x99, 0x3b, 0x80, 0x15, 0x13, 0xbe, 0x45, 0x0f, 0x7b, 0x58, 0xe4, + 0xb0, 0x55, 0xb2, 0xfb, 0xa2, 0x87, 0xb1, 0xd7, 0x46, 0x26, 0x8c, 0x7c, 0x13, 0x86, 0x21, 0xa6, + 0x90, 0xfa, 0x38, 0x1c, 0xd5, 0x2b, 0x27, 0x5e, 0x6e, 0x1d, 0x74, 0x0e, 0x4d, 0x18, 0xf6, 0x13, + 0xd7, 0xf3, 0x30, 0xf0, 0x43, 0x6c, 0xf2, 0xaf, 0xd8, 0xd2, 0xff, 0x92, 0xc0, 0x73, 0xfb, 0xc4, + 0xdb, 0x66, 0x3d, 0xa0, 0x4e, 0xd0, 0xe8, 0x29, 0xdb, 0x40, 0x76, 0x21, 0x85, 0xaa, 0x54, 0x93, + 0x56, 0x8a, 0x1b, 0x8b, 0x86, 0x28, 0x67, 0x8c, 0xca, 0x19, 0x9b, 0x61, 0xdf, 0x7a, 0xe1, 0x87, + 0xe3, 0xb5, 0xe5, 0xd9, 0xe9, 0x8d, 0x46, 0x6f, 0x0b, 0x52, 0x68, 0xf3, 0x74, 0xa5, 0x0c, 0x64, + 0xe2, 0x7f, 0x84, 0xd4, 0x54, 0x4d, 0x5a, 0x91, 0xac, 0xcc, 0xd9, 0x40, 0x93, 0xd6, 0x6c, 0xbe, + 0xa5, 0x68, 0x40, 0x6e, 0x41, 0xd2, 0x52, 0xd3, 0x35, 0x69, 0xa5, 0x60, 0x15, 0xff, 0x1c, 0x68, + 0xb9, 0xb8, 0x1d, 0xd5, 0xf5, 0x35, 0xdd, 0xe6, 0x0e, 0xe5, 0x35, 0x70, 0xd3, 0x45, 0x51, 0x8c, + 0x1c, 0x48, 0x91, 0xdb, 0x3c, 0x8c, 0x71, 0xa0, 0xca, 0x3c, 0x36, 0xa5, 0x4a, 0xf6, 0x8d, 0xb1, + 0x6b, 0x27, 0xc6, 0x81, 0xa2, 0x00, 0x99, 0x47, 0x64, 0x6a, 0xd2, 0x4a, 0xc9, 0xe6, 0xeb, 0x7a, + 0xed, 0xd3, 0xaf, 0xb4, 0x85, 0xcf, 0x4e, 0x8f, 0x56, 0xc7, 0x4d, 0x9a, 0x53, 0x53, 0xea, 0xdf, + 0xa7, 0x40, 0x7e, 0x0f, 0x79, 0xd0, 0xe9, 0x37, 0x7a, 0xca, 0x22, 0xc8, 0x84, 0x38, 0x74, 0x10, + 0x9f, 0x59, 0xb6, 0x85, 0xa1, 0x6c, 0x81, 0x82, 0x07, 0x19, 0x65, 0xbe, 0x23, 0xc6, 0x28, 0x58, + 0x77, 0x7e, 0x19, 0x68, 0x4b, 0x82, 0x3d, 0xe2, 0x7e, 0x68, 0xf8, 0xd8, 0x0c, 0x20, 0x6d, 0x19, + 0xbb, 0x21, 0x7d, 0x76, 0xbc, 0x06, 0x12, 0x5a, 0x77, 0x43, 0x6a, 0xe7, 0x3d, 0x48, 0x1e, 0xb2, + 0x44, 0xa5, 0x0a, 0xd2, 0x1e, 0x24, 0x7c, 0x56, 0xd9, 0x2a, 0x0d, 0x07, 0x5a, 0xfe, 0x01, 0x24, + 0x7b, 0x7e, 0xe0, 0x53, 0x9b, 0x39, 0x94, 0x1b, 0x20, 0x45, 0xb1, 0x18, 0xcf, 0x4e, 0x51, 0xac, + 0x3c, 0x00, 0x99, 0x2e, 0x6c, 0x77, 0x10, 0x9f, 0xa7, 0x60, 0xad, 0x5f, 0x78, 0xe2, 0x70, 0xa0, + 0x65, 0x37, 0x03, 0xdc, 0x99, 0x3b, 0x5b, 0xe4, 0x33, 0x5c, 0x38, 0x8f, 0x59, 0x81, 0x0b, 0x27, + 0xa5, 0x04, 0xa4, 0xae, 0x9a, 0xe3, 0x1b, 0x52, 0x97, 0x59, 0xb1, 0x9a, 0x17, 0x56, 0xcc, 0x2c, + 0xa2, 0x16, 0x84, 0x45, 0xea, 0x1a, 0x43, 0xf0, 0x12, 0x96, 0xf5, 0x1f, 0xd3, 0xa0, 0xb4, 0xe9, + 0x38, 0x88, 0x90, 0x3d, 0x9f, 0xd0, 0x46, 0x4f, 0x79, 0x1b, 0xe4, 0x9d, 0x16, 0xf4, 0xc3, 0xa6, + 0xef, 0x72, 0x1c, 0x0b, 0x96, 0x79, 0x59, 0xef, 0xb9, 0xfb, 0x2c, 0x78, 0x77, 0xeb, 0x6c, 0xa0, + 0xe5, 0x1c, 0xb1, 0xb4, 0x93, 0x85, 0x3b, 0x26, 0x24, 0x35, 0x49, 0xc8, 0x1b, 0x93, 0x84, 0x08, + 0xf1, 0x94, 0x2f, 0x3c, 0x62, 0x9e, 0x02, 0xf9, 0x72, 0x0a, 0x32, 0xe7, 0x14, 0xdc, 0x1b, 0x51, + 0x90, 0xe5, 0x67, 0xbc, 0x7c, 0x0d, 0x0a, 0x66, 0x41, 0xcf, 0x4d, 0x80, 0xfe, 0x3e, 0xc8, 0x43, + 0x0e, 0x14, 0x22, 0x6a, 0xbe, 0x96, 0x5e, 0x29, 0x6e, 0xdc, 0x36, 0xe6, 0x50, 0x15, 0x50, 0x36, + 0x3a, 0x51, 0x1b, 0x59, 0xb5, 0x27, 0x03, 0x6d, 0xe1, 0x6c, 0xa0, 0x01, 0x78, 0x8e, 0xef, 0xb7, + 0xbf, 0x6a, 0x60, 0x8c, 0xb6, 0x7d, 0x5e, 0x50, 0x30, 0x5a, 0x98, 0x62, 0x14, 0x4c, 0x31, 0x5a, + 0xbc, 0x36, 0xa3, 0x9f, 0xcb, 0xa0, 0xb4, 0xd5, 0x0f, 0x61, 0xe0, 0x3b, 0x3b, 0x08, 0xfd, 0x2f, + 0x8c, 0xde, 0x03, 0x45, 0xc6, 0x28, 0xf5, 0xa3, 0xa6, 0x03, 0xa3, 0xab, 0x39, 0x65, 0xfc, 0x37, + 0xfc, 0xe8, 0x3e, 0x8c, 0x46, 0xa9, 0x87, 0x08, 0xf1, 0x54, 0xf9, 0x3a, 0xa9, 0x3b, 0x08, 0xb1, + 0xd4, 0x44, 0x0f, 0x99, 0xcb, 0xf5, 0x90, 0x9d, 0xd7, 0x43, 0xee, 0x5f, 0xeb, 0x21, 0x7f, 0x81, + 0x1e, 0x0a, 0xff, 0x89, 0x1e, 0xc0, 0x94, 0x1e, 0x8a, 0x53, 0x7a, 0x28, 0x5d, 0x5b, 0x0f, 0x3a, + 0xa8, 0x6c, 0xf7, 0x28, 0x0a, 0x89, 0x8f, 0xc3, 0x77, 0x22, 0xfe, 0xc4, 0x8c, 0x2f, 0xd0, 0xba, + 0xcc, 0xd2, 0xf5, 0xaf, 0x25, 0xb0, 0x34, 0x75, 0xb1, 0xda, 0x88, 0x44, 0x38, 0x24, 0x7c, 0x72, + 0x7e, 0xc9, 0x73, 0xe1, 0x24, 0xf7, 0xfa, 0x5d, 0x20, 0xb7, 0xb1, 0x47, 0xd4, 0x14, 0x9f, 0x7a, + 0x69, 0x7e, 0xea, 0x3d, 0xec, 0xd9, 0x3c, 0x44, 0xb9, 0x05, 0xd2, 0x31, 0xa2, 0x5c, 0x11, 0x25, + 0x9b, 0x2d, 0x95, 0x32, 0xc8, 0x77, 0x83, 0x26, 0x8a, 0x63, 0x1c, 0x27, 0xd7, 0x65, 0xae, 0x1b, + 0x6c, 0x33, 0x93, 0xb9, 0x98, 0x16, 0x3a, 0x04, 0xb9, 0x82, 0x55, 0x3b, 0xe7, 0x41, 0xf2, 0x88, + 0x20, 0x37, 0x69, 0xf3, 0x3b, 0x09, 0xdc, 0xdc, 0x27, 0xde, 0xa3, 0xc8, 0x85, 0x14, 0x3d, 0x84, + 0x31, 0x0c, 0x08, 0xbb, 0x4d, 0x60, 0x87, 0xb6, 0x70, 0xec, 0xd3, 0x7e, 0x22, 0x6f, 0xf5, 0xd9, + 0xf1, 0xda, 0x62, 0x72, 0x93, 0x6e, 0xba, 0x6e, 0x8c, 0x08, 0x79, 0x97, 0xc6, 0x7e, 0xe8, 0xd9, + 0xe3, 0x50, 0xe5, 0x4d, 0x90, 0x8d, 0x78, 0x05, 0x2e, 0xe5, 0xe2, 0x86, 0x3a, 0x3f, 0x86, 0x38, + 0xc1, 0x2a, 0x30, 0xde, 0xbe, 0x39, 0x3d, 0x5a, 0x95, 0xec, 0x24, 0xa5, 0xbe, 0xf1, 0xf8, 0xf4, + 0x68, 0x75, 0x5c, 0x8c, 0x3d, 0x51, 0xda, 0xf8, 0x89, 0xea, 0xf1, 0x3f, 0x80, 0x99, 0x46, 0xf5, + 0x32, 0x58, 0x9e, 0xd9, 0x1a, 0x81, 0xbc, 0xf1, 0x87, 0x04, 0xd2, 0xfb, 0xc4, 0x53, 0x3e, 0x06, + 0x60, 0xe2, 0x05, 0xd7, 0xe6, 0x3b, 0x9a, 0xe2, 0xa8, 0x72, 0xe7, 0x8a, 0x80, 0x51, 0x7d, 0xfd, + 0x95, 0xc7, 0x3f, 0xfd, 0xfe, 0x65, 0x4a, 0xd3, 0x6f, 0x9b, 0xf3, 0x3f, 0x29, 0x49, 0x74, 0x93, + 0xf6, 0x94, 0x0f, 0x40, 0x69, 0x0a, 0xda, 0x97, 0xfe, 0xb1, 0xfe, 0x64, 0x48, 0xe5, 0xee, 0x95, + 0x21, 0xa3, 0x26, 0x2a, 0x99, 0x4f, 0x18, 0x84, 0xd6, 0x5b, 0x4f, 0x86, 0x55, 0xe9, 0xe9, 0xb0, + 0x2a, 0xfd, 0x36, 0xac, 0x4a, 0x5f, 0x9c, 0x54, 0x17, 0x9e, 0x9e, 0x54, 0x17, 0x7e, 0x3e, 0xa9, + 0x2e, 0xbc, 0xf7, 0xaa, 0xe7, 0xd3, 0x56, 0xe7, 0xc0, 0x70, 0x70, 0xc0, 0xba, 0xc3, 0xc4, 0x9c, + 0x85, 0x94, 0xf6, 0x23, 0x44, 0x0e, 0xb2, 0xfc, 0x1f, 0xe6, 0xf5, 0xbf, 0x03, 0x00, 0x00, 0xff, + 0xff, 0x15, 0xc1, 0x6b, 0xfd, 0xd3, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -670,6 +673,13 @@ func (m *MsgEthereumTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.From) i = encodeVarintTx(dAtA, i, uint64(len(m.From))) i-- + dAtA[i] = 0x2a + } + if len(m.DeprecatedFrom) > 0 { + i -= len(m.DeprecatedFrom) + copy(dAtA[i:], m.DeprecatedFrom) + i = encodeVarintTx(dAtA, i, uint64(len(m.DeprecatedFrom))) + i-- dAtA[i] = 0x22 } if len(m.Hash) > 0 { @@ -1217,6 +1227,10 @@ func (m *MsgEthereumTx) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = len(m.DeprecatedFrom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } l = len(m.From) if l > 0 { n += 1 + l + sovTx(uint64(l)) @@ -1556,7 +1570,7 @@ func (m *MsgEthereumTx) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedFrom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1584,7 +1598,41 @@ func (m *MsgEthereumTx) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.From = string(dAtA[iNdEx:postIndex]) + m.DeprecatedFrom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.From = append(m.From[:0], dAtA[iNdEx:postIndex]...) + if m.From == nil { + m.From = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/evm/types/tx_args.go b/x/evm/types/tx_args.go index f445e23a08..e286b8637b 100644 --- a/x/evm/types/tx_args.go +++ b/x/evm/types/tx_args.go @@ -73,7 +73,8 @@ func (args *TransactionArgs) ToTransaction() *MsgEthereumTx { var ( chainID, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas sdkmath.Int gas, nonce uint64 - from, to string + to string + from []byte ) // Set sender address or use zero address if none specified. @@ -156,7 +157,7 @@ func (args *TransactionArgs) ToTransaction() *MsgEthereumTx { } if args.From != nil { - from = args.From.Hex() + from = args.From.Bytes() } msg := MsgEthereumTx{ diff --git a/x/evm/types/utils.go b/x/evm/types/utils.go index a13c98de33..193a858963 100644 --- a/x/evm/types/utils.go +++ b/x/evm/types/utils.go @@ -16,6 +16,7 @@ package types import ( + "encoding/hex" "fmt" "math/big" @@ -38,21 +39,35 @@ var EmptyCodeHash = crypto.Keccak256(nil) // DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse func DecodeTxResponse(in []byte) (*MsgEthereumTxResponse, error) { - var txMsgData sdk.TxMsgData - if err := proto.Unmarshal(in, &txMsgData); err != nil { + responses, err := DecodeTxResponses(in) + if err != nil { return nil, err } - - if len(txMsgData.MsgResponses) == 0 { + if len(responses) == 0 { return &MsgEthereumTxResponse{}, nil } + return responses[0], nil +} - var res MsgEthereumTxResponse - if err := proto.Unmarshal(txMsgData.MsgResponses[0].Value, &res); err != nil { - return nil, errorsmod.Wrap(err, "failed to unmarshal tx response message data") +// DecodeTxResponses decodes a protobuf-encoded byte slice into TxResponses +func DecodeTxResponses(in []byte) ([]*MsgEthereumTxResponse, error) { + var txMsgData sdk.TxMsgData + if err := proto.Unmarshal(in, &txMsgData); err != nil { + return nil, err } - - return &res, nil + responses := make([]*MsgEthereumTxResponse, 0, len(txMsgData.MsgResponses)) + for _, res := range txMsgData.MsgResponses { + var response MsgEthereumTxResponse + if res.TypeUrl != "/"+proto.MessageName(&response) { + continue + } + err := proto.Unmarshal(res.Value, &response) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to unmarshal tx response message data") + } + responses = append(responses, &response) + } + return responses, nil } // EncodeTransactionLogs encodes TransactionLogs slice into a protobuf-encoded byte slice. @@ -116,3 +131,11 @@ func BinSearch(lo, hi uint64, executable func(uint64) (bool, *MsgEthereumTxRespo func EffectiveGasPrice(baseFee *big.Int, feeCap *big.Int, tipCap *big.Int) *big.Int { return math.BigMin(new(big.Int).Add(tipCap, baseFee), feeCap) } + +// HexAddress encode ethereum address without checksum, faster to run for state machine +func HexAddress(a []byte) string { + var buf [common.AddressLength*2 + 2]byte + copy(buf[:2], "0x") + hex.Encode(buf[2:], a) + return string(buf[:]) +} diff --git a/x/evm/types/utils_test.go b/x/evm/types/utils_test.go index 9d3e80c511..4d3b3a2225 100644 --- a/x/evm/types/utils_test.go +++ b/x/evm/types/utils_test.go @@ -41,11 +41,11 @@ func TestEvmDataEncoding(t *testing.T) { txDataBz, err := proto.Marshal(txData) require.NoError(t, err) - res, err := evmtypes.DecodeTxResponse(txDataBz) + rsps, err := evmtypes.DecodeTxResponses(txDataBz) require.NoError(t, err) - require.NotNil(t, res) - require.Equal(t, data.Logs, res.Logs) - require.Equal(t, ret, res.Ret) + require.NotEmpty(t, rsps) + require.Equal(t, data.Logs, rsps[0].Logs) + require.Equal(t, ret, rsps[0].Ret) } func TestUnwrapEthererumMsg(t *testing.T) { @@ -62,6 +62,7 @@ func TestUnwrapEthererumMsg(t *testing.T) { msg := evmtypes.NewTx(big.NewInt(1), 0, &common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil, nil, []byte{}, nil) err = builder.SetMsgs(msg) + require.NoError(t, err) tx = builder.GetTx().(sdk.Tx) msg_, err := evmtypes.UnwrapEthereumMsg(&tx, msg.AsTransaction().Hash()) diff --git a/x/feemarket/genesis.go b/x/feemarket/genesis.go index 9568465e71..a46264bb00 100644 --- a/x/feemarket/genesis.go +++ b/x/feemarket/genesis.go @@ -45,7 +45,7 @@ func InitGenesis( // ExportGenesis exports genesis state of the fee market module func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - storedGasWanted, _ := k.GetBlockGasWanted(ctx) + storedGasWanted := k.GetBlockGasWanted(ctx) return &types.GenesisState{ Params: k.GetParams(ctx), BlockGas: storedGasWanted, diff --git a/x/feemarket/keeper/abci.go b/x/feemarket/keeper/abci.go index 4f403bf005..7c93c47701 100644 --- a/x/feemarket/keeper/abci.go +++ b/x/feemarket/keeper/abci.go @@ -24,6 +24,7 @@ import ( "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + ethermint "github.com/evmos/ethermint/types" ) // BeginBlock updates base fee @@ -60,22 +61,25 @@ func (k *Keeper) BeginBlocker(ctx context.Context) error { func (k *Keeper) EndBlocker(ctx context.Context) error { sdkCtx := sdk.UnwrapSDKContext(ctx) - if sdkCtx.BlockGasMeter() == nil { - k.Logger(sdkCtx).Error("block gas meter is nil when setting block gas wanted") - return nil + gasWanted := sdkCtx.BlockGasWanted() + gw, err := ethermint.SafeInt64(gasWanted) + if err != nil { + return err } - - gasWanted := k.GetTransientGasWanted(sdkCtx) - gasUsed := sdkCtx.BlockGasMeter().GasConsumedToLimit() + gasUsed, err := ethermint.SafeInt64(sdkCtx.BlockGasUsed()) + if err != nil { + return err + } + // gasUsed := sdkCtx.BlockGasMeter().GasConsumedToLimit() // to prevent BaseFee manipulation we limit the gasWanted so that // gasWanted = max(gasWanted * MinGasMultiplier, gasUsed) // this will be keep BaseFee protected from un-penalized manipulation // more info here https://github.com/evmos/ethermint/pull/1105#discussion_r888798925 minGasMultiplier := k.GetParams(sdkCtx).MinGasMultiplier - limitedGasWanted := math.LegacyNewDec(int64(gasWanted)).Mul(minGasMultiplier) //#nosec G115 + limitedGasWanted := math.LegacyNewDec(gw).Mul(minGasMultiplier) //#nosec G115 gasWanted = math.LegacyMaxDec(limitedGasWanted, math.LegacyNewDec(int64(gasUsed))).TruncateInt().Uint64() //#nosec G115 - err := k.SetBlockGasWanted(sdkCtx, gasWanted) + err = k.SetBlockGasWanted(sdkCtx, gasWanted) if err != nil { return err } diff --git a/x/feemarket/keeper/abci_test.go b/x/feemarket/keeper/abci_test.go index e1fec84181..8240d7c3ae 100644 --- a/x/feemarket/keeper/abci_test.go +++ b/x/feemarket/keeper/abci_test.go @@ -24,8 +24,7 @@ func (suite *KeeperTestSuite) TestEndBlock() { false, func() { meter := storetypes.NewGasMeter(uint64(1000000000)) - suite.ctx = suite.ctx.WithBlockGasMeter(meter) - suite.app.FeeMarketKeeper.SetTransientBlockGasWanted(suite.ctx, 5000000) + suite.ctx = suite.ctx.WithBlockGasMeter(meter).WithBlockGasWanted(5000000) }, uint64(2500000), }, @@ -39,9 +38,8 @@ func (suite *KeeperTestSuite) TestEndBlock() { tc.malleate() suite.app.FeeMarketKeeper.EndBlocker(suite.ctx.WithBlockHeight(1)) - gasWanted, err := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) + gasWanted := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) suite.Require().Equal(tc.expGasWanted, gasWanted, tc.name) - suite.Require().NoError(err) }) } } diff --git a/x/feemarket/keeper/eip1559.go b/x/feemarket/keeper/eip1559.go index 366271afd3..0a6d53fc99 100644 --- a/x/feemarket/keeper/eip1559.go +++ b/x/feemarket/keeper/eip1559.go @@ -16,6 +16,7 @@ package keeper import ( + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -35,7 +36,6 @@ func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int { if !params.IsBaseFeeEnabled(ctx.BlockHeight()) { return nil } - consParams := ctx.ConsensusParams() // If the current block is the first EIP-1559 block, return the base fee @@ -54,18 +54,13 @@ func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int { return nil } - parentGasUsed, err := k.GetBlockGasWanted(ctx) - if err != nil { - return nil - } - - gasLimit := new(big.Int).SetUint64(math.MaxUint64) + parentGasUsed := k.GetBlockGasWanted(ctx) // NOTE: a MaxGas equal to -1 means that block gas is unlimited - if consParams.Block.MaxGas > -1 { - gasLimit = big.NewInt(consParams.Block.MaxGas) + if consParams.Block == nil || consParams.Block.MaxGas <= -1 { + panic(fmt.Sprintf("get invalid consensus params: %s", consParams)) } - + gasLimit := big.NewInt(consParams.Block.MaxGas) // CONTRACT: ElasticityMultiplier cannot be 0 as it's checked in the params // validation parentGasTargetBig := new(big.Int).Div(gasLimit, new(big.Int).SetUint64(uint64(params.ElasticityMultiplier))) diff --git a/x/feemarket/keeper/grpc_query.go b/x/feemarket/keeper/grpc_query.go index bdd9f3b849..ea97816648 100644 --- a/x/feemarket/keeper/grpc_query.go +++ b/x/feemarket/keeper/grpc_query.go @@ -54,10 +54,7 @@ func (k Keeper) BaseFee(c context.Context, _ *types.QueryBaseFeeRequest) (*types // BlockGas implements the Query/BlockGas gRPC method func (k Keeper) BlockGas(c context.Context, _ *types.QueryBlockGasRequest) (*types.QueryBlockGasResponse, error) { ctx := sdk.UnwrapSDKContext(c) - gas, err := k.GetBlockGasWanted(ctx) - if err != nil { - return nil, err - } + gas := k.GetBlockGasWanted(ctx) return &types.QueryBlockGasResponse{ Gas: int64(gas), //#nosec G115 diff --git a/x/feemarket/keeper/grpc_query_test.go b/x/feemarket/keeper/grpc_query_test.go index 2cbf65851f..b832b87ced 100644 --- a/x/feemarket/keeper/grpc_query_test.go +++ b/x/feemarket/keeper/grpc_query_test.go @@ -86,9 +86,7 @@ func (suite *KeeperTestSuite) TestQueryBlockGas() { }, } for _, tc := range testCases { - gas, err := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) - suite.Require().NoError(err) - + gas := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) exp := &types.QueryBlockGasResponse{Gas: int64(gas)} res, err := suite.queryClient.BlockGas(suite.ctx.Context(), &types.QueryBlockGasRequest{}) diff --git a/x/feemarket/keeper/integration_test.go b/x/feemarket/keeper/integration_test.go index 29a3c2ae00..8429b2001d 100644 --- a/x/feemarket/keeper/integration_test.go +++ b/x/feemarket/keeper/integration_test.go @@ -562,7 +562,7 @@ func buildEthTx( data, accesses, ) - msgEthereumTx.From = from.String() + msgEthereumTx.From = from.Bytes() return msgEthereumTx } @@ -579,7 +579,6 @@ func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereu err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv)) s.Require().NoError(err) - msgEthereumTx.From = "" err = txBuilder.SetMsgs(msgEthereumTx) s.Require().NoError(err) @@ -601,7 +600,7 @@ func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereu func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) *abci.ResponseCheckTx { bz := prepareEthTx(priv, msgEthereumTx) req := abci.RequestCheckTx{Tx: bz} - res, _ := s.app.BaseApp.CheckTx(&req) + res, _ := s.app.CheckTxSync(&req) return res } @@ -683,7 +682,7 @@ func prepareCosmosTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ... func checkTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) *abci.ResponseCheckTx { bz := prepareCosmosTx(priv, gasPrice, msgs...) req := abci.RequestCheckTx{Tx: bz} - res, _ := s.app.BaseApp.CheckTx(&req) + res, _ := s.app.CheckTxSync(&req) return res } diff --git a/x/feemarket/keeper/keeper.go b/x/feemarket/keeper/keeper.go index 7b5640613d..ec281a3222 100644 --- a/x/feemarket/keeper/keeper.go +++ b/x/feemarket/keeper/keeper.go @@ -20,7 +20,6 @@ import ( corestoretypes "cosmossdk.io/core/store" "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -37,7 +36,6 @@ type Keeper struct { cdc codec.BinaryCodec // Store key required for the Fee Market Prefix KVStore. storeService corestoretypes.KVStoreService - transientKey storetypes.StoreKey // the address capable of executing a MsgUpdateParams message. Typically, this should be the x/gov module account. authority sdk.AccAddress // Legacy subspace @@ -49,7 +47,6 @@ func NewKeeper( cdc codec.BinaryCodec, authority sdk.AccAddress, storeService corestoretypes.KVStoreService, - transientKey storetypes.StoreKey, ss paramstypes.Subspace, ) Keeper { // ensure authority account is correctly formatted @@ -61,7 +58,6 @@ func NewKeeper( cdc: cdc, storeService: storeService, authority: authority, - transientKey: transientKey, ss: ss, } } @@ -90,38 +86,14 @@ func (k Keeper) SetBlockGasWanted(ctx sdk.Context, gas uint64) error { } // GetBlockGasWanted returns the last block gas wanted value from the store. -func (k Keeper) GetBlockGasWanted(ctx sdk.Context) (uint64, error) { +func (k Keeper) GetBlockGasWanted(ctx sdk.Context) uint64 { store := k.storeService.OpenKVStore(ctx) - bz, err := store.Get(types.KeyPrefixBlockGasWanted) - if len(bz) == 0 { - return 0, err - } - - return sdk.BigEndianToUint64(bz), nil -} - -// GetTransientGasWanted returns the gas wanted in the current block from transient store. -func (k Keeper) GetTransientGasWanted(ctx sdk.Context) uint64 { - store := ctx.TransientStore(k.transientKey) - bz := store.Get(types.KeyPrefixTransientBlockGasWanted) + bz, _ := store.Get(types.KeyPrefixBlockGasWanted) if len(bz) == 0 { return 0 } - return sdk.BigEndianToUint64(bz) -} -// SetTransientBlockGasWanted sets the block gas wanted to the transient store. -func (k Keeper) SetTransientBlockGasWanted(ctx sdk.Context, gasWanted uint64) { - store := ctx.TransientStore(k.transientKey) - gasBz := sdk.Uint64ToBigEndian(gasWanted) - store.Set(types.KeyPrefixTransientBlockGasWanted, gasBz) -} - -// AddTransientGasWanted adds the cumulative gas wanted in the transient store -func (k Keeper) AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error) { - result := k.GetTransientGasWanted(ctx) + gasWanted - k.SetTransientBlockGasWanted(ctx, result) - return result, nil + return sdk.BigEndianToUint64(bz) } // GetBaseFeeV1 get the base fee from v1 version of states. diff --git a/x/feemarket/keeper/keeper_test.go b/x/feemarket/keeper/keeper_test.go index 3b05f1c623..f7ebd78d41 100644 --- a/x/feemarket/keeper/keeper_test.go +++ b/x/feemarket/keeper/keeper_test.go @@ -194,9 +194,8 @@ func (suite *KeeperTestSuite) TestSetGetBlockGasWanted() { for _, tc := range testCases { tc.malleate() - gas, err := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) + gas := suite.app.FeeMarketKeeper.GetBlockGasWanted(suite.ctx) suite.Require().Equal(tc.expGas, gas, tc.name) - suite.Require().NoError(err) } } diff --git a/x/feemarket/keeper/params.go b/x/feemarket/keeper/params.go index 4f1ce40670..e2c8735546 100644 --- a/x/feemarket/keeper/params.go +++ b/x/feemarket/keeper/params.go @@ -25,16 +25,15 @@ import ( ) // GetParams returns the total set of fee market parameters. -func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + var params types.Params store := k.storeService.OpenKVStore(ctx) bz, _ := store.Get(types.ParamsKey) if len(bz) == 0 { - var p types.Params - k.ss.GetParamSetIfExists(ctx, &p) - return p + k.ss.GetParamSetIfExists(ctx, ¶ms) + } else { + k.cdc.MustUnmarshal(bz, ¶ms) } - - k.cdc.MustUnmarshal(bz, ¶ms) return params } diff --git a/x/feemarket/types/keys.go b/x/feemarket/types/keys.go index 4b89ca3c7a..82b7514cbe 100644 --- a/x/feemarket/types/keys.go +++ b/x/feemarket/types/keys.go @@ -26,9 +26,8 @@ const ( // RouterKey uses module name for routing RouterKey = ModuleName - // TransientKey is the key to access the FeeMarket transient store, that is reset - // during the Commit phase. - TransientKey = "transient_" + ModuleName + // ObjectStoreKey is the key to access the Fee Market object store + ObjectStoreKey = "object:" + ModuleName ) // prefix bytes for the feemarket persistent store @@ -37,8 +36,9 @@ const ( deprecatedPrefixBaseFee // unused ) +// prefix bytes for the feemarket object store const ( - prefixTransientBlockGasUsed = iota + 1 + prefixObjectParams = iota + 1 ) // KVStore key prefixes @@ -46,7 +46,7 @@ var ( KeyPrefixBlockGasWanted = []byte{prefixBlockGasWanted} ) -// Transient Store key prefixes +// Object store key prefixes var ( - KeyPrefixTransientBlockGasWanted = []byte{prefixTransientBlockGasUsed} + KeyPrefixObjectParams = []byte{prefixObjectParams} )