Skip to content

Commit 39f1d90

Browse files
tbocekkaralabe
authored andcommitted
[release/1.4.7] accounts/abi: Negative numbers not properly converted in ABI encoding
When converting a negative number e.g., -2, the resulting ABI encoding should look as follows: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe. However, since the check of the type is for an uint instead of an int, it results in the following ABI encoding: 0101010101010101010101010101010101010101010101010101010101010102. The Ethereum ABI (https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) says, that signed integers are stored in two's complement which should be of the form ffffff.... and not 01010101..... for e.g. -1. Thus, I removed the type check in numbers.go as well as the function S256 as I don't think they are correct. Or maybe I'm missing something? (cherry picked from commit 89c6c5b)
1 parent 71b577f commit 39f1d90

File tree

4 files changed

+10
-64
lines changed

4 files changed

+10
-64
lines changed

accounts/abi/method.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (m Method) pack(method Method, args ...interface{}) ([]byte, error) {
6262
// calculate the offset
6363
offset := len(method.Inputs)*32 + len(variableInput)
6464
// set the offset
65-
ret = append(ret, packNum(reflect.ValueOf(offset), UintTy)...)
65+
ret = append(ret, packNum(reflect.ValueOf(offset))...)
6666
// Append the packed output to the variable input. The variable input
6767
// will be appended at the end of the input.
6868
variableInput = append(variableInput, packed...)

accounts/abi/numbers.go

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -61,54 +61,20 @@ func U256(n *big.Int) []byte {
6161
return common.LeftPadBytes(common.U256(n).Bytes(), 32)
6262
}
6363

64-
func S256(n *big.Int) []byte {
65-
sint := common.S256(n)
66-
ret := common.LeftPadBytes(sint.Bytes(), 32)
67-
if sint.Cmp(common.Big0) < 0 {
68-
for i, b := range ret {
69-
if b == 0 {
70-
ret[i] = 1
71-
continue
72-
}
73-
break
74-
}
75-
}
76-
77-
return ret
78-
}
79-
8064
// S256 will ensure signed 256bit on big nums
8165
func U2U256(n uint64) []byte {
8266
return U256(big.NewInt(int64(n)))
8367
}
8468

85-
func S2S256(n int64) []byte {
86-
return S256(big.NewInt(n))
87-
}
88-
8969
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
90-
func packNum(value reflect.Value, to byte) []byte {
70+
func packNum(value reflect.Value) []byte {
9171
switch kind := value.Kind(); kind {
9272
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
93-
if to == UintTy {
94-
return U2U256(value.Uint())
95-
} else {
96-
return S2S256(int64(value.Uint()))
97-
}
73+
return U2U256(value.Uint())
9874
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
99-
if to == UintTy {
100-
return U2U256(uint64(value.Int()))
101-
} else {
102-
return S2S256(value.Int())
103-
}
75+
return U2U256(uint64(value.Int()))
10476
case reflect.Ptr:
105-
// This only takes care of packing and casting. No type checking is done here. It should be done prior to using this function.
106-
if to == UintTy {
107-
return U256(value.Interface().(*big.Int))
108-
} else {
109-
return S256(value.Interface().(*big.Int))
110-
}
111-
77+
return U256(value.Interface().(*big.Int))
11278
}
11379

11480
return nil

accounts/abi/numbers_test.go

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,48 +26,28 @@ import (
2626
func TestNumberTypes(t *testing.T) {
2727
ubytes := make([]byte, 32)
2828
ubytes[31] = 1
29-
sbytesmin := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
3029

3130
unsigned := U256(big.NewInt(1))
3231
if !bytes.Equal(unsigned, ubytes) {
3332
t.Errorf("expected %x got %x", ubytes, unsigned)
3433
}
35-
36-
signed := S256(big.NewInt(1))
37-
if !bytes.Equal(signed, ubytes) {
38-
t.Errorf("expected %x got %x", ubytes, unsigned)
39-
}
40-
41-
signed = S256(big.NewInt(-1))
42-
if !bytes.Equal(signed, sbytesmin) {
43-
t.Errorf("expected %x got %x", ubytes, unsigned)
44-
}
4534
}
4635

4736
func TestPackNumber(t *testing.T) {
4837
ubytes := make([]byte, 32)
4938
ubytes[31] = 1
50-
sbytesmin := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
5139
maxunsigned := []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
5240

53-
packed := packNum(reflect.ValueOf(1), IntTy)
54-
if !bytes.Equal(packed, ubytes) {
55-
t.Errorf("expected %x got %x", ubytes, packed)
56-
}
57-
packed = packNum(reflect.ValueOf(-1), IntTy)
58-
if !bytes.Equal(packed, sbytesmin) {
59-
t.Errorf("expected %x got %x", ubytes, packed)
60-
}
61-
packed = packNum(reflect.ValueOf(1), UintTy)
41+
packed := packNum(reflect.ValueOf(1))
6242
if !bytes.Equal(packed, ubytes) {
6343
t.Errorf("expected %x got %x", ubytes, packed)
6444
}
65-
packed = packNum(reflect.ValueOf(-1), UintTy)
45+
packed = packNum(reflect.ValueOf(-1))
6646
if !bytes.Equal(packed, maxunsigned) {
6747
t.Errorf("expected %x got %x", maxunsigned, packed)
6848
}
6949

70-
packed = packNum(reflect.ValueOf("string"), UintTy)
50+
packed = packNum(reflect.ValueOf("string"))
7151
if packed != nil {
7252
t.Errorf("expected 'string' to pack to nil. got %x instead", packed)
7353
}

accounts/abi/packing.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
2626
// bytes slice
2727
func packBytesSlice(bytes []byte, l int) []byte {
28-
len := packNum(reflect.ValueOf(l), UintTy)
28+
len := packNum(reflect.ValueOf(l))
2929
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
3030
}
3131

@@ -34,7 +34,7 @@ func packBytesSlice(bytes []byte, l int) []byte {
3434
func packElement(t Type, reflectValue reflect.Value) []byte {
3535
switch t.T {
3636
case IntTy, UintTy:
37-
return packNum(reflectValue, t.T)
37+
return packNum(reflectValue)
3838
case StringTy:
3939
return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len())
4040
case AddressTy:

0 commit comments

Comments
 (0)