accounts/abi: differentiate between static and dynamic arrays (#3121)
solves #3119 Signed-off-by: VoR0220 <rj@erisindustries.com>
This commit is contained in:
parent
ed2bc7fbe9
commit
2ad5dba50a
@ -98,28 +98,46 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
|||||||
case HashTy: // hash must be of slice hash
|
case HashTy: // hash must be of slice hash
|
||||||
refSlice = reflect.ValueOf([]common.Hash(nil))
|
refSlice = reflect.ValueOf([]common.Hash(nil))
|
||||||
case FixedBytesTy:
|
case FixedBytesTy:
|
||||||
refSlice = reflect.ValueOf([]byte(nil))
|
refSlice = reflect.ValueOf([][]byte(nil))
|
||||||
default: // no other types are supported
|
default: // no other types are supported
|
||||||
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
|
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
|
||||||
}
|
}
|
||||||
// get the offset which determines the start of this array ...
|
|
||||||
offset := int(common.BytesToBig(output[index : index+32]).Uint64())
|
var slice []byte
|
||||||
if offset+32 > len(output) {
|
var size int
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
var offset int
|
||||||
|
if t.Type.IsSlice {
|
||||||
|
|
||||||
|
// get the offset which determines the start of this array ...
|
||||||
|
offset = int(common.BytesToBig(output[index : index+32]).Uint64())
|
||||||
|
if offset+32 > len(output) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
||||||
|
}
|
||||||
|
|
||||||
|
slice = output[offset:]
|
||||||
|
// ... starting with the size of the array in elements ...
|
||||||
|
size = int(common.BytesToBig(slice[:32]).Uint64())
|
||||||
|
slice = slice[32:]
|
||||||
|
// ... and make sure that we've at the very least the amount of bytes
|
||||||
|
// available in the buffer.
|
||||||
|
if size*32 > len(slice) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reslice to match the required size
|
||||||
|
slice = slice[:(size * 32)]
|
||||||
|
} else if t.Type.IsArray {
|
||||||
|
//get the number of elements in the array
|
||||||
|
size = t.Type.SliceSize
|
||||||
|
|
||||||
|
//check to make sure array size matches up
|
||||||
|
if index+32*size > len(output) {
|
||||||
|
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size)
|
||||||
|
}
|
||||||
|
//slice is there for a fixed amount of times
|
||||||
|
slice = output[index : index+size*32]
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := output[offset:]
|
|
||||||
// ... starting with the size of the array in elements ...
|
|
||||||
size := int(common.BytesToBig(slice[:32]).Uint64())
|
|
||||||
slice = slice[32:]
|
|
||||||
// ... and make sure that we've at the very least the amount of bytes
|
|
||||||
// available in the buffer.
|
|
||||||
if size*32 > len(slice) {
|
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
|
|
||||||
}
|
|
||||||
|
|
||||||
// reslice to match the required size
|
|
||||||
slice = slice[:(size * 32)]
|
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
var (
|
var (
|
||||||
inter interface{} // interface type
|
inter interface{} // interface type
|
||||||
@ -136,6 +154,8 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
|||||||
inter = common.BytesToAddress(returnOutput)
|
inter = common.BytesToAddress(returnOutput)
|
||||||
case HashTy:
|
case HashTy:
|
||||||
inter = common.BytesToHash(returnOutput)
|
inter = common.BytesToHash(returnOutput)
|
||||||
|
case FixedBytesTy:
|
||||||
|
inter = returnOutput
|
||||||
}
|
}
|
||||||
// append the item to our reflect slice
|
// append the item to our reflect slice
|
||||||
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
|
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
|
||||||
|
@ -357,8 +357,6 @@ func TestMethodPack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sig := abi.Methods["slice"].Id()
|
sig := abi.Methods["slice"].Id()
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
|
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||||
|
|
||||||
@ -406,8 +404,6 @@ func TestMethodPack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sig = abi.Methods["slice256"].Id()
|
sig = abi.Methods["slice256"].Id()
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
|
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||||
|
|
||||||
@ -931,6 +927,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
|
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
|
||||||
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
|
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
|
||||||
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
|
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
|
||||||
|
{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
|
||||||
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
|
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
|
||||||
{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] },
|
{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] },
|
||||||
{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]`
|
{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]`
|
||||||
@ -1083,6 +1080,26 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
t.Errorf("expected %x, got %x", fixed, out[1])
|
t.Errorf("expected %x, got %x", fixed, out[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buff.Reset()
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"))
|
||||||
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
|
||||||
|
// marshal int array
|
||||||
|
var intArray [3]*big.Int
|
||||||
|
err = abi.Unpack(&intArray, "intArraySingle", buff.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
var testAgainstIntArray [3]*big.Int
|
||||||
|
testAgainstIntArray[0] = big.NewInt(1)
|
||||||
|
testAgainstIntArray[1] = big.NewInt(2)
|
||||||
|
testAgainstIntArray[2] = big.NewInt(3)
|
||||||
|
|
||||||
|
for i, Int := range intArray {
|
||||||
|
if Int.Cmp(testAgainstIntArray[i]) != 0 {
|
||||||
|
t.Errorf("expected %v, got %v", testAgainstIntArray[i], Int)
|
||||||
|
}
|
||||||
|
}
|
||||||
// marshal address slice
|
// marshal address slice
|
||||||
buff.Reset()
|
buff.Reset()
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset
|
||||||
|
@ -78,10 +78,6 @@ func set(dst, src reflect.Value, output Argument) error {
|
|||||||
case dstType.AssignableTo(src.Type()):
|
case dstType.AssignableTo(src.Type()):
|
||||||
dst.Set(src)
|
dst.Set(src)
|
||||||
case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice:
|
case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice:
|
||||||
if !dstType.Elem().AssignableTo(r_byte) {
|
|
||||||
return fmt.Errorf("abi: cannot unmarshal %v in to array of elem %v", src.Type(), dstType.Elem())
|
|
||||||
}
|
|
||||||
|
|
||||||
if dst.Len() < output.Type.SliceSize {
|
if dst.Len() < output.Type.SliceSize {
|
||||||
return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
|
return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
|
|||||||
|
|
||||||
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy {
|
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy {
|
||||||
var packed []byte
|
var packed []byte
|
||||||
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
val, err := t.Elem.pack(v.Index(i))
|
val, err := t.Elem.pack(v.Index(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -177,7 +178,11 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
packed = append(packed, val...)
|
packed = append(packed, val...)
|
||||||
}
|
}
|
||||||
return packBytesSlice(packed, v.Len()), nil
|
if t.IsSlice {
|
||||||
|
return packBytesSlice(packed, v.Len()), nil
|
||||||
|
} else if t.IsArray {
|
||||||
|
return packed, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return packElement(t, v), nil
|
return packElement(t, v), nil
|
||||||
@ -186,5 +191,5 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
|
|||||||
// requireLengthPrefix returns whether the type requires any sort of length
|
// requireLengthPrefix returns whether the type requires any sort of length
|
||||||
// prefixing.
|
// prefixing.
|
||||||
func (t Type) requiresLengthPrefix() bool {
|
func (t Type) requiresLengthPrefix() bool {
|
||||||
return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice || t.IsArray)
|
return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user