From 1f37dda27267276ed38e9a356a8dc480c5ac72e6 Mon Sep 17 00:00:00 2001 From: Cedric Cordenier Date: Wed, 5 Jun 2024 11:24:30 +0100 Subject: [PATCH] [fix] Handle negative big ints correctly --- pkg/values/big_int.go | 5 +- pkg/values/big_int_test.go | 31 +++++++ pkg/values/pb/values.go | 7 +- pkg/values/pb/values.pb.go | 166 +++++++++++++++++++++++++++---------- pkg/values/pb/values.proto | 8 +- pkg/values/value.go | 13 ++- 6 files changed, 176 insertions(+), 54 deletions(-) diff --git a/pkg/values/big_int.go b/pkg/values/big_int.go index 9c8d6a3c7..6c48f03a6 100644 --- a/pkg/values/big_int.go +++ b/pkg/values/big_int.go @@ -16,7 +16,10 @@ func NewBigInt(b *big.Int) *BigInt { } func (b *BigInt) proto() *pb.Value { - return pb.NewBigIntValue(b.Underlying.Bytes()) + return pb.NewBigIntValue( + b.Underlying.Sign(), + b.Underlying.Bytes(), + ) } func (b *BigInt) Unwrap() (any, error) { diff --git a/pkg/values/big_int_test.go b/pkg/values/big_int_test.go index 180a11514..758837b80 100644 --- a/pkg/values/big_int_test.go +++ b/pkg/values/big_int_test.go @@ -31,3 +31,34 @@ func Test_BigIntUnwrapTo(t *testing.T) { err = v.UnwrapTo(&varStr) assert.ErrorContains(t, err, "cannot unwrap to value of type: *string") } + +func Test_BigInt(t *testing.T) { + testCases := []struct { + name string + bi *big.Int + }{ + { + name: "positive", + bi: big.NewInt(100), + }, + { + name: "0", + bi: big.NewInt(0), + }, + { + name: "negative", + bi: big.NewInt(-1), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + v := NewBigInt(tc.bi) + + vp := Proto(v) + got := FromProto(vp) + + assert.Equal(t, tc.bi, got.(*BigInt).Underlying) + }) + } +} diff --git a/pkg/values/pb/values.go b/pkg/values/pb/values.go index 98b62c644..fbd1cab25 100644 --- a/pkg/values/pb/values.go +++ b/pkg/values/pb/values.go @@ -64,10 +64,13 @@ func NewInt64Value(i int64) *Value { } } -func NewBigIntValue(bib []byte) *Value { +func NewBigIntValue(sign int, bib []byte) *Value { return &Value{ Value: &Value_BigintValue{ - BigintValue: bib, + BigintValue: &BigInt{ + AbsVal: bib, + Sign: int64(sign), + }, }, } } diff --git a/pkg/values/pb/values.pb.go b/pkg/values/pb/values.pb.go index 465fb5fcb..161e7e6ca 100644 --- a/pkg/values/pb/values.pb.go +++ b/pkg/values/pb/values.pb.go @@ -126,7 +126,7 @@ func (x *Value) GetInt64Value() int64 { return 0 } -func (x *Value) GetBigintValue() []byte { +func (x *Value) GetBigintValue() *BigInt { if x, ok := x.GetValue().(*Value_BigintValue); ok { return x.BigintValue } @@ -166,7 +166,7 @@ type Value_Int64Value struct { } type Value_BigintValue struct { - BigintValue []byte `protobuf:"bytes,8,opt,name=bigint_value,json=bigintValue,proto3,oneof"` + BigintValue *BigInt `protobuf:"bytes,9,opt,name=bigint_value,json=bigintValue,proto3,oneof"` } func (*Value_StringValue) isValue_Value() {} @@ -185,6 +185,61 @@ func (*Value_Int64Value) isValue_Value() {} func (*Value_BigintValue) isValue_Value() {} +type BigInt struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AbsVal []byte `protobuf:"bytes,1,opt,name=abs_val,json=absVal,proto3" json:"abs_val,omitempty"` + Sign int64 `protobuf:"varint,2,opt,name=sign,proto3" json:"sign,omitempty"` +} + +func (x *BigInt) Reset() { + *x = BigInt{} + if protoimpl.UnsafeEnabled { + mi := &file_values_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BigInt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BigInt) ProtoMessage() {} + +func (x *BigInt) ProtoReflect() protoreflect.Message { + mi := &file_values_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BigInt.ProtoReflect.Descriptor instead. +func (*BigInt) Descriptor() ([]byte, []int) { + return file_values_proto_rawDescGZIP(), []int{1} +} + +func (x *BigInt) GetAbsVal() []byte { + if x != nil { + return x.AbsVal + } + return nil +} + +func (x *BigInt) GetSign() int64 { + if x != nil { + return x.Sign + } + return 0 +} + type Map struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -196,7 +251,7 @@ type Map struct { func (x *Map) Reset() { *x = Map{} if protoimpl.UnsafeEnabled { - mi := &file_values_proto_msgTypes[1] + mi := &file_values_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -209,7 +264,7 @@ func (x *Map) String() string { func (*Map) ProtoMessage() {} func (x *Map) ProtoReflect() protoreflect.Message { - mi := &file_values_proto_msgTypes[1] + mi := &file_values_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -222,7 +277,7 @@ func (x *Map) ProtoReflect() protoreflect.Message { // Deprecated: Use Map.ProtoReflect.Descriptor instead. func (*Map) Descriptor() ([]byte, []int) { - return file_values_proto_rawDescGZIP(), []int{1} + return file_values_proto_rawDescGZIP(), []int{2} } func (x *Map) GetFields() map[string]*Value { @@ -243,7 +298,7 @@ type List struct { func (x *List) Reset() { *x = List{} if protoimpl.UnsafeEnabled { - mi := &file_values_proto_msgTypes[2] + mi := &file_values_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -256,7 +311,7 @@ func (x *List) String() string { func (*List) ProtoMessage() {} func (x *List) ProtoReflect() protoreflect.Message { - mi := &file_values_proto_msgTypes[2] + mi := &file_values_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -269,7 +324,7 @@ func (x *List) ProtoReflect() protoreflect.Message { // Deprecated: Use List.ProtoReflect.Descriptor instead. func (*List) Descriptor() ([]byte, []int) { - return file_values_proto_rawDescGZIP(), []int{2} + return file_values_proto_rawDescGZIP(), []int{3} } func (x *List) GetFields() []*Value { @@ -283,7 +338,7 @@ var File_values_proto protoreflect.FileDescriptor var file_values_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xc3, 0x02, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xd9, 0x02, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, @@ -300,26 +355,31 @@ var file_values_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, - 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, - 0x0a, 0x0c, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x80, 0x01, 0x0a, - 0x03, 0x4d, 0x61, 0x70, 0x12, 0x2f, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x4d, 0x61, - 0x70, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x48, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x2d, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x3c, - 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, - 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x33, + 0x0a, 0x0c, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x42, 0x69, + 0x67, 0x49, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x08, + 0x10, 0x09, 0x22, 0x35, 0x0a, 0x06, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, + 0x61, 0x62, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x61, + 0x62, 0x73, 0x56, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x22, 0x80, 0x01, 0x0a, 0x03, 0x4d, 0x61, + 0x70, 0x12, 0x2f, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x70, 0x2e, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x73, 0x1a, 0x48, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2d, 0x0a, 0x04, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x3c, 0x5a, 0x3a, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -334,24 +394,26 @@ func file_values_proto_rawDescGZIP() []byte { return file_values_proto_rawDescData } -var file_values_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_values_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_values_proto_goTypes = []interface{}{ - (*Value)(nil), // 0: values.Value - (*Map)(nil), // 1: values.Map - (*List)(nil), // 2: values.List - nil, // 3: values.Map.FieldsEntry + (*Value)(nil), // 0: values.Value + (*BigInt)(nil), // 1: values.BigInt + (*Map)(nil), // 2: values.Map + (*List)(nil), // 3: values.List + nil, // 4: values.Map.FieldsEntry } var file_values_proto_depIdxs = []int32{ - 1, // 0: values.Value.map_value:type_name -> values.Map - 2, // 1: values.Value.list_value:type_name -> values.List - 3, // 2: values.Map.fields:type_name -> values.Map.FieldsEntry - 0, // 3: values.List.fields:type_name -> values.Value - 0, // 4: values.Map.FieldsEntry.value:type_name -> values.Value - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 2, // 0: values.Value.map_value:type_name -> values.Map + 3, // 1: values.Value.list_value:type_name -> values.List + 1, // 2: values.Value.bigint_value:type_name -> values.BigInt + 4, // 3: values.Map.fields:type_name -> values.Map.FieldsEntry + 0, // 4: values.List.fields:type_name -> values.Value + 0, // 5: values.Map.FieldsEntry.value:type_name -> values.Value + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_values_proto_init() } @@ -373,7 +435,7 @@ func file_values_proto_init() { } } file_values_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Map); i { + switch v := v.(*BigInt); i { case 0: return &v.state case 1: @@ -385,6 +447,18 @@ func file_values_proto_init() { } } file_values_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Map); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_values_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*List); i { case 0: return &v.state @@ -413,7 +487,7 @@ func file_values_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_values_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/values/pb/values.proto b/pkg/values/pb/values.proto index 899d852a8..604715512 100644 --- a/pkg/values/pb/values.proto +++ b/pkg/values/pb/values.proto @@ -5,6 +5,7 @@ option go_package = "github.com/smartcontractkit/chainlink-common/pkg/values/pb" package values; message Value { + reserved 8; oneof value { string string_value = 1; bool bool_value = 2; @@ -13,10 +14,15 @@ message Value { List list_value = 5; string decimal_value = 6; int64 int64_value = 7; - bytes bigint_value = 8; + BigInt bigint_value = 9; } } +message BigInt { + bytes abs_val = 1; + int64 sign = 2; +} + message Map { map fields = 1; } diff --git a/pkg/values/value.go b/pkg/values/value.go index 3d3c8a27c..b037cd03c 100644 --- a/pkg/values/value.go +++ b/pkg/values/value.go @@ -174,10 +174,15 @@ func fromDecimalValueProto(decStr string) *Decimal { return NewDecimal(dec) } -func fromBigIntValueProto(b []byte) *BigInt { - i := big.Int{} - bi := i.SetBytes(b) - return NewBigInt(bi) +func fromBigIntValueProto(biv *pb.BigInt) *BigInt { + av := &big.Int{} + av = av.SetBytes(biv.AbsVal) + + if biv.Sign < 0 { + av.Neg(av) + } + + return NewBigInt(av) } func createMapFromStruct(v any) (Value, error) {