mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
abiv2 proto fuzzer: Fuzz return data coding
This commit is contained in:
parent
efeee15d32
commit
9772cc44a0
@ -92,8 +92,13 @@ message TestFunction {
|
||||
}
|
||||
|
||||
message Contract {
|
||||
enum Test {
|
||||
CALLDATA_CODER = 1;
|
||||
RETURNDATA_CODER = 2;
|
||||
}
|
||||
required VarDecl state_vars = 1;
|
||||
required TestFunction testfunction = 2;
|
||||
required Test test = 3;
|
||||
}
|
||||
|
||||
package dev.test.abiv2fuzzer;
|
@ -114,7 +114,14 @@ template <typename T>
|
||||
pair<string, string> ProtoConverter::processType(T const& _type, bool _isValueType)
|
||||
{
|
||||
ostringstream local, global;
|
||||
auto [varName, paramName] = newVarNames(getNextVarCounter());
|
||||
auto [varName, paramName] = newVarNames(getNextVarCounter(), m_isStateVar);
|
||||
|
||||
// Add variable name to the argument list of coder function call
|
||||
if (m_argsCoder.str().empty())
|
||||
m_argsCoder << varName;
|
||||
else
|
||||
m_argsCoder << ", " << varName;
|
||||
|
||||
string location{};
|
||||
if (!m_isStateVar && !_isValueType)
|
||||
location = "memory";
|
||||
@ -177,6 +184,16 @@ pair<string, string> ProtoConverter::varDecl(
|
||||
_paramName,
|
||||
((m_varCounter == 1) ? Delimiter::SKIP : Delimiter::ADD)
|
||||
);
|
||||
appendTypes(
|
||||
_isValueType,
|
||||
typeStr,
|
||||
((m_varCounter == 1) ? Delimiter::SKIP : Delimiter::ADD)
|
||||
);
|
||||
appendTypedReturn(
|
||||
_isValueType,
|
||||
typeStr,
|
||||
((m_varCounter == 1) ? Delimiter::SKIP : Delimiter::ADD)
|
||||
);
|
||||
|
||||
// Update dyn param only if necessary
|
||||
if (tVisitor.isLastDynParamRightPadded())
|
||||
@ -259,6 +276,41 @@ void ProtoConverter::appendTypedParams(
|
||||
}
|
||||
}
|
||||
|
||||
void ProtoConverter::appendTypes(
|
||||
bool _isValueType,
|
||||
string const& _typeString,
|
||||
Delimiter _delimiter
|
||||
)
|
||||
{
|
||||
string qualifiedTypeString = (
|
||||
_isValueType ?
|
||||
_typeString :
|
||||
_typeString + " memory"
|
||||
);
|
||||
m_types << Whiskers(R"(<delimiter><type>)")
|
||||
("delimiter", delimiterToString(_delimiter))
|
||||
("type", qualifiedTypeString)
|
||||
.render();
|
||||
}
|
||||
|
||||
void ProtoConverter::appendTypedReturn(
|
||||
bool _isValueType,
|
||||
string const& _typeString,
|
||||
Delimiter _delimiter
|
||||
)
|
||||
{
|
||||
string qualifiedTypeString = (
|
||||
_isValueType ?
|
||||
_typeString :
|
||||
_typeString + " memory"
|
||||
);
|
||||
m_typedReturn << Whiskers(R"(<delimiter><type> <varName>)")
|
||||
("delimiter", delimiterToString(_delimiter))
|
||||
("type", qualifiedTypeString)
|
||||
("varName", "lv_" + to_string(m_varCounter - 1))
|
||||
.render();
|
||||
}
|
||||
|
||||
// Adds the qualifier "calldata" to non-value parameter of an external function.
|
||||
void ProtoConverter::appendTypedParamsExternal(
|
||||
bool _isValueType,
|
||||
@ -310,7 +362,6 @@ std::string ProtoConverter::typedParametersAsString(CalleeType _calleeType)
|
||||
}
|
||||
}
|
||||
|
||||
// Test function to be called externally.
|
||||
string ProtoConverter::visit(TestFunction const& _x, string const& _storageVarDefs)
|
||||
{
|
||||
// TODO: Support more than one but less than N local variables
|
||||
@ -320,38 +371,76 @@ string ProtoConverter::visit(TestFunction const& _x, string const& _storageVarDe
|
||||
string localVarDefs = localVarBuffers.second;
|
||||
|
||||
ostringstream testBuffer;
|
||||
string functionDecl = "function test() public returns (uint)";
|
||||
|
||||
string testFunction = Whiskers(R"(
|
||||
function test() public returns (uint) {
|
||||
<?calldata>return test_calldata_coding();</calldata>
|
||||
<?returndata>return test_returndata_coding();</returndata>
|
||||
})")
|
||||
("calldata", m_test == Contract_Test::Contract_Test_CALLDATA_CODER)
|
||||
("returndata", m_test == Contract_Test::Contract_Test_RETURNDATA_CODER)
|
||||
.render();
|
||||
|
||||
string functionDeclCalldata = "function test_calldata_coding() internal returns (uint)";
|
||||
string functionDeclReturndata = "function test_returndata_coding() internal returns (uint)";
|
||||
|
||||
testBuffer << Whiskers(R"(<structTypeDecl>
|
||||
<functionDecl> {
|
||||
<testFunction>
|
||||
<?calldata>
|
||||
<functionDeclCalldata> {
|
||||
<storageVarDefs>
|
||||
<localVarDefs>
|
||||
<testCode>
|
||||
})")
|
||||
<calldataTestCode>
|
||||
}
|
||||
<calldataHelperFuncs>
|
||||
</calldata>
|
||||
<?returndata>
|
||||
<functionDeclReturndata> {
|
||||
<returndataTestCode>
|
||||
}
|
||||
|
||||
<?varsPresent>
|
||||
function coder_returndata_external() external returns (<return_types>) {
|
||||
<storageVarDefs>
|
||||
<localVarDefs>
|
||||
return (<return_values>);
|
||||
}
|
||||
</varsPresent>
|
||||
</returndata>)")
|
||||
("testFunction", testFunction)
|
||||
("calldata", m_test == Contract_Test::Contract_Test_CALLDATA_CODER)
|
||||
("returndata", m_test == Contract_Test::Contract_Test_RETURNDATA_CODER)
|
||||
("calldataHelperFuncs", calldataHelperFunctions())
|
||||
("varsPresent", !m_types.str().empty())
|
||||
("structTypeDecl", structTypeDecl)
|
||||
("functionDecl", functionDecl)
|
||||
("functionDeclCalldata", functionDeclCalldata)
|
||||
("functionDeclReturndata", functionDeclReturndata)
|
||||
("storageVarDefs", _storageVarDefs)
|
||||
("localVarDefs", localVarDefs)
|
||||
("testCode", testCode(_x.invalid_encoding_length()))
|
||||
("calldataTestCode", testCallDataFunction(_x.invalid_encoding_length()))
|
||||
("returndataTestCode", testReturnDataFunction())
|
||||
("return_types", m_types.str())
|
||||
("return_values", m_argsCoder.str())
|
||||
.render();
|
||||
return testBuffer.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::testCode(unsigned _invalidLength)
|
||||
string ProtoConverter::testCallDataFunction(unsigned _invalidLength)
|
||||
{
|
||||
return Whiskers(R"(
|
||||
uint returnVal = this.coder_public(<parameterNames>);
|
||||
uint returnVal = this.coder_calldata_public(<argumentNames>);
|
||||
if (returnVal != 0)
|
||||
return returnVal;
|
||||
|
||||
returnVal = this.coder_external(<parameterNames>);
|
||||
returnVal = this.coder_calldata_external(<argumentNames>);
|
||||
if (returnVal != 0)
|
||||
return uint(200000) + returnVal;
|
||||
|
||||
<?atLeastOneVar>
|
||||
bytes memory argumentEncoding = abi.encode(<parameterNames>);
|
||||
bytes memory argumentEncoding = abi.encode(<argumentNames>);
|
||||
|
||||
returnVal = checkEncodedCall(
|
||||
this.coder_public.selector,
|
||||
this.coder_calldata_public.selector,
|
||||
argumentEncoding,
|
||||
<invalidLengthFuzz>,
|
||||
<isRightPadded>
|
||||
@ -360,7 +449,7 @@ string ProtoConverter::testCode(unsigned _invalidLength)
|
||||
return returnVal;
|
||||
|
||||
returnVal = checkEncodedCall(
|
||||
this.coder_external.selector,
|
||||
this.coder_calldata_external.selector,
|
||||
argumentEncoding,
|
||||
<invalidLengthFuzz>,
|
||||
<isRightPadded>
|
||||
@ -370,26 +459,32 @@ string ProtoConverter::testCode(unsigned _invalidLength)
|
||||
</atLeastOneVar>
|
||||
return 0;
|
||||
)")
|
||||
("parameterNames", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
|
||||
("argumentNames", m_argsCoder.str())
|
||||
("invalidLengthFuzz", std::to_string(_invalidLength))
|
||||
("isRightPadded", isLastDynParamRightPadded() ? "true" : "false")
|
||||
("atLeastOneVar", m_varCounter > 0)
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::helperFunctions()
|
||||
string ProtoConverter::testReturnDataFunction()
|
||||
{
|
||||
stringstream helperFuncs;
|
||||
helperFuncs << R"(
|
||||
function bytesCompare(bytes memory a, bytes memory b) internal pure returns (bool) {
|
||||
if(a.length != b.length)
|
||||
return false;
|
||||
for (uint i = 0; i < a.length; i++)
|
||||
if (a[i] != b[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return Whiskers(R"(
|
||||
<?varsPresent>
|
||||
(<varDecl>) = this.coder_returndata_external();
|
||||
<equality_checks>
|
||||
</varsPresent>
|
||||
return 0;
|
||||
)")
|
||||
("varsPresent", !m_typedReturn.str().empty())
|
||||
("varDecl", m_typedReturn.str())
|
||||
("equality_checks", m_checks.str())
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::calldataHelperFunctions()
|
||||
{
|
||||
stringstream calldataHelperFuncs;
|
||||
calldataHelperFuncs << R"(
|
||||
/// Accepts function selector, correct argument encoding, and length of
|
||||
/// invalid encoding and returns the correct and incorrect abi encoding
|
||||
/// for calling the function specified by the function selector.
|
||||
@ -452,19 +547,18 @@ string ProtoConverter::helperFunctions()
|
||||
if (success == true)
|
||||
return 400001;
|
||||
return 0;
|
||||
}
|
||||
)";
|
||||
})";
|
||||
|
||||
// These are callee functions that encode from storage, decode to
|
||||
// memory/calldata and check if decoded value matches storage value
|
||||
// return true on successful match, false otherwise
|
||||
helperFuncs << Whiskers(R"(
|
||||
function coder_public(<parameters_memory>) public pure returns (uint) {
|
||||
calldataHelperFuncs << Whiskers(R"(
|
||||
function coder_calldata_public(<parameters_memory>) public pure returns (uint) {
|
||||
<equality_checks>
|
||||
return 0;
|
||||
}
|
||||
|
||||
function coder_external(<parameters_calldata>) external pure returns (uint) {
|
||||
function coder_calldata_external(<parameters_calldata>) external pure returns (uint) {
|
||||
<equality_checks>
|
||||
return 0;
|
||||
}
|
||||
@ -473,6 +567,25 @@ string ProtoConverter::helperFunctions()
|
||||
("equality_checks", equalityChecksAsString())
|
||||
("parameters_calldata", typedParametersAsString(CalleeType::EXTERNAL))
|
||||
.render();
|
||||
|
||||
return calldataHelperFuncs.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::commonHelperFunctions()
|
||||
{
|
||||
stringstream helperFuncs;
|
||||
helperFuncs << R"(
|
||||
/// Compares bytes, returning true if they are equal and false otherwise.
|
||||
function bytesCompare(bytes memory a, bytes memory b) internal pure returns (bool) {
|
||||
if(a.length != b.length)
|
||||
return false;
|
||||
for (uint i = 0; i < a.length; i++)
|
||||
if (a[i] != b[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
)";
|
||||
|
||||
return helperFuncs.str();
|
||||
}
|
||||
|
||||
@ -481,6 +594,9 @@ void ProtoConverter::visit(Contract const& _x)
|
||||
string pragmas = R"(pragma solidity >=0.0;
|
||||
pragma experimental ABIEncoderV2;)";
|
||||
|
||||
// Record test spec
|
||||
m_test = _x.test();
|
||||
|
||||
// TODO: Support more than one but less than N state variables
|
||||
auto storageBuffers = visit(_x.state_vars());
|
||||
string storageVarDecls = storageBuffers.first;
|
||||
@ -499,7 +615,7 @@ pragma experimental ABIEncoderV2;)";
|
||||
ostringstream contractBody;
|
||||
contractBody << storageVarDecls
|
||||
<< testFunction
|
||||
<< helperFunctions();
|
||||
<< commonHelperFunctions();
|
||||
m_output << Whiskers(R"(<pragmas>
|
||||
<contractStart>
|
||||
<contractBody>
|
||||
@ -1085,4 +1201,4 @@ string ValueGetterVisitor::bytesArrayValueAsString(unsigned _counter, bool _isHe
|
||||
_counter,
|
||||
_isHexLiteral
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -19,84 +19,118 @@
|
||||
/**
|
||||
* Template of the solidity test program generated by this converter is as follows:
|
||||
*
|
||||
* pragma solidity >=0.0;
|
||||
* pragma experimental ABIEncoderV2;
|
||||
* pragma solidity >=0.0;
|
||||
* pragma experimental ABIEncoderV2;
|
||||
*
|
||||
* contract C {
|
||||
* // State variable
|
||||
* string x_0;
|
||||
* // Test function that is called by the VM.
|
||||
* function test() public returns (uint) {
|
||||
* // Local variable
|
||||
* bytes x_1 = "1";
|
||||
* x_0 = "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d";
|
||||
* uint returnVal = this.coder_public(x_0, x_1);
|
||||
* if (returnVal != 0)
|
||||
* return returnVal;
|
||||
* // Since the return codes in the public and external coder functions are identical
|
||||
* // we offset error code by a fixed amount (200000) for differentiation.
|
||||
* returnVal = this.coder_external(x_0, x_1);
|
||||
* if (returnVal != 0)
|
||||
* return 200000 + returnVal;
|
||||
* // Encode parameters
|
||||
* bytes memory argumentEncoding = abi.encode(<parameter_names>);
|
||||
* returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
* // Check if calls to coder_public meet expectations for correctly/incorrectly encoded data.
|
||||
* if (returnVal != 0)
|
||||
* return returnVal;
|
||||
* contract C {
|
||||
* // State variable
|
||||
* string sv_0;
|
||||
* // Test function that is called by the VM.
|
||||
* // There are 2 variations of this function: one returns
|
||||
* // the output of test_calldata_coding() and the other
|
||||
* // returns the output of test_returndata_coding(). The
|
||||
* // proto field called Test decides which one of the two
|
||||
* // are chosen for creating a test case.
|
||||
* function test() public returns (uint) {
|
||||
* // The protobuf field "Contract.test" decides which of
|
||||
* // the two internal functions "test_calldata_coding()"
|
||||
* // and "test_returndata_coding()" are called. Here,
|
||||
* // we assume that the protobuf field equals "CALLDATA_CODER"
|
||||
* return this.test_calldata_coding()
|
||||
* }
|
||||
*
|
||||
* returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
* // Check if calls to coder_external meet expectations for correctly/incorrectly encoded data.
|
||||
* // Offset return value to distinguish between failures originating from coder_public and coder_external.
|
||||
* if (returnVal != 0)
|
||||
* return uint(200000) + returnVal;
|
||||
* // Return zero if all checks pass.
|
||||
* return 0;
|
||||
* }
|
||||
* // The following function is generated if the protobuf field
|
||||
* // "Contract.test" is equal to "RETURNDATA_CODER".
|
||||
* function test_returndata_coding() internal returns (uint) {
|
||||
* string memory lv_0, bytes memory lv_1 = test_returndata_external();
|
||||
* if (lv_0 != 044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d)
|
||||
* return 1;
|
||||
* if (lv_1 != "1")
|
||||
* return 2;
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* /// Accepts function selector, correct argument encoding, and an invalid encoding length as input.
|
||||
* /// Returns a non-zero value if either call with correct encoding fails or call with incorrect encoding
|
||||
* /// succeeds. Returns zero if both calls meet expectation.
|
||||
* function checkEncodedCall(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
|
||||
* public returns (uint) {
|
||||
* ...
|
||||
* }
|
||||
* // The following function is generated if the protobuf field
|
||||
* // "Contract.test" is equal to "RETURNDATA_CODER".
|
||||
* function test_returndata_external() external returns (string memory, bytes memory)
|
||||
* {
|
||||
* sv_0 = "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d";
|
||||
* bytes memory lv_0 = "1";
|
||||
* return (sv_0, lv_0);
|
||||
* }
|
||||
*
|
||||
* /// Accepts function selector, correct argument encoding, and length of invalid encoding and returns
|
||||
* /// the correct and incorrect abi encoding for calling the function specified by the function selector.
|
||||
* function createEncoding(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
|
||||
* internal pure returns (bytes memory, bytes memory) {
|
||||
* ...
|
||||
* }
|
||||
* // The following function is generated if the protobuf field
|
||||
* // "Contract.test" is equal to "CALLDATA_CODER".
|
||||
* function test_calldata_coding() internal returns (uint) {
|
||||
* // Local variable
|
||||
* bytes lv_1 = "1";
|
||||
* sv_0 = "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d";
|
||||
* uint returnVal = this.coder_public(sv_0, lv_1);
|
||||
* if (returnVal != 0)
|
||||
* return returnVal;
|
||||
* // Since the return codes in the public and external coder functions are identical
|
||||
* // we offset error code by a fixed amount (200000) for differentiation.
|
||||
* returnVal = this.coder_external(sv_0, lv_1);
|
||||
* if (returnVal != 0)
|
||||
* return 200000 + returnVal;
|
||||
* // Encode parameters
|
||||
* bytes memory argumentEncoding = abi.encode(<parameter_names>);
|
||||
* returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
* // Check if calls to coder_public meet expectations for correctly/incorrectly encoded data.
|
||||
* if (returnVal != 0)
|
||||
* return returnVal;
|
||||
*
|
||||
* /// Compares two dynamically sized bytes arrays for equality.
|
||||
* function bytesCompare(bytes memory a, bytes memory b) internal pure returns (bool) {
|
||||
* ...
|
||||
* }
|
||||
* returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
* // Check if calls to coder_external meet expectations for correctly/incorrectly encoded data.
|
||||
* // Offset return value to distinguish between failures originating from coder_public and coder_external.
|
||||
* if (returnVal != 0)
|
||||
* return uint(200000) + returnVal;
|
||||
* // Return zero if all checks pass.
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* // Public function that is called by test() function. Accepts one or more arguments and returns
|
||||
* // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
|
||||
* function coder_public(string memory c_0, bytes memory c_1) public pure returns (uint) {
|
||||
* if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
|
||||
* return 1;
|
||||
* if (!bytesCompare(c_1, "1"))
|
||||
* return 2;
|
||||
* return 0;
|
||||
* }
|
||||
* /// Accepts function selector, correct argument encoding, and an invalid encoding length as input.
|
||||
* /// Returns a non-zero value if either call with correct encoding fails or call with incorrect encoding
|
||||
* /// succeeds. Returns zero if both calls meet expectation.
|
||||
* function checkEncodedCall(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
|
||||
* public returns (uint) {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* // External function that is called by test() function. Accepts one or more arguments and returns
|
||||
* // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
|
||||
* function coder_external(string calldata c_0, bytes calldata c_1) external pure returns (uint) {
|
||||
* if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
|
||||
* return 1;
|
||||
* if (!bytesCompare(c_1, "1"))
|
||||
* return 2;
|
||||
* return 0;
|
||||
* }
|
||||
* }
|
||||
* /// Accepts function selector, correct argument encoding, and length of invalid encoding and returns
|
||||
* /// the correct and incorrect abi encoding for calling the function specified by the function selector.
|
||||
* function createEncoding(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
|
||||
* internal pure returns (bytes memory, bytes memory) {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* /// Compares two dynamically sized bytes arrays for equality.
|
||||
* function bytesCompare(bytes memory a, bytes memory b) internal pure returns (bool) {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* // Public function that is called by test() function. Accepts one or more arguments and returns
|
||||
* // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
|
||||
* function coder_public(string memory c_0, bytes memory c_1) public pure returns (uint) {
|
||||
* if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
|
||||
* return 1;
|
||||
* if (!bytesCompare(c_1, "1"))
|
||||
* return 2;
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* // External function that is called by test() function. Accepts one or more arguments and returns
|
||||
* // a uint value (zero if abi en/decoding was successful, non-zero otherwise)
|
||||
* function coder_external(string calldata c_0, bytes calldata c_1) external pure returns (uint) {
|
||||
* if (!bytesCompare(bytes(c_0), "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"))
|
||||
* return 1;
|
||||
* if (!bytesCompare(c_1, "1"))
|
||||
* return 2;
|
||||
* return 0;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace test
|
||||
@ -242,6 +276,20 @@ private:
|
||||
Delimiter _delimiter = Delimiter::ADD
|
||||
);
|
||||
|
||||
/// Append types to typed stream used by returndata coders.
|
||||
void appendTypes(
|
||||
bool _isValueType,
|
||||
std::string const& _typeString,
|
||||
Delimiter _delimiter
|
||||
);
|
||||
|
||||
/// Append typed return value.
|
||||
void appendTypedReturn(
|
||||
bool _isValueType,
|
||||
std::string const& _typeString,
|
||||
Delimiter _delimiter
|
||||
);
|
||||
|
||||
/// Returns a Solidity variable declaration statement
|
||||
/// @param _type: string containing Solidity type of the
|
||||
/// variable to be declared.
|
||||
@ -262,11 +310,17 @@ private:
|
||||
/// Return comma separated typed function parameters as string
|
||||
std::string typedParametersAsString(CalleeType _calleeType);
|
||||
|
||||
/// Return Solidity helper functions as string
|
||||
std::string helperFunctions();
|
||||
/// Return commonly used Solidity helper functions as string
|
||||
std::string commonHelperFunctions();
|
||||
|
||||
/// Return top-level test code as string
|
||||
std::string testCode(unsigned _invalidLength);
|
||||
/// Return helper functions used to test calldata coding
|
||||
std::string calldataHelperFunctions();
|
||||
|
||||
/// Return top-level calldata coder test function as string
|
||||
std::string testCallDataFunction(unsigned _invalidLength);
|
||||
|
||||
/// Return top-level returndata coder test function as string
|
||||
std::string testReturnDataFunction();
|
||||
|
||||
/// Return the next variable count that is used for
|
||||
/// variable naming.
|
||||
@ -276,15 +330,30 @@ private:
|
||||
}
|
||||
|
||||
/// Return a pair of names for Solidity variable and the same variable when
|
||||
/// passed as a function parameter.
|
||||
static std::pair<std::string, std::string> newVarNames(unsigned _varCounter)
|
||||
/// passed either as a function parameter or used to store the tuple
|
||||
/// returned from a function.
|
||||
/// @param _varCounter: name suffix
|
||||
/// @param _stateVar: predicate that is true for state variables, false otherwise
|
||||
std::pair<std::string, std::string> newVarNames(unsigned _varCounter, bool _stateVar)
|
||||
{
|
||||
std::string varName = _stateVar ? s_stateVarNamePrefix : s_localVarNamePrefix;
|
||||
return std::make_pair(
|
||||
s_varNamePrefix + std::to_string(_varCounter),
|
||||
s_paramNamePrefix + std::to_string(_varCounter)
|
||||
varName + std::to_string(_varCounter),
|
||||
paramName() + std::to_string(_varCounter)
|
||||
);
|
||||
}
|
||||
|
||||
std::string paramName()
|
||||
{
|
||||
switch (m_test)
|
||||
{
|
||||
case Contract_Test::Contract_Test_CALLDATA_CODER:
|
||||
return s_paramNamePrefix;
|
||||
case Contract_Test::Contract_Test_RETURNDATA_CODER:
|
||||
return s_localVarNamePrefix;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the last dynamically encoded Solidity type is right
|
||||
/// padded, returning true if it is and false otherwise.
|
||||
bool isLastDynParamRightPadded()
|
||||
@ -303,6 +372,12 @@ private:
|
||||
/// Contains typed parameter list to be passed to callee functions
|
||||
std::ostringstream m_typedParamsExternal;
|
||||
std::ostringstream m_typedParamsPublic;
|
||||
/// Contains type stream to be used in returndata coder function
|
||||
/// signature
|
||||
std::ostringstream m_types;
|
||||
std::ostringstream m_typedReturn;
|
||||
/// Argument names to be passed to coder functions
|
||||
std::ostringstream m_argsCoder;
|
||||
/// Predicate that is true if we are in contract scope
|
||||
bool m_isStateVar;
|
||||
unsigned m_counter;
|
||||
@ -316,9 +391,12 @@ private:
|
||||
/// Struct counter
|
||||
unsigned m_structCounter;
|
||||
unsigned m_numStructsAdded;
|
||||
/// Enum stating abiv2 coder to be tested
|
||||
Contract_Test m_test;
|
||||
/// Prefixes for declared and parameterized variable names
|
||||
static auto constexpr s_varNamePrefix = "x_";
|
||||
static auto constexpr s_paramNamePrefix = "c_";
|
||||
static auto constexpr s_localVarNamePrefix = "lv_";
|
||||
static auto constexpr s_stateVarNamePrefix = "sv_";
|
||||
static auto constexpr s_paramNamePrefix = "p_";
|
||||
};
|
||||
|
||||
/// Visitor interface for Solidity protobuf types.
|
||||
@ -857,4 +935,4 @@ public:
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user