diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 905b5ce629d..b2b86b863c2 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -141,11 +141,143 @@ func ReadFixedBytes(t Type, word []byte) (interface{}, error) { if t.T != FixedBytesTy { return nil, errors.New("abi: invalid type in call to make fixed byte array") } - // convert - array := reflect.New(t.GetType()).Elem() - reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) - return array.Interface(), nil + if t.Size < 1 || t.Size > 32 { + return nil, errors.New("abi: invalid size") + } + + switch t.Size { + case 1: + var arr [1]byte + copy(arr[:], word[:1]) + return arr, nil + case 2: + var arr [2]byte + copy(arr[:], word[:2]) + return arr, nil + case 3: + var arr [3]byte + copy(arr[:], word[:3]) + return arr, nil + case 4: + var arr [4]byte + copy(arr[:], word[:4]) + return arr, nil + case 5: + var arr [5]byte + copy(arr[:], word[:5]) + return arr, nil + case 6: + var arr [6]byte + copy(arr[:], word[:6]) + return arr, nil + case 7: + var arr [7]byte + copy(arr[:], word[:7]) + return arr, nil + case 8: + var arr [8]byte + copy(arr[:], word[:8]) + return arr, nil + case 9: + var arr [9]byte + copy(arr[:], word[:9]) + return arr, nil + case 10: + var arr [10]byte + copy(arr[:], word[:10]) + return arr, nil + case 11: + var arr [11]byte + copy(arr[:], word[:11]) + return arr, nil + case 12: + var arr [12]byte + copy(arr[:], word[:12]) + return arr, nil + case 13: + var arr [13]byte + copy(arr[:], word[:13]) + return arr, nil + case 14: + var arr [14]byte + copy(arr[:], word[:14]) + return arr, nil + case 15: + var arr [15]byte + copy(arr[:], word[:15]) + return arr, nil + case 16: + var arr [16]byte + copy(arr[:], word[:16]) + return arr, nil + case 17: + var arr [17]byte + copy(arr[:], word[:17]) + return arr, nil + case 18: + var arr [18]byte + copy(arr[:], word[:18]) + return arr, nil + case 19: + var arr [19]byte + copy(arr[:], word[:19]) + return arr, nil + case 20: + var arr [20]byte + copy(arr[:], word[:20]) + return arr, nil + case 21: + var arr [21]byte + copy(arr[:], word[:21]) + return arr, nil + case 22: + var arr [22]byte + copy(arr[:], word[:22]) + return arr, nil + case 23: + var arr [23]byte + copy(arr[:], word[:23]) + return arr, nil + case 24: + var arr [24]byte + copy(arr[:], word[:24]) + return arr, nil + case 25: + var arr [25]byte + copy(arr[:], word[:25]) + return arr, nil + case 26: + var arr [26]byte + copy(arr[:], word[:26]) + return arr, nil + case 27: + var arr [27]byte + copy(arr[:], word[:27]) + return arr, nil + case 28: + var arr [28]byte + copy(arr[:], word[:28]) + return arr, nil + case 29: + var arr [29]byte + copy(arr[:], word[:29]) + return arr, nil + case 30: + var arr [30]byte + copy(arr[:], word[:30]) + return arr, nil + case 31: + var arr [31]byte + copy(arr[:], word[:31]) + return arr, nil + case 32: + var arr [32]byte + copy(arr[:], word[:32]) + return arr, nil + default: + return nil, errors.New("unsupported size") + } } // forEachUnpack iteratively unpack elements. diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 90713c03ca2..d06619ed99f 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -1162,3 +1162,190 @@ func TestPackAndUnpackIncompatibleNumber(t *testing.T) { } } } + +func TestReadFixedBytes(t *testing.T) { + word := make([]byte, 33) + for i := range word { + word[i] = byte(i) + } + + tests := []struct { + name string + tType Type + word []byte + wantErr bool + }{ + {"size0", Type{T: FixedBytesTy, Size: 0}, word, true}, + {"size33", Type{T: FixedBytesTy, Size: 33}, word, true}, + } + for size := 1; size <= 32; size++ { + tests = append(tests, struct { + name string + tType Type + word []byte + wantErr bool + }{ + name: fmt.Sprintf("size_%d", size), + tType: Type{T: FixedBytesTy, Size: size}, + word: word, + wantErr: false, + }) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ReadFixedBytes(tt.tType, tt.word) + if tt.wantErr { + if err == nil { + t.Errorf("expected error, got nil") + } + return + } + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + switch arr := got.(type) { + case [1]byte: + if !bytes.Equal(arr[:], word[:1]) { + t.Errorf("data mismatch") + } + case [2]byte: + if !bytes.Equal(arr[:], word[:2]) { + t.Errorf("data mismatch") + } + case [3]byte: + if !bytes.Equal(arr[:], word[:3]) { + t.Errorf("data mismatch") + } + case [4]byte: + if !bytes.Equal(arr[:], word[:4]) { + t.Errorf("data mismatch") + } + case [5]byte: + if !bytes.Equal(arr[:], word[:5]) { + t.Errorf("data mismatch") + } + case [6]byte: + if !bytes.Equal(arr[:], word[:6]) { + t.Errorf("data mismatch") + } + case [7]byte: + if !bytes.Equal(arr[:], word[:7]) { + t.Errorf("data mismatch") + } + case [8]byte: + if !bytes.Equal(arr[:], word[:8]) { + t.Errorf("data mismatch") + } + case [9]byte: + if !bytes.Equal(arr[:], word[:9]) { + t.Errorf("data mismatch") + } + case [10]byte: + if !bytes.Equal(arr[:], word[:10]) { + t.Errorf("data mismatch") + } + case [11]byte: + if !bytes.Equal(arr[:], word[:11]) { + t.Errorf("data mismatch") + } + case [12]byte: + if !bytes.Equal(arr[:], word[:12]) { + t.Errorf("data mismatch") + } + case [13]byte: + if !bytes.Equal(arr[:], word[:13]) { + t.Errorf("data mismatch") + } + case [14]byte: + if !bytes.Equal(arr[:], word[:14]) { + t.Errorf("data mismatch") + } + case [15]byte: + if !bytes.Equal(arr[:], word[:15]) { + t.Errorf("data mismatch") + } + case [16]byte: + if !bytes.Equal(arr[:], word[:16]) { + t.Errorf("data mismatch") + } + case [17]byte: + if !bytes.Equal(arr[:], word[:17]) { + t.Errorf("data mismatch") + } + case [18]byte: + if !bytes.Equal(arr[:], word[:18]) { + t.Errorf("data mismatch") + } + case [19]byte: + if !bytes.Equal(arr[:], word[:19]) { + t.Errorf("data mismatch") + } + case [20]byte: + if !bytes.Equal(arr[:], word[:20]) { + t.Errorf("data mismatch") + } + case [21]byte: + if !bytes.Equal(arr[:], word[:21]) { + t.Errorf("data mismatch") + } + case [22]byte: + if !bytes.Equal(arr[:], word[:22]) { + t.Errorf("data mismatch") + } + case [23]byte: + if !bytes.Equal(arr[:], word[:23]) { + t.Errorf("data mismatch") + } + case [24]byte: + if !bytes.Equal(arr[:], word[:24]) { + t.Errorf("data mismatch") + } + case [25]byte: + if !bytes.Equal(arr[:], word[:25]) { + t.Errorf("data mismatch") + } + case [26]byte: + if !bytes.Equal(arr[:], word[:26]) { + t.Errorf("data mismatch") + } + case [27]byte: + if !bytes.Equal(arr[:], word[:27]) { + t.Errorf("data mismatch") + } + case [28]byte: + if !bytes.Equal(arr[:], word[:28]) { + t.Errorf("data mismatch") + } + case [29]byte: + if !bytes.Equal(arr[:], word[:29]) { + t.Errorf("data mismatch") + } + case [30]byte: + if !bytes.Equal(arr[:], word[:30]) { + t.Errorf("data mismatch") + } + case [31]byte: + if !bytes.Equal(arr[:], word[:31]) { + t.Errorf("data mismatch") + } + case [32]byte: + if !bytes.Equal(arr[:], word[:32]) { + t.Errorf("data mismatch") + } + default: + t.Errorf("unexpected type %T", got) + } + }) + } +} + +func BenchmarkReadFixedBytes(b *testing.B) { + t := Type{T: FixedBytesTy, Size: 32} + word := make([]byte, 32) + for i := 0; i < b.N; i++ { + _, _ = ReadFixedBytes(t, word) + } +}