Coverage Report

Created: 2025-09-04 07:34

/src/solidity/test/tools/ossfuzz/protoToAbiV2.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <test/tools/ossfuzz/abiV2Proto.pb.h>
4
5
#include <libsolutil/FixedHash.h>
6
#include <libsolutil/Keccak256.h>
7
#include <libsolutil/StringUtils.h>
8
#include <libsolutil/Whiskers.h>
9
#include <libsolutil/Numeric.h>
10
11
#include <liblangutil/Exceptions.h>
12
13
#include <boost/algorithm/string.hpp>
14
15
#include <ostream>
16
#include <random>
17
#include <sstream>
18
19
/**
20
 * Template of the solidity test program generated by this converter is as follows:
21
 *
22
 *    pragma solidity >=0.0;
23
 *    pragma experimental ABIEncoderV2;
24
 *
25
 *    contract C {
26
 *        // State variable
27
 *        string sv_0;
28
 *        // Test function that is called by the VM.
29
 *        // There are 2 variations of this function: one returns
30
 *        // the output of test_calldata_coding() and the other
31
 *        // returns the output of test_returndata_coding(). The
32
 *        // proto field called Test decides which one of the two
33
 *        // are chosen for creating a test case.
34
 *        function test() public returns (uint) {
35
 *            // The protobuf field "Contract.test" decides which of
36
 *            // the two internal functions "test_calldata_coding()"
37
 *            // and "test_returndata_coding()" are called. Here,
38
 *            // we assume that the protobuf field equals "CALLDATA_CODER"
39
 *            return this.test_calldata_coding()
40
 *        }
41
 *
42
 *        // The following function is generated if the protobuf field
43
 *        // "Contract.test" is equal to "RETURNDATA_CODER".
44
 *        function test_returndata_coding() internal returns (uint) {
45
 *            string memory lv_0, bytes memory lv_1 = test_returndata_external();
46
 *            if (lv_0 != 044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d)
47
 *                return 1;
48
 *            if (lv_1 != "1")
49
 *                return 2;
50
 *            return 0;
51
 *        }
52
 *
53
 *        // The following function is generated if the protobuf field
54
 *        // "Contract.test" is equal to "RETURNDATA_CODER".
55
 *        function test_returndata_external() external returns (string memory, bytes memory)
56
 *        {
57
 *            sv_0 = "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d";
58
 *            bytes memory lv_0 = "1";
59
 *            return (sv_0, lv_0);
60
 *        }
61
 *
62
 *        // The following function is generated if the protobuf field
63
 *        // "Contract.test" is equal to "CALLDATA_CODER".
64
 *        function test_calldata_coding() internal returns (uint) {
65
 *            // Local variable
66
 *            bytes lv_1 = "1";
67
 *            sv_0 = "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d";
68
 *            uint returnVal = this.coder_public(sv_0, lv_1);
69
 *            if (returnVal != 0)
70
 *                return returnVal;
71
 *            // Since the return codes in the public and external coder functions are identical
72
 *            // we offset error code by a fixed amount (200000) for differentiation.
73
 *            returnVal = this.coder_external(sv_0, lv_1);
74
 *            if (returnVal != 0)
75
 *                return 200000 + returnVal;
76
 *            // Encode parameters
77
 *            bytes memory argumentEncoding = abi.encode(<parameter_names>);
78
 *            returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
79
 *            // Check if calls to coder_public meet expectations for correctly/incorrectly encoded data.
80
 *            if (returnVal != 0)
81
 *                return returnVal;
82
 *
83
 *            returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
84
 *            // Check if calls to coder_external meet expectations for correctly/incorrectly encoded data.
85
 *            // Offset return value to distinguish between failures originating from coder_public and coder_external.
86
 *            if (returnVal != 0)
87
 *                return uint(200000) + returnVal;
88
 *            // Return zero if all checks pass.
89
 *            return 0;
90
 *        }
91
 *
92
 *        /// Accepts function selector, correct argument encoding, and an invalid encoding length as input.
93
 *        /// Returns a non-zero value if either call with correct encoding fails or call with incorrect encoding
94
 *        /// succeeds. Returns zero if both calls meet expectation.
95
 *        function checkEncodedCall(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
96
 *            public returns (uint) {
97
 *            ...
98
 *        }
99
 *
100
 *        /// Accepts function selector, correct argument encoding, and length of invalid encoding and returns
101
 *        /// the correct and incorrect abi encoding for calling the function specified by the function selector.
102
 *        function createEncoding(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
103
 *            internal pure returns (bytes memory, bytes memory) {
104
 *            ...
105
 *        }
106
 *
107
 *        /// Compares two dynamically sized bytes arrays for equality.
108
 *        function bytesCompare(bytes memory a, bytes memory b) internal pure returns (bool) {
109
 *            ...
110
 *        }
111
 *
112
 *        // Public function that is called by test() function. Accepts one or more arguments and returns
113
 *        // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
114
 *        function coder_public(string memory c_0, bytes memory c_1) public pure returns (uint) {
115
 *            if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
116
 *                return 1;
117
 *            if (!bytesCompare(c_1, "1"))
118
 *                return 2;
119
 *            return 0;
120
 *        }
121
 *
122
 *        // External function that is called by test() function. Accepts one or more arguments and returns
123
 *        // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
124
 *        function coder_external(string calldata c_0, bytes calldata c_1) external pure returns (uint) {
125
 *            if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
126
 *                return 1;
127
 *            if (!bytesCompare(c_1, "1"))
128
 *                return 2;
129
 *            return 0;
130
 *        }
131
 *    }
132
 */
133
134
namespace solidity::test::abiv2fuzzer
135
{
136
using RandomEngine = std::mt19937_64;
137
using Distribution = std::uniform_int_distribution<unsigned>;
138
using Bernoulli = std::bernoulli_distribution;
139
140
/// Converts a protobuf input into a Solidity program that tests
141
/// abi coding.
142
class ProtoConverter
143
{
144
public:
145
  ProtoConverter(unsigned _seed):
146
    m_isStateVar(true),
147
    m_counter(0),
148
    m_varCounter(0),
149
    m_returnValue(1),
150
    m_isLastDynParamRightPadded(false),
151
    m_structCounter(0),
152
    m_numStructsAdded(0)
153
319
  {
154
319
    m_random = std::make_unique<RandomEngine>(_seed);
155
319
  }
156
157
  ProtoConverter(ProtoConverter const&) = delete;
158
  ProtoConverter(ProtoConverter&&) = delete;
159
  std::string contractToString(Contract const& _input);
160
  std::string isabelleTypeString() const;
161
  std::string isabelleValueString() const;
162
  bool coderFunction() const
163
142
  {
164
142
    return m_test == Contract_Test::Contract_Test_CALLDATA_CODER;
165
142
  }
166
private:
167
  enum class Delimiter
168
  {
169
    ADD,
170
    SKIP
171
  };
172
  /// Enum of possible function types that decode abi
173
  /// encoded parameters.
174
  enum class CalleeType
175
  {
176
    PUBLIC,
177
    EXTERNAL
178
  };
179
180
  /// Each external parameter representation contains the following:
181
  /// - Delimiter prefix
182
  /// - Boolean that is true if value type, false otherwise
183
  /// - String representation of type
184
  /// - Parameter name
185
  using ParameterPack = std::tuple<Delimiter, bool, std::string, std::string>;
186
187
  /// Visitors for various Protobuf types
188
  /// Visit top-level contract specification
189
  void visit(Contract const&);
190
191
  /// Convert test function specification into Solidity test
192
  /// function
193
  /// @param _testSpec: Protobuf test function specification
194
  /// @param _storageDefs: String containing Solidity assignment
195
  /// statements to be placed inside the scope of the test function.
196
  std::string visit(TestFunction const& _testSpec, std::string const& _storageDefs);
197
198
  /// Visitors for the remaining protobuf types. They convert
199
  /// the input protobuf specification type into Solidity code.
200
  /// @return A pair of strings, first of which contains Solidity
201
  /// code to be placed inside contract scope, second of which contains
202
  /// Solidity code to be placed inside test function scope.
203
  std::pair<std::string, std::string> visit(VarDecl const&);
204
  std::pair<std::string, std::string> visit(Type const&);
205
  std::pair<std::string, std::string> visit(ValueType const&);
206
  std::pair<std::string, std::string> visit(NonValueType const&);
207
  std::pair<std::string, std::string> visit(BoolType const&);
208
  std::pair<std::string, std::string> visit(IntegerType const&);
209
  std::pair<std::string, std::string> visit(FixedByteType const&);
210
  std::pair<std::string, std::string> visit(AddressType const&);
211
  std::pair<std::string, std::string> visit(DynamicByteArrayType const&);
212
  std::pair<std::string, std::string> visit(ArrayType const&);
213
  std::pair<std::string, std::string> visit(StructType const&);
214
215
  /// Convert a protobuf type @a _T into Solidity code to be placed
216
  /// inside contract and test function scopes.
217
  /// @param: _type (of parameterized type protobuf type T) is the type
218
  /// of protobuf input to be converted.
219
  /// @param: _isValueType is true if _type is a Solidity value type e.g., uint
220
  /// and false otherwise e.g., string
221
  /// @return: A pair of strings, first of which contains Solidity
222
  /// code to be placed inside contract scope, second of which contains
223
  /// Solidity code to be placed inside test function scope.
224
  template <typename T>
225
  std::pair<std::string, std::string> processType(T const& _type, bool _isValueType);
226
227
  /// Convert a protobuf type @a _T into Solidity variable assignment and check
228
  /// statements to be placed inside contract and test function scopes.
229
  /// @param: _varName is the name of the Solidity variable
230
  /// @param: _paramName is the name of the Solidity parameter that is passed
231
  /// to the test function
232
  /// @param: _type (of parameterized type protobuf type T) is the type
233
  /// of protobuf input to be converted.
234
  /// @return: A pair of strings, first of which contains Solidity
235
  /// statements to be placed inside contract scope, second of which contains
236
  /// Solidity statements to be placed inside test function scope.
237
  template <typename T>
238
  std::pair<std::string, std::string> assignChecker(
239
    std::string const& _varName,
240
    std::string const& _paramName,
241
    T _type
242
  );
243
244
  /// Convert a protobuf type @a _T into Solidity variable declaration statement.
245
  /// @param: _varName is the name of the Solidity variable
246
  /// @param: _paramName is the name of the Solidity parameter that is passed
247
  /// to the test function
248
  /// @param: _type (of parameterized type protobuf type T) is the type
249
  /// of protobuf input to be converted.
250
  /// @param: _isValueType is a boolean that is true if _type is a
251
  /// Solidity value type e.g., uint and false otherwise e.g., string
252
  /// @param: _location is the Solidity location qualifier string to
253
  /// be used inside variable declaration statements
254
  /// @return: A pair of strings, first of which contains Solidity
255
  /// variable declaration statement to be placed inside contract scope,
256
  /// second of which contains Solidity variable declaration statement
257
  /// to be placed inside test function scope.
258
  template <typename T>
259
  std::pair<std::string, std::string> varDecl(
260
    std::string const& _varName,
261
    std::string const& _paramName,
262
    T _type,
263
    bool _isValueType,
264
    std::string const& _location
265
  );
266
267
  /// Appends a function parameter to the function parameter stream.
268
  void appendTypedParams(
269
    CalleeType _calleeType,
270
    bool _isValueType,
271
    std::string const& _typeString,
272
    std::string const& _varName,
273
    Delimiter _delimiter
274
  );
275
276
  /// Appends a function parameter to the public test function's
277
  /// parameter stream.
278
  void appendTypedParamsPublic(
279
    bool _isValueType,
280
    std::string const& _typeString,
281
    std::string const& _varName,
282
    Delimiter _delimiter = Delimiter::ADD
283
  );
284
285
  /// Appends a function parameter to the external test function's
286
  /// parameter stream.
287
  void appendTypedParamsExternal(
288
    bool _isValueType,
289
    std::string const& _typeString,
290
    std::string const& _varName,
291
    Delimiter _delimiter = Delimiter::ADD
292
  );
293
294
  /// Append types to typed stream used by returndata coders.
295
  void appendTypes(
296
    bool _isValueType,
297
    std::string const& _typeString,
298
    Delimiter _delimiter
299
  );
300
301
  /// Append typed return value.
302
  void appendTypedReturn(
303
    bool _isValueType,
304
    std::string const& _typeString,
305
    Delimiter _delimiter
306
  );
307
308
  /// Append type name to type string meant to be
309
  /// passed to Isabelle coder API.
310
  void appendToIsabelleTypeString(
311
    std::string const& _typeString,
312
    Delimiter _delimiter
313
  );
314
315
  /// Append @a _valueString to value string meant to be
316
  /// passed to Isabelle coder API.
317
  void appendToIsabelleValueString(
318
    std::string const& _valueString,
319
    Delimiter _delimiter
320
  );
321
322
  /// Returns a Solidity variable declaration statement
323
  /// @param _type: string containing Solidity type of the
324
  /// variable to be declared.
325
  /// @param _varName: string containing Solidity variable
326
  /// name
327
  /// @param _qualifier: string containing location where
328
  /// the variable will be placed
329
  std::string getVarDecl(
330
    std::string const& _type,
331
    std::string const& _varName,
332
    std::string const& _qualifier
333
  );
334
335
  /// Return checks that are encoded as Solidity if statements
336
  /// as string
337
  std::string equalityChecksAsString();
338
339
  /// Return comma separated typed function parameters as string
340
  std::string typedParametersAsString(CalleeType _calleeType);
341
342
  /// Return commonly used Solidity helper functions as string
343
  std::string commonHelperFunctions();
344
345
  /// Return helper functions used to test calldata coding
346
  std::string calldataHelperFunctions();
347
348
  /// Return top-level calldata coder test function as string
349
  std::string testCallDataFunction(unsigned _invalidLength);
350
351
  /// Return top-level returndata coder test function as string
352
  std::string testReturnDataFunction();
353
354
  /// Return the next variable count that is used for
355
  /// variable naming.
356
  unsigned getNextVarCounter()
357
501
  {
358
501
    return m_varCounter++;
359
501
  }
360
361
  /// Return a pair of names for Solidity variable and the same variable when
362
  /// passed either as a function parameter or used to store the tuple
363
  /// returned from a function.
364
  /// @param _varCounter: name suffix
365
  /// @param _stateVar: predicate that is true for state variables, false otherwise
366
  std::pair<std::string, std::string> newVarNames(unsigned _varCounter, bool _stateVar)
367
501
  {
368
501
    std::string varName = _stateVar ? s_stateVarNamePrefix : s_localVarNamePrefix;
369
501
    return std::make_pair(
370
501
      varName + std::to_string(_varCounter),
371
501
      paramName() + std::to_string(_varCounter)
372
501
    );
373
501
  }
374
375
  std::string paramName()
376
501
  {
377
501
    switch (m_test)
378
501
    {
379
414
    case Contract_Test::Contract_Test_CALLDATA_CODER:
380
414
      return s_paramNamePrefix;
381
87
    case Contract_Test::Contract_Test_RETURNDATA_CODER:
382
87
      return s_localVarNamePrefix;
383
501
    }
384
501
  }
385
386
  /// Checks if the last dynamically encoded Solidity type is right
387
  /// padded, returning true if it is and false otherwise.
388
  bool isLastDynParamRightPadded()
389
319
  {
390
319
    return m_isLastDynParamRightPadded;
391
319
  }
392
393
  /// Convert delimiter to a comma or null string.
394
  static std::string delimiterToString(Delimiter _delimiter, bool _space = true);
395
  /// Generates number in the range [1, @param _n] uniformly at random.
396
  unsigned randomNumberOneToN(unsigned _n)
397
319
  {
398
319
    return Distribution(1, _n)(*m_random);
399
319
  }
400
  /// Generates boolean that has a bernoulli distribution defined by @param _p.
401
  bool randomBool(double _p)
402
2.48k
  {
403
2.48k
    return Bernoulli{_p}(*m_random);
404
2.48k
  }
405
406
  /// Contains the test program
407
  std::ostringstream m_output;
408
  /// Contains a subset of the test program. This subset contains
409
  /// checks to be encoded in the test program
410
  std::ostringstream m_checks;
411
  /// Contains typed parameter list to be passed to callee functions
412
  std::ostringstream m_typedParamsPublic;
413
  /// Contains parameter list to be passed to callee functions
414
  std::ostringstream m_untypedParamsExternal;
415
  /// Contains type string to be passed to Isabelle API
416
  std::ostringstream m_isabelleTypeString;
417
  /// Contains values to be encoded in the format accepted
418
  /// by the Isabelle API.
419
  std::ostringstream m_isabelleValueString;
420
  /// Contains type stream to be used in returndata coder function
421
  /// signature
422
  std::ostringstream m_types;
423
  std::ostringstream m_typedReturn;
424
  /// Argument names to be passed to coder functions
425
  std::ostringstream m_argsCoder;
426
  /// Predicate that is true if we are in contract scope
427
  bool m_isStateVar;
428
  unsigned m_counter;
429
  unsigned m_varCounter;
430
  /// Monotonically increasing return value for error reporting
431
  unsigned m_returnValue;
432
  /// Flag that indicates if last dynamically encoded parameter
433
  /// passed to a function call is of a type that is going to be
434
  /// right padded by the ABI encoder.
435
  bool m_isLastDynParamRightPadded;
436
  /// Struct counter
437
  unsigned m_structCounter;
438
  unsigned m_numStructsAdded;
439
  /// Enum stating abiv2 coder to be tested
440
  Contract_Test m_test;
441
  /// Representation of external parameters
442
  std::vector<ParameterPack> m_externalParamsRep;
443
  /// Random number generator
444
  std::unique_ptr<RandomEngine> m_random;
445
  /// Prefixes for declared and parameterized variable names
446
  static auto constexpr s_localVarNamePrefix = "lv_";
447
  static auto constexpr s_stateVarNamePrefix = "sv_";
448
  static auto constexpr s_paramNamePrefix = "p_";
449
  /// Maximum number of indirections to test calldata coding
450
  static unsigned constexpr s_maxIndirections = 5;
451
};
452
453
/// Visitor interface for Solidity protobuf types.
454
template <typename T>
455
class AbiV2ProtoVisitor
456
{
457
public:
458
  static unsigned constexpr s_maxArrayDimensions = 3;
459
354k
  virtual ~AbiV2ProtoVisitor() = default;
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::~AbiV2ProtoVisitor()
Line
Count
Source
459
233k
  virtual ~AbiV2ProtoVisitor() = default;
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::~AbiV2ProtoVisitor()
Line
Count
Source
459
120k
  virtual ~AbiV2ProtoVisitor() = default;
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::~AbiV2ProtoVisitor()
Line
Count
Source
459
501
  virtual ~AbiV2ProtoVisitor() = default;
460
461
  virtual T visit(BoolType const& _node) = 0;
462
  virtual T visit(IntegerType const& _node) = 0;
463
  virtual T visit(FixedByteType const& _node) = 0;
464
  virtual T visit(AddressType const& _node) = 0;
465
  virtual T visit(DynamicByteArrayType const& _node) = 0;
466
  virtual T visit(ArrayType const& _node) = 0;
467
  virtual T visit(StructType const& _node) = 0;
468
  virtual T visit(ValueType const& _node)
469
282k
  {
470
282k
    return visitValueType(_node);
471
282k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visit(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
469
33.9k
  {
470
33.9k
    return visitValueType(_node);
471
33.9k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visit(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
469
47.3k
  {
470
47.3k
    return visitValueType(_node);
471
47.3k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
469
201k
  {
470
201k
    return visitValueType(_node);
471
201k
  }
472
  virtual T visit(NonValueType const& _node)
473
506k
  {
474
506k
    return visitNonValueType(_node);
475
506k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visit(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
473
28.4k
  {
474
28.4k
    return visitNonValueType(_node);
475
28.4k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visit(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
473
38.7k
  {
474
38.7k
    return visitNonValueType(_node);
475
38.7k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
473
439k
  {
474
439k
    return visitNonValueType(_node);
475
439k
  }
476
  virtual T visit(Type const& _node)
477
864k
  {
478
864k
    return visitType(_node);
479
864k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
477
703k
  {
478
703k
    return visitType(_node);
479
703k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visit(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
477
62.4k
  {
478
62.4k
    return visitType(_node);
479
62.4k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visit(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
477
98.3k
  {
478
98.3k
    return visitType(_node);
479
98.3k
  }
480
481
  enum class DataType
482
  {
483
    BYTES,
484
    VALUE,
485
    ARRAY
486
  };
487
488
  /// Prefixes for declared and parameterized variable names
489
  static auto constexpr s_structNamePrefix = "S";
490
491
  // Static function definitions
492
  static bool isValueType(DataType _dataType)
493
  {
494
    return _dataType == DataType::VALUE;
495
  }
496
497
  static unsigned getIntWidth(IntegerType const& _x)
498
25.6k
  {
499
25.6k
    return 8 * ((_x.width() % 32) + 1);
500
25.6k
  }
501
502
  static bool isIntSigned(IntegerType const& _x)
503
11.1k
  {
504
11.1k
    return _x.is_signed();
505
11.1k
  }
506
507
  static std::string getIntTypeAsString(IntegerType const& _x)
508
11.1k
  {
509
11.1k
    return ((isIntSigned(_x) ? "int" : "uint") + std::to_string(getIntWidth(_x)));
510
11.1k
  }
511
512
  static unsigned getFixedByteWidth(FixedByteType const& _x)
513
8.65k
  {
514
8.65k
    return (_x.width() % 32) + 1;
515
8.65k
  }
516
517
  static std::string getFixedByteTypeAsString(FixedByteType const& _x)
518
4.03k
  {
519
4.03k
    return "bytes" + std::to_string(getFixedByteWidth(_x));
520
4.03k
  }
521
522
  // Convert _counter to string and return its keccak256 hash
523
  static u256 hashUnsignedInt(unsigned _counter)
524
21.0k
  {
525
21.0k
    return util::keccak256(util::h256(_counter));
526
21.0k
  }
527
528
  static u256 maskUnsignedInt(unsigned _counter, unsigned _numMaskNibbles)
529
21.0k
  {
530
21.0k
    return hashUnsignedInt(_counter) & u256("0x" + std::string(_numMaskNibbles, 'f'));
531
21.0k
  }
532
533
  // Requires caller to pass number of nibbles (twice the number of bytes) as second argument.
534
  // Note: Don't change HexPrefix::Add. See comment in fixedByteValueAsString().
535
  static std::string maskUnsignedIntToHex(unsigned _counter, unsigned _numMaskNibbles)
536
21.0k
  {
537
21.0k
    return "0x" + toHex(maskUnsignedInt(_counter, _numMaskNibbles));
538
21.0k
  }
539
540
  /// Dynamically sized arrays can have a length of at least zero
541
  /// and at most s_maxArrayLength.
542
  static unsigned getDynArrayLengthFromFuzz(unsigned _fuzz, unsigned _counter)
543
6.65k
  {
544
    // Increment modulo value by one in order to meet upper bound
545
6.65k
    return (_fuzz + _counter) % (s_maxArrayLength + 1);
546
6.65k
  }
547
548
  /// Statically sized arrays must have a length of at least one
549
  /// and at most s_maxArrayLength.
550
  static unsigned getStaticArrayLengthFromFuzz(unsigned _fuzz)
551
4.22k
  {
552
4.22k
    return _fuzz % s_maxArrayLength + 1;
553
4.22k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::getStaticArrayLengthFromFuzz(unsigned int)
Line
Count
Source
551
2.72k
  {
552
2.72k
    return _fuzz % s_maxArrayLength + 1;
553
2.72k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::getStaticArrayLengthFromFuzz(unsigned int)
Line
Count
Source
551
1.50k
  {
552
1.50k
    return _fuzz % s_maxArrayLength + 1;
553
1.50k
  }
554
555
  /// Returns a pseudo-random value for the size of a string/hex
556
  /// literal. Used for creating variable length hex/string literals.
557
  /// @param _counter Monotonically increasing counter value
558
  static unsigned getVarLength(unsigned _counter)
559
6.36k
  {
560
    // Since _counter values are usually small, we use
561
    // this linear equation to make the number derived from
562
    // _counter approach a uniform distribution over
563
    // [0, s_maxDynArrayLength]
564
6.36k
    auto v = (_counter + 879) * 32 % (s_maxDynArrayLength + 1);
565
    /// Always return an even number because Isabelle string
566
    /// values are formatted as hex literals
567
6.36k
    if (v % 2 == 1)
568
3.07k
      return v + 1;
569
3.29k
    else
570
3.29k
      return v;
571
6.36k
  }
572
protected:
573
T visitValueType(ValueType const& _type)
574
282k
{
575
282k
  switch (_type.value_type_oneof_case())
576
282k
  {
577
67.5k
  case ValueType::kInty:
578
67.5k
    return visit(_type.inty());
579
34.5k
  case ValueType::kByty:
580
34.5k
    return visit(_type.byty());
581
75.5k
  case ValueType::kAdty:
582
75.5k
    return visit(_type.adty());
583
88.0k
  case ValueType::kBoolty:
584
88.0k
    return visit(_type.boolty());
585
17.2k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
17.2k
    return T();
587
282k
  }
588
282k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visitValueType(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
574
33.9k
{
575
33.9k
  switch (_type.value_type_oneof_case())
576
33.9k
  {
577
11.1k
  case ValueType::kInty:
578
11.1k
    return visit(_type.inty());
579
4.02k
  case ValueType::kByty:
580
4.02k
    return visit(_type.byty());
581
7.79k
  case ValueType::kAdty:
582
7.79k
    return visit(_type.adty());
583
11.0k
  case ValueType::kBoolty:
584
11.0k
    return visit(_type.boolty());
585
0
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
0
    return T();
587
33.9k
  }
588
33.9k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visitValueType(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
574
47.3k
{
575
47.3k
  switch (_type.value_type_oneof_case())
576
47.3k
  {
577
14.5k
  case ValueType::kInty:
578
14.5k
    return visit(_type.inty());
579
4.61k
  case ValueType::kByty:
580
4.61k
    return visit(_type.byty());
581
10.0k
  case ValueType::kAdty:
582
10.0k
    return visit(_type.adty());
583
13.9k
  case ValueType::kBoolty:
584
13.9k
    return visit(_type.boolty());
585
4.23k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
4.23k
    return T();
587
47.3k
  }
588
47.3k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitValueType(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
574
201k
{
575
201k
  switch (_type.value_type_oneof_case())
576
201k
  {
577
41.9k
  case ValueType::kInty:
578
41.9k
    return visit(_type.inty());
579
25.8k
  case ValueType::kByty:
580
25.8k
    return visit(_type.byty());
581
57.6k
  case ValueType::kAdty:
582
57.6k
    return visit(_type.adty());
583
63.0k
  case ValueType::kBoolty:
584
63.0k
    return visit(_type.boolty());
585
13.0k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
13.0k
    return T();
587
201k
  }
588
201k
}
589
590
T visitNonValueType(NonValueType const& _type)
591
506k
{
592
506k
  switch (_type.nonvalue_type_oneof_case())
593
506k
  {
594
46.2k
  case NonValueType::kDynbytearray:
595
46.2k
    return visit(_type.dynbytearray());
596
46.8k
  case NonValueType::kArrtype:
597
46.8k
    return visit(_type.arrtype());
598
397k
  case NonValueType::kStype:
599
397k
    return visit(_type.stype());
600
15.5k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
15.5k
    return T();
602
506k
  }
603
506k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visitNonValueType(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
591
28.4k
{
592
28.4k
  switch (_type.nonvalue_type_oneof_case())
593
28.4k
  {
594
5.81k
  case NonValueType::kDynbytearray:
595
5.81k
    return visit(_type.dynbytearray());
596
6.53k
  case NonValueType::kArrtype:
597
6.53k
    return visit(_type.arrtype());
598
16.1k
  case NonValueType::kStype:
599
16.1k
    return visit(_type.stype());
600
0
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
0
    return T();
602
28.4k
  }
603
28.4k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visitNonValueType(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
591
38.7k
{
592
38.7k
  switch (_type.nonvalue_type_oneof_case())
593
38.7k
  {
594
6.34k
  case NonValueType::kDynbytearray:
595
6.34k
    return visit(_type.dynbytearray());
596
10.4k
  case NonValueType::kArrtype:
597
10.4k
    return visit(_type.arrtype());
598
19.7k
  case NonValueType::kStype:
599
19.7k
    return visit(_type.stype());
600
2.18k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
2.18k
    return T();
602
38.7k
  }
603
38.7k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitNonValueType(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
591
439k
{
592
439k
  switch (_type.nonvalue_type_oneof_case())
593
439k
  {
594
34.1k
  case NonValueType::kDynbytearray:
595
34.1k
    return visit(_type.dynbytearray());
596
29.8k
  case NonValueType::kArrtype:
597
29.8k
    return visit(_type.arrtype());
598
361k
  case NonValueType::kStype:
599
361k
    return visit(_type.stype());
600
13.3k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
13.3k
    return T();
602
439k
  }
603
439k
}
604
605
T visitType(Type const& _type)
606
864k
{
607
864k
  switch (_type.type_oneof_case())
608
864k
  {
609
282k
  case Type::kVtype:
610
282k
    return visit(_type.vtype());
611
506k
  case Type::kNvtype:
612
506k
    return visit(_type.nvtype());
613
74.6k
  case Type::TYPE_ONEOF_NOT_SET:
614
74.6k
    return T();
615
864k
  }
616
864k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitType(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
606
703k
{
607
703k
  switch (_type.type_oneof_case())
608
703k
  {
609
201k
  case Type::kVtype:
610
201k
    return visit(_type.vtype());
611
439k
  case Type::kNvtype:
612
439k
    return visit(_type.nvtype());
613
62.3k
  case Type::TYPE_ONEOF_NOT_SET:
614
62.3k
    return T();
615
703k
  }
616
703k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::visitType(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
606
62.4k
{
607
62.4k
  switch (_type.type_oneof_case())
608
62.4k
  {
609
33.9k
  case Type::kVtype:
610
33.9k
    return visit(_type.vtype());
611
28.4k
  case Type::kNvtype:
612
28.4k
    return visit(_type.nvtype());
613
0
  case Type::TYPE_ONEOF_NOT_SET:
614
0
    return T();
615
62.4k
  }
616
62.4k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::visitType(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
606
98.3k
{
607
98.3k
  switch (_type.type_oneof_case())
608
98.3k
  {
609
47.3k
  case Type::kVtype:
610
47.3k
    return visit(_type.vtype());
611
38.7k
  case Type::kNvtype:
612
38.7k
    return visit(_type.nvtype());
613
12.2k
  case Type::TYPE_ONEOF_NOT_SET:
614
12.2k
    return T();
615
98.3k
  }
616
98.3k
}
617
private:
618
  static unsigned constexpr s_maxArrayLength = 4;
619
  static unsigned constexpr s_maxDynArrayLength = 256;
620
};
621
622
/// Converts a protobuf type into a Solidity type string.
623
class TypeVisitor: public AbiV2ProtoVisitor<std::string>
624
{
625
public:
626
  TypeVisitor(unsigned _structSuffix = 0):
627
    m_indentation(1),
628
    m_structCounter(_structSuffix),
629
    m_structStartCounter(_structSuffix),
630
    m_structFieldCounter(0),
631
    m_isLastDynParamRightPadded(false)
632
57.7k
  {}
633
634
  std::string visit(BoolType const&) override;
635
  std::string visit(IntegerType const&) override;
636
  std::string visit(FixedByteType const&) override;
637
  std::string visit(AddressType const&) override;
638
  std::string visit(ArrayType const&) override;
639
  std::string visit(DynamicByteArrayType const&) override;
640
  std::string visit(StructType const&) override;
641
  using AbiV2ProtoVisitor<std::string>::visit;
642
  std::string baseType()
643
0
  {
644
0
    return m_baseType;
645
0
  }
646
  bool isLastDynParamRightPadded()
647
501
  {
648
501
    return m_isLastDynParamRightPadded;
649
501
  }
650
  std::string structDef()
651
48.2k
  {
652
48.2k
    return m_structDef.str();
653
48.2k
  }
654
  unsigned numStructs()
655
48.2k
  {
656
48.2k
    return m_structCounter - m_structStartCounter;
657
48.2k
  }
658
  static bool arrayOfStruct(ArrayType const& _type)
659
1.63k
  {
660
1.63k
    Type const& baseType = _type.t();
661
1.63k
    if (baseType.has_nvtype() && baseType.nvtype().has_stype())
662
903
      return true;
663
731
    else if (baseType.has_nvtype() && baseType.nvtype().has_arrtype())
664
274
      return arrayOfStruct(baseType.nvtype().arrtype());
665
457
    else
666
457
      return false;
667
1.63k
  }
668
  std::string isabelleTypeString()
669
48.2k
  {
670
48.2k
    return m_structTupleString.stream.str();
671
48.2k
  }
672
private:
673
  struct StructTupleString
674
  {
675
57.7k
    StructTupleString() = default;
676
    unsigned index = 0;
677
    std::ostringstream stream;
678
    void start()
679
16.5k
    {
680
16.5k
      stream << "(";
681
16.5k
    }
682
    void end()
683
16.5k
    {
684
16.5k
      stream << ")";
685
16.5k
    }
686
    void addTypeStringToTuple(std::string& _typeString);
687
    void addArrayBracketToType(std::string& _arrayBracket);
688
  };
689
  void structDefinition(StructType const&);
690
691
  std::string indentation()
692
80.7k
  {
693
80.7k
    return std::string(m_indentation * 1, '\t');
694
80.7k
  }
695
  std::string lineString(std::string const& _line)
696
80.7k
  {
697
80.7k
    return indentation() + _line + "\n";
698
80.7k
  }
699
  std::string m_baseType;
700
  std::ostringstream m_structDef;
701
  /// Utility type for conveniently composing a tuple
702
  /// string for struct types.
703
  StructTupleString m_structTupleString;
704
  unsigned m_indentation;
705
  unsigned m_structCounter;
706
  unsigned m_structStartCounter;
707
  unsigned m_structFieldCounter;
708
  bool m_isLastDynParamRightPadded;
709
710
  static auto constexpr s_structTypeName = "S";
711
};
712
713
/// Returns a pair of strings, first of which contains assignment statements
714
/// to initialize a given type, and second of which contains checks to be
715
/// placed inside the coder function to test abi en/decoding.
716
class AssignCheckVisitor: public AbiV2ProtoVisitor<std::pair<std::string, std::string>>
717
{
718
public:
719
  AssignCheckVisitor(
720
    std::string _varName,
721
    std::string _paramName,
722
    unsigned _errorStart,
723
    bool _stateVar,
724
    unsigned _counter,
725
    unsigned _structCounter
726
  )
727
501
  {
728
501
    m_counter = m_counterStart = _counter;
729
501
    m_varName = _varName;
730
501
    m_paramName = _paramName;
731
501
    m_errorCode = m_errorStart = _errorStart;
732
501
    m_indentation = 2;
733
501
    m_stateVar = _stateVar;
734
501
    m_structCounter = m_structStart = _structCounter;
735
501
  }
736
  std::pair<std::string, std::string> visit(BoolType const&) override;
737
  std::pair<std::string, std::string> visit(IntegerType const&) override;
738
  std::pair<std::string, std::string> visit(FixedByteType const&) override;
739
  std::pair<std::string, std::string> visit(AddressType const&) override;
740
  std::pair<std::string, std::string> visit(ArrayType const&) override;
741
  std::pair<std::string, std::string> visit(DynamicByteArrayType const&) override;
742
  std::pair<std::string, std::string> visit(StructType const&) override;
743
  using AbiV2ProtoVisitor<std::pair<std::string, std::string>>::visit;
744
745
  unsigned errorStmts()
746
501
  {
747
501
    return m_errorCode - m_errorStart;
748
501
  }
749
750
  unsigned counted()
751
501
  {
752
501
    return m_counter - m_counterStart;
753
501
  }
754
755
  unsigned structs()
756
0
  {
757
0
    return m_structCounter - m_structStart;
758
0
  }
759
760
  std::string isabelleValueString()
761
501
  {
762
501
    return m_valueStream.stream.str();
763
501
  }
764
private:
765
  struct ValueStream
766
  {
767
501
    ValueStream() = default;
768
    unsigned index = 0;
769
    std::ostringstream stream;
770
    void startStruct()
771
13.7k
    {
772
13.7k
      if (index >= 1)
773
6.29k
        stream << ",";
774
13.7k
      index = 0;
775
13.7k
      stream << "(";
776
13.7k
    }
777
    void endStruct()
778
13.7k
    {
779
13.7k
      stream << ")";
780
13.7k
    }
781
    void startArray()
782
5.89k
    {
783
5.89k
      if (index >= 1)
784
4.54k
        stream << ",";
785
5.89k
      index = 0;
786
5.89k
      stream << "[";
787
5.89k
    }
788
    void endArray()
789
5.89k
    {
790
5.89k
      stream << "]";
791
5.89k
      index++;
792
5.89k
    }
793
    void appendValue(std::string& _value);
794
  };
795
  std::string indentation()
796
113k
  {
797
113k
    return std::string(m_indentation * 1, '\t');
798
113k
  }
799
  unsigned counter()
800
56.1k
  {
801
56.1k
    return m_counter++;
802
56.1k
  }
803
804
  std::pair<std::string, std::string> assignAndCheckStringPair(
805
    std::string const& _varRef,
806
    std::string const& _checkRef,
807
    std::string const& _assignValue,
808
    std::string const& _checkValue,
809
    DataType _type
810
  );
811
  std::string assignString(std::string const&, std::string const&);
812
  std::string checkString(std::string const&, std::string const&, DataType);
813
  unsigned m_counter;
814
  unsigned m_counterStart;
815
  std::string m_varName;
816
  std::string m_paramName;
817
  unsigned m_errorCode;
818
  unsigned m_errorStart;
819
  unsigned m_indentation;
820
  bool m_stateVar;
821
  unsigned m_structCounter;
822
  unsigned m_structStart;
823
  ValueStream m_valueStream;
824
  bool m_forcedVisit = false;
825
};
826
827
/// Returns a valid value (as a string) for a given type.
828
class ValueGetterVisitor: AbiV2ProtoVisitor<std::string>
829
{
830
public:
831
63.1k
  ValueGetterVisitor(unsigned _counter = 0): m_counter(_counter) {}
832
833
  std::string visit(BoolType const&) override;
834
  std::string visit(IntegerType const&) override;
835
  std::string visit(FixedByteType const&) override;
836
  std::string visit(AddressType const&) override;
837
  std::string visit(DynamicByteArrayType const&) override;
838
  std::string visit(ArrayType const&) override
839
0
  {
840
0
    solAssert(false, "ABIv2 proto fuzzer: Cannot call valuegettervisitor on complex type");
841
0
  }
842
  std::string visit(StructType const&) override
843
0
  {
844
0
    solAssert(false, "ABIv2 proto fuzzer: Cannot call valuegettervisitor on complex type");
845
0
  }
846
  using AbiV2ProtoVisitor<std::string>::visit;
847
  static std::string isabelleAddressValueAsString(std::string& _solAddressString);
848
  static std::string isabelleBytesValueAsString(std::string& _solFixedBytesString);
849
private:
850
  unsigned counter()
851
49.5k
  {
852
49.5k
    return m_counter++;
853
49.5k
  }
854
855
  static std::string addressValueAsString(unsigned _counter);
856
  static std::string fixedByteValueAsString(unsigned _width, unsigned _counter);
857
858
  /// Returns a hex literal if _isHexLiteral is true, a string literal otherwise.
859
  /// The size of the returned literal is _numBytes bytes.
860
  /// @param _decorate If true, the returned string is enclosed within double quotes
861
  /// if _isHexLiteral is false.
862
  /// @param _isHexLiteral If true, the returned string is enclosed within
863
  /// double quotes prefixed by the string "hex" if _decorate is true. If
864
  /// _decorate is false, the returned string is returned as-is.
865
  /// @return hex value as string
866
  static std::string hexValueAsString(
867
    unsigned _numBytes,
868
    unsigned _counter,
869
    bool _isHexLiteral,
870
    bool _decorate = true
871
  );
872
873
  /// Returns a hex/string literal of variable length whose value and
874
  /// size are pseudo-randomly determined from the counter value.
875
  /// @param _counter A monotonically increasing counter value
876
  /// @param _isHexLiteral Flag that indicates whether hex (if true) or
877
  /// string literal (false) is desired
878
  /// @return A variable length hex/string value
879
  static std::string bytesArrayValueAsString(unsigned _counter, bool _isHexLiteral);
880
881
  /// Concatenates the hash value obtained from monotonically increasing counter
882
  /// until the desired number of bytes determined by _numBytes.
883
  /// @param _width Desired number of bytes for hex value
884
  /// @param _counter A counter value used for creating a keccak256 hash
885
  /// @param _isHexLiteral Since this routine may be used to construct
886
  /// string or hex literals, this flag is used to construct a valid output.
887
  /// @return Valid hex or string literal of size _width bytes
888
  static std::string variableLengthValueAsString(
889
    unsigned _width,
890
    unsigned _counter,
891
    bool _isHexLiteral
892
  );
893
894
  /// Returns a value that is @a _numBytes bytes long.
895
  /// @param _numBytes: Number of bytes of desired value
896
  /// @param _counter: A counter value
897
  /// @param _isHexLiteral: True if desired value is a hex literal, false otherwise
898
  static std::string croppedString(unsigned _numBytes, unsigned _counter, bool _isHexLiteral);
899
900
  unsigned m_counter;
901
};
902
903
/// Returns true if protobuf array specification is well-formed, false otherwise
904
class ValidityVisitor: AbiV2ProtoVisitor<bool>
905
{
906
public:
907
209k
  ValidityVisitor(): m_arrayDimensions(0) {}
908
909
  bool visit(BoolType const&) override
910
50.2k
  {
911
50.2k
    return true;
912
50.2k
  }
913
914
  bool visit(IntegerType const&) override
915
34.3k
  {
916
34.3k
    return true;
917
34.3k
  }
918
919
  bool visit(FixedByteType const&) override
920
21.9k
  {
921
21.9k
    return true;
922
21.9k
  }
923
924
  bool visit(AddressType const&) override
925
49.2k
  {
926
49.2k
    return true;
927
49.2k
  }
928
929
  bool visit(DynamicByteArrayType const&) override
930
29.1k
  {
931
29.1k
    return true;
932
29.1k
  }
933
934
  bool visit(ArrayType const& _type) override
935
62.2k
  {
936
    // Mark array type as invalid in one of the following is true
937
    //  - contains more than s_maxArrayDimensions dimensions
938
    //  - contains an invalid base type, which happens in the
939
    //  following cases
940
    //    - array base type is invalid
941
    //    - array base type is empty
942
62.2k
    m_arrayDimensions++;
943
62.2k
    if (m_arrayDimensions > s_maxArrayDimensions)
944
398
      return false;
945
61.8k
    return visit(_type.t());
946
62.2k
  }
947
948
  bool visit(StructType const& _type) override
949
432k
  {
950
    // A struct is marked invalid only if all of its fields
951
    // are invalid. This is done to prevent an empty struct
952
    // being defined (which is a Solidity error).
953
432k
    for (auto const& t: _type.t())
954
481k
      if (visit(t))
955
415k
        return true;
956
16.2k
    return false;
957
432k
  }
958
959
  unsigned m_arrayDimensions;
960
  using AbiV2ProtoVisitor<bool>::visit;
961
};
962
963
/// Returns true if visited type is dynamically encoded by the abi coder,
964
/// false otherwise.
965
class DynParamVisitor: AbiV2ProtoVisitor<bool>
966
{
967
public:
968
23.6k
  DynParamVisitor() = default;
969
970
  bool visit(BoolType const&) override
971
12.7k
  {
972
12.7k
    return false;
973
12.7k
  }
974
975
  bool visit(IntegerType const&) override
976
7.59k
  {
977
7.59k
    return false;
978
7.59k
  }
979
980
  bool visit(FixedByteType const&) override
981
3.89k
  {
982
3.89k
    return false;
983
3.89k
  }
984
985
  bool visit(AddressType const&) override
986
8.38k
  {
987
8.38k
    return false;
988
8.38k
  }
989
990
  bool visit(DynamicByteArrayType const&) override
991
4.98k
  {
992
4.98k
    return true;
993
4.98k
  }
994
995
  bool visit(ArrayType const& _type) override
996
11.6k
  {
997
    // Return early if array spec is not well-formed
998
11.6k
    if (!ValidityVisitor().visit(_type))
999
1.89k
      return false;
1000
1001
    // Array is dynamically encoded if it at least one of the following is true
1002
    //   - at least one dimension is dynamically sized
1003
    //   - base type is dynamically encoded
1004
9.80k
    if (!_type.is_static())
1005
7.10k
      return true;
1006
2.69k
    else
1007
2.69k
      return visit(_type.t());
1008
9.80k
  }
1009
1010
  bool visit(StructType const& _type) override
1011
53.1k
  {
1012
    // Return early if empty struct
1013
53.1k
    if (!ValidityVisitor().visit(_type))
1014
1.51k
      return false;
1015
1016
    // Struct is dynamically encoded if at least one of its fields
1017
    // is dynamically encoded.
1018
51.6k
    for (auto const& t: _type.t())
1019
91.2k
      if (visit(t))
1020
13.3k
        return true;
1021
38.2k
    return false;
1022
51.6k
  }
1023
1024
  using AbiV2ProtoVisitor<bool>::visit;
1025
};
1026
1027
}