fuzzer.js
1 const utils = require('web3-utils'); 2 const u = require('../../utils/utils.js'); 3 4 // generates random inputs based on the inputs of an ABI 5 class ContractFuzzer { 6 constructor(embark) { 7 this.embark = embark; 8 this.logger = embark.logger; 9 this.events = embark.events; 10 } 11 12 // main function to call, takes in iteration number and a contract and returns a map object 13 // composed of method names -> fuzzed inputs. 14 generateFuzz(iterations, contract) { 15 const self = this; 16 let fuzzMap = {}; 17 contract.abiDefinition.filter((x) => x.inputs && x.inputs.length !== 0 && x.type !== "event").forEach((abiMethod) => { 18 let name = abiMethod.type === "constructor" ? "constructor" : abiMethod.name; 19 let inputTypes = abiMethod.inputs.map(input => input.type); 20 fuzzMap[name] = {}; 21 for (let i = 0; i < iterations; i++) { 22 fuzzMap[name][i] = inputTypes.map(input => this.getTypeFuzz(input)); 23 self.logger.trace(name); 24 self.logger.trace("iteration: " + i + "\n" + fuzzMap[name][i]); 25 } 26 }); 27 self.logger.trace('\n'); 28 return fuzzMap; 29 } 30 31 getTypeFuzz(typeString) { 32 const self = this; 33 // Group 0: uint256[3] 34 // Group 1: uint256 35 // Group 2: uint 36 // Group 3: 256 37 // Group 4: [3] 38 // Group 5: 3 39 let regexObj = typeString.match(/((bool|int|uint|bytes|string|address)([0-9]*)?)(\[([0-9]*)\])*$/); 40 let type = regexObj[1]; 41 let kind = regexObj[2]; 42 let size = regexObj[3]; 43 let array = regexObj[4]; 44 let arraySize = regexObj[5]; 45 switch(true) { 46 case array !== undefined: { 47 // if it's a dynamic array pick a number between 1 and 256 for length of array 48 let length = arraySize === undefined || arraySize === null || arraySize === '' ? Math.floor((Math.random() * 256) + 1) : arraySize; 49 return self.generateArrayOfType(length, type); 50 } 51 case kind === "bool": 52 return self.generateRandomBool(); 53 case kind === "uint" || kind === "int": 54 return self.generateRandomInt(size || 256); 55 case kind === "bytes": 56 return self.generateRandomStaticBytes(size || 32); 57 case kind === "string": 58 return self.generateRandomDynamicType(); 59 case kind === "address": 60 return self.generateRandomAddress(); 61 default: 62 throw new Error("Couldn't find proper ethereum abi type"); 63 } 64 } 65 66 generateRandomBool() { 67 return u.sample([true, false]); 68 } 69 70 generateArrayOfType(length, type) { 71 var arr = []; 72 for (var i = 0; i < length; i++) arr.push(this.getTypeFuzz(type)); 73 return arr; 74 } 75 76 generateRandomDynamicType() { 77 return Math.random().toString(36).slice(2); 78 } 79 80 generateRandomStaticBytes(size) { 81 return utils.randomHex(parseInt(size, 10)); 82 } 83 84 generateRandomInt(size) { 85 return utils.toBN(utils.randomHex(parseInt(size, 10) / 8)).toString(); 86 } 87 88 generateRandomAddress() { 89 return utils.randomHex(20); 90 } 91 } 92 93 module.exports = ContractFuzzer;