github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/tests/fuzzers/abi/abifuzzer.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 24 fuzz "github.com/google/gofuzz" 25 26 "github.com/scroll-tech/go-ethereum/accounts/abi" 27 ) 28 29 var ( 30 names = []string{"_name", "name", "NAME", "name_", "__", "_name_", "n"} 31 stateMut = []string{"", "pure", "view", "payable"} 32 stateMutabilites = []*string{&stateMut[0], &stateMut[1], &stateMut[2], &stateMut[3]} 33 pays = []string{"", "true", "false"} 34 payables = []*string{&pays[0], &pays[1]} 35 vNames = []string{"a", "b", "c", "d", "e", "f", "g"} 36 varNames = append(vNames, names...) 37 varTypes = []string{"bool", "address", "bytes", "string", 38 "uint8", "int8", "uint8", "int8", "uint16", "int16", 39 "uint24", "int24", "uint32", "int32", "uint40", "int40", "uint48", "int48", "uint56", "int56", 40 "uint64", "int64", "uint72", "int72", "uint80", "int80", "uint88", "int88", "uint96", "int96", 41 "uint104", "int104", "uint112", "int112", "uint120", "int120", "uint128", "int128", "uint136", "int136", 42 "uint144", "int144", "uint152", "int152", "uint160", "int160", "uint168", "int168", "uint176", "int176", 43 "uint184", "int184", "uint192", "int192", "uint200", "int200", "uint208", "int208", "uint216", "int216", 44 "uint224", "int224", "uint232", "int232", "uint240", "int240", "uint248", "int248", "uint256", "int256", 45 "bytes1", "bytes2", "bytes3", "bytes4", "bytes5", "bytes6", "bytes7", "bytes8", "bytes9", "bytes10", "bytes11", 46 "bytes12", "bytes13", "bytes14", "bytes15", "bytes16", "bytes17", "bytes18", "bytes19", "bytes20", "bytes21", 47 "bytes22", "bytes23", "bytes24", "bytes25", "bytes26", "bytes27", "bytes28", "bytes29", "bytes30", "bytes31", 48 "bytes32", "bytes"} 49 ) 50 51 func unpackPack(abi abi.ABI, method string, input []byte) ([]interface{}, bool) { 52 if out, err := abi.Unpack(method, input); err == nil { 53 _, err := abi.Pack(method, out...) 54 if err != nil { 55 // We have some false positives as we can unpack these type successfully, but not pack them 56 if err.Error() == "abi: cannot use []uint8 as type [0]int8 as argument" || 57 err.Error() == "abi: cannot use uint8 as type int8 as argument" { 58 return out, false 59 } 60 panic(err) 61 } 62 return out, true 63 } 64 return nil, false 65 } 66 67 func packUnpack(abi abi.ABI, method string, input *[]interface{}) bool { 68 if packed, err := abi.Pack(method, input); err == nil { 69 outptr := reflect.New(reflect.TypeOf(input)) 70 err := abi.UnpackIntoInterface(outptr.Interface(), method, packed) 71 if err != nil { 72 panic(err) 73 } 74 out := outptr.Elem().Interface() 75 if !reflect.DeepEqual(input, out) { 76 panic(fmt.Sprintf("unpackPack is not equal, \ninput : %x\noutput: %x", input, out)) 77 } 78 return true 79 } 80 return false 81 } 82 83 type args struct { 84 name string 85 typ string 86 } 87 88 func createABI(name string, stateMutability, payable *string, inputs []args) (abi.ABI, error) { 89 sig := fmt.Sprintf(`[{ "type" : "function", "name" : "%v" `, name) 90 if stateMutability != nil { 91 sig += fmt.Sprintf(`, "stateMutability": "%v" `, *stateMutability) 92 } 93 if payable != nil { 94 sig += fmt.Sprintf(`, "payable": %v `, *payable) 95 } 96 if len(inputs) > 0 { 97 sig += `, "inputs" : [ {` 98 for i, inp := range inputs { 99 sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ) 100 if i+1 < len(inputs) { 101 sig += "," 102 } 103 } 104 sig += "} ]" 105 sig += `, "outputs" : [ {` 106 for i, inp := range inputs { 107 sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ) 108 if i+1 < len(inputs) { 109 sig += "," 110 } 111 } 112 sig += "} ]" 113 } 114 sig += `}]` 115 116 return abi.JSON(strings.NewReader(sig)) 117 } 118 119 func runFuzzer(input []byte) int { 120 good := false 121 fuzzer := fuzz.NewFromGoFuzz(input) 122 123 name := names[getUInt(fuzzer)%len(names)] 124 stateM := stateMutabilites[getUInt(fuzzer)%len(stateMutabilites)] 125 payable := payables[getUInt(fuzzer)%len(payables)] 126 maxLen := 5 127 for k := 1; k < maxLen; k++ { 128 var arg []args 129 for i := k; i > 0; i-- { 130 argName := varNames[i] 131 argTyp := varTypes[getUInt(fuzzer)%len(varTypes)] 132 if getUInt(fuzzer)%10 == 0 { 133 argTyp += "[]" 134 } else if getUInt(fuzzer)%10 == 0 { 135 arrayArgs := getUInt(fuzzer)%30 + 1 136 argTyp += fmt.Sprintf("[%d]", arrayArgs) 137 } 138 arg = append(arg, args{ 139 name: argName, 140 typ: argTyp, 141 }) 142 } 143 abi, err := createABI(name, stateM, payable, arg) 144 if err != nil { 145 continue 146 } 147 structs, b := unpackPack(abi, name, input) 148 c := packUnpack(abi, name, &structs) 149 good = good || b || c 150 } 151 if good { 152 return 1 153 } 154 return 0 155 } 156 157 func Fuzz(input []byte) int { 158 return runFuzzer(input) 159 } 160 161 func getUInt(fuzzer *fuzz.Fuzzer) int { 162 var i int 163 fuzzer.Fuzz(&i) 164 if i < 0 { 165 i = -i 166 if i < 0 { 167 return 0 168 } 169 } 170 return i 171 }