/ lib / modules / profiler / fuzzer.js
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;