accounts/abi: fix unpacking of negative int256 (#17583)
This commit is contained in:
		@@ -25,8 +25,17 @@ import (
 | 
				
			|||||||
	"github.com/ethereum/go-ethereum/common"
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						maxUint256 = big.NewInt(0).Add(
 | 
				
			||||||
 | 
							big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil),
 | 
				
			||||||
 | 
							big.NewInt(-1))
 | 
				
			||||||
 | 
						maxInt256 = big.NewInt(0).Add(
 | 
				
			||||||
 | 
							big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
 | 
				
			||||||
 | 
							big.NewInt(-1))
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// reads the integer based on its kind
 | 
					// reads the integer based on its kind
 | 
				
			||||||
func readInteger(kind reflect.Kind, b []byte) interface{} {
 | 
					func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
 | 
				
			||||||
	switch kind {
 | 
						switch kind {
 | 
				
			||||||
	case reflect.Uint8:
 | 
						case reflect.Uint8:
 | 
				
			||||||
		return b[len(b)-1]
 | 
							return b[len(b)-1]
 | 
				
			||||||
@@ -45,7 +54,20 @@ func readInteger(kind reflect.Kind, b []byte) interface{} {
 | 
				
			|||||||
	case reflect.Int64:
 | 
						case reflect.Int64:
 | 
				
			||||||
		return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
 | 
							return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return new(big.Int).SetBytes(b)
 | 
							// the only case lefts for integer is int256/uint256.
 | 
				
			||||||
 | 
							// big.SetBytes can't tell if a number is negative, positive on itself.
 | 
				
			||||||
 | 
							// On EVM, if the returned number > max int256, it is negative.
 | 
				
			||||||
 | 
							ret := new(big.Int).SetBytes(b)
 | 
				
			||||||
 | 
							if typ == UintTy {
 | 
				
			||||||
 | 
								return ret
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ret.Cmp(maxInt256) > 0 {
 | 
				
			||||||
 | 
								ret.Add(maxUint256, big.NewInt(0).Neg(ret))
 | 
				
			||||||
 | 
								ret.Add(ret, big.NewInt(1))
 | 
				
			||||||
 | 
								ret.Neg(ret)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ret
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -179,7 +201,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
 | 
				
			|||||||
	case StringTy: // variable arrays are written at the end of the return bytes
 | 
						case StringTy: // variable arrays are written at the end of the return bytes
 | 
				
			||||||
		return string(output[begin : begin+end]), nil
 | 
							return string(output[begin : begin+end]), nil
 | 
				
			||||||
	case IntTy, UintTy:
 | 
						case IntTy, UintTy:
 | 
				
			||||||
		return readInteger(t.Kind, returnOutput), nil
 | 
							return readInteger(t.T, t.Kind, returnOutput), nil
 | 
				
			||||||
	case BoolTy:
 | 
						case BoolTy:
 | 
				
			||||||
		return readBool(returnOutput)
 | 
							return readBool(returnOutput)
 | 
				
			||||||
	case AddressTy:
 | 
						case AddressTy:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,6 +117,11 @@ var unpackTests = []unpackTest{
 | 
				
			|||||||
		enc:  "0000000000000000000000000000000000000000000000000000000000000001",
 | 
							enc:  "0000000000000000000000000000000000000000000000000000000000000001",
 | 
				
			||||||
		want: big.NewInt(1),
 | 
							want: big.NewInt(1),
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							def:  `[{"type": "int256"}]`,
 | 
				
			||||||
 | 
							enc:  "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
 | 
				
			||||||
 | 
							want: big.NewInt(-1),
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		def:  `[{"type": "address"}]`,
 | 
							def:  `[{"type": "address"}]`,
 | 
				
			||||||
		enc:  "0000000000000000000000000100000000000000000000000000000000000000",
 | 
							enc:  "0000000000000000000000000100000000000000000000000000000000000000",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user