Fabcoin Core  0.16.2
P2P Digital Currency
fuzzHelper.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU 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  cpp-ethereum 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 General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include <chrono>
23 #include <boost/random.hpp>
24 #include <boost/filesystem/path.hpp>
25 #include <libevmcore/Instruction.h>
28 
29 namespace dev
30 {
31 namespace test
32 {
33 
34 boost::random::mt19937 RandomCode::gen;
39 
44 
45 int RandomCode::recursiveRLP(std::string& _result, int _depth, std::string& _debug)
46 {
47  bool genValidRlp = true;
48  int bugProbability = randUniIntGen() % 100;
49  if (bugProbability < 80)
50  genValidRlp = false;
51 
52  if (_depth > 1)
53  {
54  //create rlp blocks
55  int size = 1 + randUniIntGen() % 4;
56  for (auto i = 0; i < size; i++)
57  {
58  std::string blockstr;
59  std::string blockDebug;
60  recursiveRLP(blockstr, _depth - 1, blockDebug);
61  _result += blockstr;
62  _debug += blockDebug;
63  }
64 
65  //make rlp header
66  int length = _result.size() / 2;
67  std::string header;
68  int rtype = 0;
69  int rnd = randUniIntGen() % 100;
70  if (rnd < 10)
71  {
72  //make header as array
73  if (length <= 55)
74  {
75  header = toCompactHex(128 + length);
76  rtype = 1;
77  }
78  else
79  {
80  std::string hexlength = toCompactHex(length);
81  header = toCompactHex(183 + hexlength.size() / 2) + hexlength;
82  rtype = 2;
83  }
84  }
85  else
86  {
87  //make header as list
88  if (length <= 55)
89  {
90  header = toCompactHex(192 + length);
91  rtype = 3;
92  }
93  else
94  {
95  std::string hexlength = toCompactHex(length, HexPrefix::DontAdd, 1);
96  header = toCompactHex(247 + hexlength.size() / 2) + hexlength;
97  rtype = 4;
98  }
99  }
100  _result = header + _result;
101  _debug = "[" + header + "(" + toString(length) + "){" + toString(rtype) + "}]" + _debug;
102  return _result.size() / 2;
103  }
104  if (_depth == 1)
105  {
106  bool genbug = false;
107  bool genbug2 = false;
108  int bugProbability = randUniIntGen() % 100;
109  if (bugProbability < 50 && !genValidRlp)
110  genbug = true;
111  bugProbability = randUniIntGen() % 100; //more randomness
112  if (bugProbability < 50 && !genValidRlp)
113  genbug2 = true;
114 
115  std::string emptyZeros = genValidRlp ? "" : genbug ? "00" : "";
116  std::string emptyZeros2 = genValidRlp ? "" : genbug2 ? "00" : "";
117 
118  int rnd = randUniIntGen() % 5;
119  switch (rnd)
120  {
121  case 0:
122  {
123  //single byte [0x00, 0x7f]
124  std::string rlp = emptyZeros + toCompactHex(genbug ? randUniIntGen() % 255 : randUniIntGen() % 128, HexPrefix::DontAdd, 1);
125  _result.insert(0, rlp);
126  _debug.insert(0, "[" + rlp + "]");
127  return 1;
128  }
129  case 1:
130  {
131  //string 0-55 [0x80, 0xb7] + string
132  int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
133  std::string hex = rndByteSequence(len);
134  if (len == 1)
135  if (genValidRlp && fromHex(hex)[0] < 128)
136  hex = toCompactHex((u64)128);
137 
138  _result.insert(0, toCompactHex(128 + len) + emptyZeros + hex);
139  _debug.insert(0, "[" + toCompactHex(128 + len) + "(" + toString(len) + ")]" + emptyZeros + hex);
140  return len + 1;
141  }
142  case 2:
143  {
144  //string more 55 [0xb8, 0xbf] + length + string
145  int len = randUniIntGen() % 100;
146  if (len < 56 && genValidRlp)
147  len = 56;
148 
149  std::string hex = rndByteSequence(len);
150  std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
151  std::string rlpblock = toCompactHex(183 + hexlen.size() / 2) + hexlen + emptyZeros + hex;
152  _debug.insert(0, "[" + toCompactHex(183 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){2}]" + emptyZeros + hex);
153  _result.insert(0, rlpblock);
154  return rlpblock.size() / 2;
155  }
156  case 3:
157  {
158  //list 0-55 [0xc0, 0xf7] + data
159  int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
160  std::string hex = emptyZeros + rndByteSequence(len);
161  _result.insert(0, toCompactHex(192 + len) + hex);
162  _debug.insert(0, "[" + toCompactHex(192 + len) + "(" + toString(len) + "){3}]" + hex);
163  return len + 1;
164  }
165  case 4:
166  {
167  //list more 55 [0xf8, 0xff] + length + data
168  int len = randUniIntGen() % 100;
169  if (len < 56 && genValidRlp)
170  len = 56;
171  std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
172  std::string rlpblock = toCompactHex(247 + hexlen.size() / 2) + hexlen + emptyZeros + rndByteSequence(len);
173  _debug.insert(0, "[" + toCompactHex(247 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){4}]" + emptyZeros + rndByteSequence(len));
174  _result.insert(0, rlpblock);
175  return rlpblock.size() / 2;
176  }
177  }
178  }
179  return 0;
180 }
181 
182 std::string RandomCode::rndRLPSequence(int _depth, std::string& _debug)
183 {
184  refreshSeed();
185  std::string hash;
186  _depth = std::min(std::max(1, _depth), 7); //limit depth to avoid overkill
187  recursiveRLP(hash, _depth, _debug);
188  return hash;
189 }
190 
191 std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
192 {
193  refreshSeed();
194  std::string hash = "";
195  _length = (_sizeType == SizeStrictness::Strict) ? std::max(0, _length) : (int)randomUniInt() % _length;
196  for (auto i = 0; i < _length; i++)
197  {
198  uint8_t byte = randOpCodeGen();
199  hash += toCompactHex(byte, HexPrefix::DontAdd, 1);
200  }
201  return hash;
202 }
203 
204 //generate smart random code
205 std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
206 {
207  refreshSeed();
208  std::string code;
209 
210  //random opCode amount
211  boostIntDistrib sizeDist (0, _maxOpNumber);
212  boostIntGenerator rndSizeGen(gen, sizeDist);
213  int size = (int)rndSizeGen();
214 
215  boostWeightGenerator randOpCodeWeight (gen, _options.opCodeProbability);
216  bool weightsDefined = _options.opCodeProbability.probabilities().size() == 255;
217 
218  for (auto i = 0; i < size; i++)
219  {
220  uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen();
222 
223  if (info.name.find("INVALID_INSTRUCTION") != std::string::npos)
224  {
225  //Byte code is yet not implemented
226  if (_options.useUndefinedOpCodes == false)
227  {
228  i--;
229  continue;
230  }
231  }
232  else
233  {
234  if (info.name.find("PUSH") != std::string::npos)
235  code += toCompactHex(opcode);
236  code += fillArguments((dev::eth::Instruction) opcode, _options);
237  }
238 
239  if (info.name.find("PUSH") == std::string::npos)
240  {
241  std::string byte = toCompactHex(opcode);
242  code += (byte == "") ? "00" : byte;
243  }
244  }
245  return code;
246 }
247 
248 std::string RandomCode::randomUniIntHex(u256 _maxVal)
249 {
250  if (_maxVal == 0)
252  refreshSeed();
253  int rand = randUniIntGen() % 100;
254  if (rand < 50)
255  return "0x" + toCompactHex((u256)randUniIntGen() % _maxVal);
256  return "0x" + toCompactHex((u256)randUInt64Gen() % _maxVal);
257 }
258 
260 {
261  if (_maxVal == 0)
263  refreshSeed();
264  return (u256)randUInt64Gen() % _maxVal;
265 }
266 
268 {
269  auto now = std::chrono::steady_clock::now().time_since_epoch();
270  auto timeSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
271  gen.seed(static_cast<unsigned int>(timeSinceEpoch));
272 }
273 
274 std::string RandomCode::getPushCode(std::string const& _hex)
275 {
276  int length = _hex.length() / 2;
277  int pushCode = 96 + length - 1;
278  return toCompactHex(pushCode) + _hex;
279 }
280 
281 std::string RandomCode::getPushCode(int _value)
282 {
283  std::string hexString = toCompactHex(_value);
284  return getPushCode(hexString);
285 }
286 
288 {
290 
291  std::string code;
292  bool smart = false;
293  unsigned num = info.args;
294  int rand = randUniIntGen() % 100;
295  if (rand < _options.smartCodeProbability)
296  smart = true;
297 
298  if (smart)
299  {
300  //PUSH1 ... PUSH32
301  if (dev::eth::Instruction::PUSH1 <= _opcode && _opcode <= dev::eth::Instruction::PUSH32)
302  {
303  code += rndByteSequence(int(_opcode) - int(dev::eth::Instruction::PUSH1) + 1);
304  return code;
305  }
306 
307  //SWAP1 ... SWAP16 || DUP1 ... DUP16
308  bool isSWAP = (dev::eth::Instruction::SWAP1 <= _opcode && _opcode <= dev::eth::Instruction::SWAP16);
309  bool isDUP = (dev::eth::Instruction::DUP1 <= _opcode && _opcode <= dev::eth::Instruction::DUP16);
310 
311  if (isSWAP || isDUP)
312  {
313  int times = 0;
314  if (isSWAP)
315  times = int(_opcode) - int(dev::eth::Instruction::SWAP1) + 2;
316  else
317  if (isDUP)
318  times = int(_opcode) - int(dev::eth::Instruction::DUP1) + 1;
319 
320  for (int i = 0; i < times; i ++)
321  code += getPushCode(randUniIntGen() % 32);
322 
323  return code;
324  }
325 
326  switch (_opcode)
327  {
329  //(CREATE value mem1 mem2)
330  code += getPushCode(randUniIntGen() % 128); //memlen1
331  code += getPushCode(randUniIntGen() % 32); //memlen1
332  code += getPushCode(randUniIntGen()); //value
333  break;
336  //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2)
337  //(CALLCODE gaslimit address value memstart1 memlen1 memstart2 memlen2)
338  code += getPushCode(randUniIntGen() % 128); //memlen2
339  code += getPushCode(randUniIntGen() % 32); //memstart2
340  code += getPushCode(randUniIntGen() % 128); //memlen1
341  code += getPushCode(randUniIntGen() % 32); //memlen1
342  code += getPushCode(randUniIntGen()); //value
343  code += getPushCode(toString(_options.getRandomAddress()));//address
344  code += getPushCode(randUniIntGen()); //gaslimit
345  break;
346  case dev::eth::Instruction::SUICIDE: //(SUICIDE address)
347  code += getPushCode(toString(_options.getRandomAddress()));
348  break;
349  case dev::eth::Instruction::RETURN: //(RETURN memlen1 memlen2)
350  code += getPushCode(randUniIntGen() % 128); //memlen1
351  code += getPushCode(randUniIntGen() % 32); //memlen1
352  break;
353  default:
354  smart = false;
355  }
356  }
357 
358  if (smart == false)
359  for (unsigned i = 0; i < num; i++)
360  {
361  //generate random parameters
362  int length = randOpLengGen();
363  code += getPushCode(rndByteSequence(length));
364  }
365  return code;
366 }
367 
368 
369 //Ramdom Code Options
370 RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodeProbability(50)
371 {
372  //each op code with same weight-probability
373  for (auto i = 0; i < 255; i++)
374  mapWeights.insert(std::pair<int, int>(i, 50));
375  setWeights();
376 }
377 
379 {
380  mapWeights.at((int)_opCode) = _weight;
381  setWeights();
382 }
383 
385 {
386  addressList.push_back(_address);
387 }
388 
390 {
391  if (addressList.size() > 0)
392  {
393  int index = (int)RandomCode::randomUniInt() % addressList.size();
394  return addressList[index];
395  }
397 }
398 
400 {
401  std::vector<int> weights;
402  for (auto const& element: mapWeights)
403  weights.push_back(element.second);
405 }
406 
408 
410 {
411  std::string code;
412  cnote << "Testing Random Code: ";
413  try
414  {
416  }
417  catch(...)
418  {
419  BOOST_ERROR("Exception thrown when generating random code!");
420  }
421  cnote << code;
422 }
423 
425 
426 }
427 }
static boostIntGenerator randUniIntGen
Generate random UniformInt from uniIntDist.
Definition: fuzzHelper.h:115
std::string toCompactHex(u256 val, HexPrefix prefix=HexPrefix::DontAdd, unsigned _min=0)
Definition: CommonData.h:175
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
static boostIntDistrib opCodeDist
0..255 opcodes
Definition: fuzzHelper.h:110
static boostIntGenerator randOpCodeGen
Generate random value from opCodeDist.
Definition: fuzzHelper.h:116
uint8_t byte
Definition: Common.h:57
int args
Number of items required on the stack for this instruction (and, for the purposes of ret...
Definition: Instruction.h:262
place 1 byte item on stack
static boostUInt64Generator randUInt64Gen
Generate random uInt64.
Definition: fuzzHelper.h:118
Fixture class for boost output when running testeth.
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
size_t count
Definition: ExecStats.cpp:37
h160 Address
An Ethereum address: 20 bytes.
Definition: Common.h:62
static std::string getPushCode(int _value)
Definition: fuzzHelper.cpp:281
swaps the highest and 17th highest value on the stack
boost::random::variate_generator< boost::mt19937 &, boostDescreteDistrib > boostWeightGenerator
Definition: fuzzHelper.h:43
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
ExecStats::duration min
Definition: ExecStats.cpp:35
bytes code
Definition: SmartVM.cpp:45
halt execution and register account for later deletion
copies the 16th highest item in the stack to the top of the stack
InstructionInfo instructionInfo(Instruction _inst)
Information on all the instructions.
halt execution returning output data
void addAddress(dev::Address const &_address)
Definition: fuzzHelper.cpp:384
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
static std::string rndRLPSequence(int _depth, std::string &_debug)
Generate random rlp byte sequence of a given depth (e.g [[[]],[]]).
Definition: fuzzHelper.cpp:182
std::string name
The name of the instruction.
Definition: Instruction.h:260
void setWeight(dev::eth::Instruction _opCode, int _weight)
Definition: fuzzHelper.cpp:378
copies the highest item in the stack to the top of the stack
ExecStats::duration max
Definition: ExecStats.cpp:36
boost::random::discrete_distribution boostDescreteDistrib
Definition: fuzzHelper.h:39
static boost::random::mt19937 gen
Random generator.
Definition: fuzzHelper.h:109
message-call with another account&#39;s code only
Fixed-size raw-byte array container type, with an API optimised for storing hashes.
Definition: FixedHash.h:47
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
static void refreshSeed()
Definition: fuzzHelper.cpp:267
Instruction
Virtual machine bytecode instruction.
Definition: Instruction.h:39
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u64
Definition: Common.h:123
static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const &_options)
Definition: fuzzHelper.cpp:287
Information structure for a particular instruction.
Definition: Instruction.h:258
place 32 byte item on stack
BOOST_AUTO_TEST_CASE(rndCode)
Definition: fuzzHelper.cpp:409
swaps the highest and second highest value on the stack
#define cnote
Definition: Log.h:303
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
static u256 randomUniInt(u256 _maxVal=0)
Definition: fuzzHelper.cpp:259
static std::string rndByteSequence(int _length=1, SizeStrictness _sizeType=SizeStrictness::Strict)
Generate random byte string of a given length.
Definition: fuzzHelper.cpp:191
uint8_t const size_t const size
Definition: sha3.h:20
static std::string randomUniIntHex(u256 _maxVal=0)
Generate random int64.
Definition: fuzzHelper.cpp:248
dev::Address getRandomAddress() const
Definition: fuzzHelper.cpp:389
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
static std::string generate(int _maxOpNumber=1, RandomCodeOptions _options=RandomCodeOptions())
Generate random vm code.
Definition: fuzzHelper.cpp:205
message-call into an account
boostDescreteDistrib opCodeProbability
Definition: fuzzHelper.h:56
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
Definition: Common.h:326
static boostUint64Distrib uInt64Dist
0..2**64
Definition: fuzzHelper.h:113
std::vector< dev::Address > addressList
Definition: fuzzHelper.h:60
static boostIntGenerator randOpLengGen
Generate random length from opLengDist.
Definition: fuzzHelper.h:117
boost::random::uniform_int_distribution boostIntDistrib
Definition: fuzzHelper.h:38
static boostIntDistrib opLengDist
1..32 byte string
Definition: fuzzHelper.h:111
boost::random::variate_generator< boost::mt19937 &, boostUint64Distrib > boostUInt64Generator
Definition: fuzzHelper.h:44
static int recursiveRLP(std::string &_result, int _depth, std::string &_debug)
Definition: fuzzHelper.cpp:45
boost::uniform_int< uint64_t > boostUint64Distrib
Definition: fuzzHelper.h:40
boost::random::variate_generator< boost::mt19937 &, boostIntDistrib > boostIntGenerator
Definition: fuzzHelper.h:42
std::map< int, int > mapWeights
Definition: fuzzHelper.h:59
static boostIntDistrib uniIntDist
0..0x7fffffff
Definition: fuzzHelper.h:112
create a new account with associated code