Coverage Report

Created: 2026-09-14 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/test/tools/ossfuzz/protoToAbiV2.h
Line
Count
Source
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
351
    m_isStateVar(true),
147
351
    m_counter(0),
148
351
    m_varCounter(0),
149
351
    m_returnValue(1),
150
351
    m_isLastDynParamRightPadded(false),
151
351
    m_structCounter(0),
152
351
    m_numStructsAdded(0)
153
351
  {
154
351
    m_random = std::make_unique<RandomEngine>(_seed);
155
351
  }
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
165
  {
164
165
    return m_test == Contract_Test::Contract_Test_CALLDATA_CODER;
165
165
  }
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
545
  {
358
545
    return m_varCounter++;
359
545
  }
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
545
  {
368
545
    std::string varName = _stateVar ? s_stateVarNamePrefix : s_localVarNamePrefix;
369
545
    return std::make_pair(
370
545
      varName + std::to_string(_varCounter),
371
545
      paramName() + std::to_string(_varCounter)
372
545
    );
373
545
  }
374
375
  std::string paramName()
376
545
  {
377
545
    switch (m_test)
378
545
    {
379
432
    case Contract_Test::Contract_Test_CALLDATA_CODER:
380
432
      return s_paramNamePrefix;
381
113
    case Contract_Test::Contract_Test_RETURNDATA_CODER:
382
113
      return s_localVarNamePrefix;
383
545
    }
384
545
  }
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
351
  {
390
351
    return m_isLastDynParamRightPadded;
391
351
  }
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
351
  {
398
351
    return Distribution(1, _n)(*m_random);
399
351
  }
400
  /// Generates boolean that has a bernoulli distribution defined by @param _p.
401
  bool randomBool(double _p)
402
2.70k
  {
403
2.70k
    return Bernoulli{_p}(*m_random);
404
2.70k
  }
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
442k
  virtual ~AbiV2ProtoVisitor() = default;
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::~AbiV2ProtoVisitor()
Line
Count
Source
459
285k
  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
156k
  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
545
  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
346k
  {
470
346k
    return visitValueType(_node);
471
346k
  }
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
41.4k
  {
470
41.4k
    return visitValueType(_node);
471
41.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::ValueType const&)
Line
Count
Source
469
61.2k
  {
470
61.2k
    return visitValueType(_node);
471
61.2k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
469
243k
  {
470
243k
    return visitValueType(_node);
471
243k
  }
472
  virtual T visit(NonValueType const& _node)
473
580k
  {
474
580k
    return visitNonValueType(_node);
475
580k
  }
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
35.3k
  {
474
35.3k
    return visitNonValueType(_node);
475
35.3k
  }
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
51.3k
  {
474
51.3k
    return visitNonValueType(_node);
475
51.3k
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
473
493k
  {
474
493k
    return visitNonValueType(_node);
475
493k
  }
476
  virtual T visit(Type const& _node)
477
1.03M
  {
478
1.03M
    return visitType(_node);
479
1.03M
  }
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visit(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
477
830k
  {
478
830k
    return visitType(_node);
479
830k
  }
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
76.7k
  {
478
76.7k
    return visitType(_node);
479
76.7k
  }
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
130k
  {
478
130k
    return visitType(_node);
479
130k
  }
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
34.6k
  {
499
34.6k
    return 8 * ((_x.width() % 32) + 1);
500
34.6k
  }
501
502
  static bool isIntSigned(IntegerType const& _x)
503
14.8k
  {
504
14.8k
    return _x.is_signed();
505
14.8k
  }
506
507
  static std::string getIntTypeAsString(IntegerType const& _x)
508
14.8k
  {
509
14.8k
    return ((isIntSigned(_x) ? "int" : "uint") + std::to_string(getIntWidth(_x)));
510
14.8k
  }
511
512
  static unsigned getFixedByteWidth(FixedByteType const& _x)
513
14.2k
  {
514
14.2k
    return (_x.width() % 32) + 1;
515
14.2k
  }
516
517
  static std::string getFixedByteTypeAsString(FixedByteType const& _x)
518
6.15k
  {
519
6.15k
    return "bytes" + std::to_string(getFixedByteWidth(_x));
520
6.15k
  }
521
522
  // Convert _counter to string and return its keccak256 hash
523
  static u256 hashUnsignedInt(unsigned _counter)
524
29.5k
  {
525
29.5k
    return util::keccak256(util::h256(_counter));
526
29.5k
  }
527
528
  static u256 maskUnsignedInt(unsigned _counter, unsigned _numMaskNibbles)
529
29.5k
  {
530
29.5k
    return hashUnsignedInt(_counter) & u256("0x" + std::string(_numMaskNibbles, 'f'));
531
29.5k
  }
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
29.5k
  {
537
29.5k
    return "0x" + toHex(maskUnsignedInt(_counter, _numMaskNibbles));
538
29.5k
  }
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
10.0k
  {
544
    // Increment modulo value by one in order to meet upper bound
545
10.0k
    return (_fuzz + _counter) % (s_maxArrayLength + 1);
546
10.0k
  }
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
6.27k
  {
552
6.27k
    return _fuzz % s_maxArrayLength + 1;
553
6.27k
  }
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
4.02k
  {
552
4.02k
    return _fuzz % s_maxArrayLength + 1;
553
4.02k
  }
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
2.25k
  {
552
2.25k
    return _fuzz % s_maxArrayLength + 1;
553
2.25k
  }
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
9.17k
  {
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
9.17k
    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
9.17k
    if (v % 2 == 1)
568
4.51k
      return v + 1;
569
4.66k
    else
570
4.66k
      return v;
571
9.17k
  }
572
protected:
573
T visitValueType(ValueType const& _type)
574
346k
{
575
346k
  switch (_type.value_type_oneof_case())
576
346k
  {
577
91.9k
  case ValueType::kInty:
578
91.9k
    return visit(_type.inty());
579
44.5k
  case ValueType::kByty:
580
44.5k
    return visit(_type.byty());
581
90.3k
  case ValueType::kAdty:
582
90.3k
    return visit(_type.adty());
583
99.4k
  case ValueType::kBoolty:
584
99.4k
    return visit(_type.boolty());
585
20.3k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
20.3k
    return T();
587
346k
  }
588
346k
}
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
41.4k
{
575
41.4k
  switch (_type.value_type_oneof_case())
576
41.4k
  {
577
14.8k
  case ValueType::kInty:
578
14.8k
    return visit(_type.inty());
579
6.14k
  case ValueType::kByty:
580
6.14k
    return visit(_type.byty());
581
8.89k
  case ValueType::kAdty:
582
8.89k
    return visit(_type.adty());
583
11.5k
  case ValueType::kBoolty:
584
11.5k
    return visit(_type.boolty());
585
0
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
0
    return T();
587
41.4k
  }
588
41.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> > > >::visitValueType(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
574
61.2k
{
575
61.2k
  switch (_type.value_type_oneof_case())
576
61.2k
  {
577
19.7k
  case ValueType::kInty:
578
19.7k
    return visit(_type.inty());
579
8.05k
  case ValueType::kByty:
580
8.05k
    return visit(_type.byty());
581
12.3k
  case ValueType::kAdty:
582
12.3k
    return visit(_type.adty());
583
15.1k
  case ValueType::kBoolty:
584
15.1k
    return visit(_type.boolty());
585
5.89k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
5.89k
    return T();
587
61.2k
  }
588
61.2k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitValueType(solidity::test::abiv2fuzzer::ValueType const&)
Line
Count
Source
574
243k
{
575
243k
  switch (_type.value_type_oneof_case())
576
243k
  {
577
57.3k
  case ValueType::kInty:
578
57.3k
    return visit(_type.inty());
579
30.3k
  case ValueType::kByty:
580
30.3k
    return visit(_type.byty());
581
69.1k
  case ValueType::kAdty:
582
69.1k
    return visit(_type.adty());
583
72.7k
  case ValueType::kBoolty:
584
72.7k
    return visit(_type.boolty());
585
14.4k
  case ValueType::VALUE_TYPE_ONEOF_NOT_SET:
586
14.4k
    return T();
587
243k
  }
588
243k
}
589
590
T visitNonValueType(NonValueType const& _type)
591
580k
{
592
580k
  switch (_type.nonvalue_type_oneof_case())
593
580k
  {
594
53.2k
  case NonValueType::kDynbytearray:
595
53.2k
    return visit(_type.dynbytearray());
596
65.4k
  case NonValueType::kArrtype:
597
65.4k
    return visit(_type.arrtype());
598
438k
  case NonValueType::kStype:
599
438k
    return visit(_type.stype());
600
22.6k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
22.6k
    return T();
602
580k
  }
603
580k
}
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
35.3k
{
592
35.3k
  switch (_type.nonvalue_type_oneof_case())
593
35.3k
  {
594
7.46k
  case NonValueType::kDynbytearray:
595
7.46k
    return visit(_type.dynbytearray());
596
9.16k
  case NonValueType::kArrtype:
597
9.16k
    return visit(_type.arrtype());
598
18.7k
  case NonValueType::kStype:
599
18.7k
    return visit(_type.stype());
600
0
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
0
    return T();
602
35.3k
  }
603
35.3k
}
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
51.3k
{
592
51.3k
  switch (_type.nonvalue_type_oneof_case())
593
51.3k
  {
594
9.16k
  case NonValueType::kDynbytearray:
595
9.16k
    return visit(_type.dynbytearray());
596
15.3k
  case NonValueType::kArrtype:
597
15.3k
    return visit(_type.arrtype());
598
23.7k
  case NonValueType::kStype:
599
23.7k
    return visit(_type.stype());
600
3.02k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
3.02k
    return T();
602
51.3k
  }
603
51.3k
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitNonValueType(solidity::test::abiv2fuzzer::NonValueType const&)
Line
Count
Source
591
493k
{
592
493k
  switch (_type.nonvalue_type_oneof_case())
593
493k
  {
594
36.6k
  case NonValueType::kDynbytearray:
595
36.6k
    return visit(_type.dynbytearray());
596
40.9k
  case NonValueType::kArrtype:
597
40.9k
    return visit(_type.arrtype());
598
396k
  case NonValueType::kStype:
599
396k
    return visit(_type.stype());
600
19.5k
  case NonValueType::NONVALUE_TYPE_ONEOF_NOT_SET:
601
19.5k
    return T();
602
493k
  }
603
493k
}
604
605
T visitType(Type const& _type)
606
1.03M
{
607
1.03M
  switch (_type.type_oneof_case())
608
1.03M
  {
609
346k
  case Type::kVtype:
610
346k
    return visit(_type.vtype());
611
580k
  case Type::kNvtype:
612
580k
    return visit(_type.nvtype());
613
110k
  case Type::TYPE_ONEOF_NOT_SET:
614
110k
    return T();
615
1.03M
  }
616
1.03M
}
solidity::test::abiv2fuzzer::AbiV2ProtoVisitor<bool>::visitType(solidity::test::abiv2fuzzer::Type const&)
Line
Count
Source
606
830k
{
607
830k
  switch (_type.type_oneof_case())
608
830k
  {
609
243k
  case Type::kVtype:
610
243k
    return visit(_type.vtype());
611
493k
  case Type::kNvtype:
612
493k
    return visit(_type.nvtype());
613
93.0k
  case Type::TYPE_ONEOF_NOT_SET:
614
93.0k
    return T();
615
830k
  }
616
830k
}
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
76.7k
{
607
76.7k
  switch (_type.type_oneof_case())
608
76.7k
  {
609
41.4k
  case Type::kVtype:
610
41.4k
    return visit(_type.vtype());
611
35.3k
  case Type::kNvtype:
612
35.3k
    return visit(_type.nvtype());
613
0
  case Type::TYPE_ONEOF_NOT_SET:
614
0
    return T();
615
76.7k
  }
616
76.7k
}
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
130k
{
607
130k
  switch (_type.type_oneof_case())
608
130k
  {
609
61.2k
  case Type::kVtype:
610
61.2k
    return visit(_type.vtype());
611
51.3k
  case Type::kNvtype:
612
51.3k
    return visit(_type.nvtype());
613
17.5k
  case Type::TYPE_ONEOF_NOT_SET:
614
17.5k
    return T();
615
130k
  }
616
130k
}
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
70.0k
    m_indentation(1),
628
70.0k
    m_structCounter(_structSuffix),
629
70.0k
    m_structStartCounter(_structSuffix),
630
70.0k
    m_structFieldCounter(0),
631
70.0k
    m_isLastDynParamRightPadded(false)
632
70.0k
  {}
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
545
  {
648
545
    return m_isLastDynParamRightPadded;
649
545
  }
650
  std::string structDef()
651
55.8k
  {
652
55.8k
    return m_structDef.str();
653
55.8k
  }
654
  unsigned numStructs()
655
55.8k
  {
656
55.8k
    return m_structCounter - m_structStartCounter;
657
55.8k
  }
658
  static bool arrayOfStruct(ArrayType const& _type)
659
2.37k
  {
660
2.37k
    Type const& baseType = _type.t();
661
2.37k
    if (baseType.has_nvtype() && baseType.nvtype().has_stype())
662
1.22k
      return true;
663
1.14k
    else if (baseType.has_nvtype() && baseType.nvtype().has_arrtype())
664
426
      return arrayOfStruct(baseType.nvtype().arrtype());
665
720
    else
666
720
      return false;
667
2.37k
  }
668
  std::string isabelleTypeString()
669
55.8k
  {
670
55.8k
    return m_structTupleString.stream.str();
671
55.8k
  }
672
private:
673
  struct StructTupleString
674
  {
675
70.0k
    StructTupleString() = default;
676
    unsigned index = 0;
677
    std::ostringstream stream;
678
    void start()
679
19.1k
    {
680
19.1k
      stream << "(";
681
19.1k
    }
682
    void end()
683
19.1k
    {
684
19.1k
      stream << ")";
685
19.1k
    }
686
    void addTypeStringToTuple(std::string& _typeString);
687
    void addArrayBracketToType(std::string& _arrayBracket);
688
  };
689
  void structDefinition(StructType const&);
690
691
  std::string indentation()
692
93.5k
  {
693
93.5k
    return std::string(m_indentation * 1, '\t');
694
93.5k
  }
695
  std::string lineString(std::string const& _line)
696
93.5k
  {
697
93.5k
    return indentation() + _line + "\n";
698
93.5k
  }
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
545
  {
728
545
    m_counter = m_counterStart = _counter;
729
545
    m_varName = _varName;
730
545
    m_paramName = _paramName;
731
545
    m_errorCode = m_errorStart = _errorStart;
732
545
    m_indentation = 2;
733
545
    m_stateVar = _stateVar;
734
545
    m_structCounter = m_structStart = _structCounter;
735
545
  }
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
545
  {
747
545
    return m_errorCode - m_errorStart;
748
545
  }
749
750
  unsigned counted()
751
545
  {
752
545
    return m_counter - m_counterStart;
753
545
  }
754
755
  unsigned structs()
756
0
  {
757
0
    return m_structCounter - m_structStart;
758
0
  }
759
760
  std::string isabelleValueString()
761
545
  {
762
545
    return m_valueStream.stream.str();
763
545
  }
764
private:
765
  struct ValueStream
766
  {
767
545
    ValueStream() = default;
768
    unsigned index = 0;
769
    std::ostringstream stream;
770
    void startStruct()
771
16.6k
    {
772
16.6k
      if (index >= 1)
773
8.04k
        stream << ",";
774
16.6k
      index = 0;
775
16.6k
      stream << "(";
776
16.6k
    }
777
    void endStruct()
778
16.6k
    {
779
16.6k
      stream << ")";
780
16.6k
    }
781
    void startArray()
782
9.40k
    {
783
9.40k
      if (index >= 1)
784
7.41k
        stream << ",";
785
9.40k
      index = 0;
786
9.40k
      stream << "[";
787
9.40k
    }
788
    void endArray()
789
9.40k
    {
790
9.40k
      stream << "]";
791
9.40k
      index++;
792
9.40k
    }
793
    void appendValue(std::string& _value);
794
  };
795
  std::string indentation()
796
151k
  {
797
151k
    return std::string(m_indentation * 1, '\t');
798
151k
  }
799
  unsigned counter()
800
74.5k
  {
801
74.5k
    return m_counter++;
802
74.5k
  }
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
86.3k
  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
64.5k
  {
852
64.5k
    return m_counter++;
853
64.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
255k
  ValidityVisitor(): m_arrayDimensions(0) {}
908
909
  bool visit(BoolType const&) override
910
59.0k
  {
911
59.0k
    return true;
912
59.0k
  }
913
914
  bool visit(IntegerType const&) override
915
48.0k
  {
916
48.0k
    return true;
917
48.0k
  }
918
919
  bool visit(FixedByteType const&) override
920
24.6k
  {
921
24.6k
    return true;
922
24.6k
  }
923
924
  bool visit(AddressType const&) override
925
58.9k
  {
926
58.9k
    return true;
927
58.9k
  }
928
929
  bool visit(DynamicByteArrayType const&) override
930
32.1k
  {
931
32.1k
    return true;
932
32.1k
  }
933
934
  bool visit(ArrayType const& _type) override
935
88.8k
  {
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
88.8k
    m_arrayDimensions++;
943
88.8k
    if (m_arrayDimensions > s_maxArrayDimensions)
944
1.20k
      return false;
945
87.6k
    return visit(_type.t());
946
88.8k
  }
947
948
  bool visit(StructType const& _type) override
949
478k
  {
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
478k
    for (auto const& t: _type.t())
954
553k
      if (visit(t))
955
459k
        return true;
956
19.0k
    return false;
957
478k
  }
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
30.1k
  DynParamVisitor() = default;
969
970
  bool visit(BoolType const&) override
971
13.6k
  {
972
13.6k
    return false;
973
13.6k
  }
974
975
  bool visit(IntegerType const&) override
976
9.26k
  {
977
9.26k
    return false;
978
9.26k
  }
979
980
  bool visit(FixedByteType const&) override
981
5.69k
  {
982
5.69k
    return false;
983
5.69k
  }
984
985
  bool visit(AddressType const&) override
986
10.1k
  {
987
10.1k
    return false;
988
10.1k
  }
989
990
  bool visit(DynamicByteArrayType const&) override
991
4.52k
  {
992
4.52k
    return true;
993
4.52k
  }
994
995
  bool visit(ArrayType const& _type) override
996
17.4k
  {
997
    // Return early if array spec is not well-formed
998
17.4k
    if (!ValidityVisitor().visit(_type))
999
2.46k
      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
14.9k
    if (!_type.is_static())
1005
11.3k
      return true;
1006
3.63k
    else
1007
3.63k
      return visit(_type.t());
1008
14.9k
  }
1009
1010
  bool visit(StructType const& _type) override
1011
58.5k
  {
1012
    // Return early if empty struct
1013
58.5k
    if (!ValidityVisitor().visit(_type))
1014
1.80k
      return false;
1015
1016
    // Struct is dynamically encoded if at least one of its fields
1017
    // is dynamically encoded.
1018
56.7k
    for (auto const& t: _type.t())
1019
106k
      if (visit(t))
1020
13.9k
        return true;
1021
42.8k
    return false;
1022
56.7k
  }
1023
1024
  using AbiV2ProtoVisitor<bool>::visit;
1025
};
1026
1027
}