github.com/CommerciumBlockchain/go-commercium@v0.0.0-20220709212705-b46438a77516/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  	"bytes"
    21  	"fmt"
    22  	"math/rand"
    23  	"reflect"
    24  	"strings"
    25  
    26  	"github.com/CommerciumBlockchain/go-commercium/accounts/abi"
    27  	"github.com/CommerciumBlockchain/go-commercium/crypto"
    28  	fuzz "github.com/google/gofuzz"
    29  )
    30  
    31  func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byte) bool {
    32  	outptr := reflect.New(reflect.TypeOf(inputType))
    33  	if err := abi.UnpackIntoInterface(outptr.Interface(), method, input); err == nil {
    34  		output, err := abi.Pack(method, input)
    35  		if err != nil {
    36  			// We have some false positives as we can unpack these type successfully, but not pack them
    37  			if err.Error() == "abi: cannot use []uint8 as type [0]int8 as argument" ||
    38  				err.Error() == "abi: cannot use uint8 as type int8 as argument" {
    39  				return false
    40  			}
    41  			panic(err)
    42  		}
    43  		if !bytes.Equal(input, output[4:]) {
    44  			panic(fmt.Sprintf("unpackPack is not equal, \ninput : %x\noutput: %x", input, output[4:]))
    45  		}
    46  		return true
    47  	}
    48  	return false
    49  }
    50  
    51  func packUnpack(abi abi.ABI, method string, input []interface{}) bool {
    52  	if packed, err := abi.Pack(method, input); err == nil {
    53  		outptr := reflect.New(reflect.TypeOf(input))
    54  		err := abi.UnpackIntoInterface(outptr.Interface(), method, packed)
    55  		if err != nil {
    56  			panic(err)
    57  		}
    58  		out := outptr.Elem().Interface()
    59  		if !reflect.DeepEqual(input, out) {
    60  			panic(fmt.Sprintf("unpackPack is not equal, \ninput : %x\noutput: %x", input, out))
    61  		}
    62  		return true
    63  	}
    64  	return false
    65  }
    66  
    67  type args struct {
    68  	name string
    69  	typ  string
    70  }
    71  
    72  func createABI(name string, stateMutability, payable *string, inputs []args) (abi.ABI, error) {
    73  	sig := fmt.Sprintf(`[{ "type" : "function", "name" : "%v" `, name)
    74  	if stateMutability != nil {
    75  		sig += fmt.Sprintf(`, "stateMutability": "%v" `, *stateMutability)
    76  	}
    77  	if payable != nil {
    78  		sig += fmt.Sprintf(`, "payable": %v `, *payable)
    79  	}
    80  	if len(inputs) > 0 {
    81  		sig += `, "inputs" : [ {`
    82  		for i, inp := range inputs {
    83  			sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ)
    84  			if i+1 < len(inputs) {
    85  				sig += ","
    86  			}
    87  		}
    88  		sig += "} ]"
    89  		sig += `, "outputs" : [ {`
    90  		for i, inp := range inputs {
    91  			sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ)
    92  			if i+1 < len(inputs) {
    93  				sig += ","
    94  			}
    95  		}
    96  		sig += "} ]"
    97  	}
    98  	sig += `}]`
    99  
   100  	return abi.JSON(strings.NewReader(sig))
   101  }
   102  
   103  func fillStruct(structs []interface{}, data []byte) {
   104  	if structs != nil && len(data) != 0 {
   105  		fuzz.NewFromGoFuzz(data).Fuzz(&structs)
   106  	}
   107  }
   108  
   109  func createStructs(args []args) []interface{} {
   110  	structs := make([]interface{}, len(args))
   111  	for i, arg := range args {
   112  		t, err := abi.NewType(arg.typ, "", nil)
   113  		if err != nil {
   114  			panic(err)
   115  		}
   116  		structs[i] = reflect.New(t.GetType()).Elem()
   117  	}
   118  	return structs
   119  }
   120  
   121  func runFuzzer(input []byte) int {
   122  	good := false
   123  
   124  	names := []string{"_name", "name", "NAME", "name_", "__", "_name_", "n"}
   125  	stateMut := []string{"", "pure", "view", "payable"}
   126  	stateMutabilites := []*string{nil, &stateMut[0], &stateMut[1], &stateMut[2], &stateMut[3]}
   127  	pays := []string{"true", "false"}
   128  	payables := []*string{nil, &pays[0], &pays[1]}
   129  	varNames := []string{"a", "b", "c", "d", "e", "f", "g"}
   130  	varNames = append(varNames, names...)
   131  	varTypes := []string{"bool", "address", "bytes", "string",
   132  		"uint8", "int8", "uint8", "int8", "uint16", "int16",
   133  		"uint24", "int24", "uint32", "int32", "uint40", "int40", "uint48", "int48", "uint56", "int56",
   134  		"uint64", "int64", "uint72", "int72", "uint80", "int80", "uint88", "int88", "uint96", "int96",
   135  		"uint104", "int104", "uint112", "int112", "uint120", "int120", "uint128", "int128", "uint136", "int136",
   136  		"uint144", "int144", "uint152", "int152", "uint160", "int160", "uint168", "int168", "uint176", "int176",
   137  		"uint184", "int184", "uint192", "int192", "uint200", "int200", "uint208", "int208", "uint216", "int216",
   138  		"uint224", "int224", "uint232", "int232", "uint240", "int240", "uint248", "int248", "uint256", "int256",
   139  		"bytes1", "bytes2", "bytes3", "bytes4", "bytes5", "bytes6", "bytes7", "bytes8", "bytes9", "bytes10", "bytes11",
   140  		"bytes12", "bytes13", "bytes14", "bytes15", "bytes16", "bytes17", "bytes18", "bytes19", "bytes20", "bytes21",
   141  		"bytes22", "bytes23", "bytes24", "bytes25", "bytes26", "bytes27", "bytes28", "bytes29", "bytes30", "bytes31",
   142  		"bytes32", "bytes"}
   143  	rnd := rand.New(rand.NewSource(123456))
   144  	if len(input) > 0 {
   145  		kec := crypto.Keccak256(input)
   146  		rnd = rand.New(rand.NewSource(int64(kec[0])))
   147  	}
   148  	name := names[rnd.Intn(len(names))]
   149  	stateM := stateMutabilites[rnd.Intn(len(stateMutabilites))]
   150  	payable := payables[rnd.Intn(len(payables))]
   151  	maxLen := 5
   152  	for k := 1; k < maxLen; k++ {
   153  		var arg []args
   154  		for i := k; i > 0; i-- {
   155  			argName := varNames[i]
   156  			argTyp := varTypes[rnd.Int31n(int32(len(varTypes)))]
   157  			if rnd.Int31n(10) == 0 {
   158  				argTyp += "[]"
   159  			} else if rnd.Int31n(10) == 0 {
   160  				arrayArgs := rnd.Int31n(30) + 1
   161  				argTyp += fmt.Sprintf("[%d]", arrayArgs)
   162  			}
   163  			arg = append(arg, args{
   164  				name: argName,
   165  				typ:  argTyp,
   166  			})
   167  		}
   168  		abi, err := createABI(name, stateM, payable, arg)
   169  		if err != nil {
   170  			continue
   171  		}
   172  		structs := createStructs(arg)
   173  		b := unpackPack(abi, name, structs, input)
   174  		fillStruct(structs, input)
   175  		c := packUnpack(abi, name, structs)
   176  		good = good || b || c
   177  	}
   178  	if good {
   179  		return 1
   180  	}
   181  	return 0
   182  }
   183  
   184  func Fuzz(input []byte) int {
   185  	return runFuzzer(input)
   186  }