Added prelim support for contract inheritance tests and cleaned up proto converter

This commit is contained in:
Bhargava Shastry 2020-04-13 13:41:04 +02:00
parent f63552f4ca
commit 89b5ac510b
4 changed files with 565 additions and 270 deletions

View File

@ -21,8 +21,6 @@
#include <libsolutil/Whiskers.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <sstream>
using namespace solidity::test::solprotofuzzer::adaptor;
@ -173,6 +171,7 @@ SolContractFunction::SolContractFunction(
ContractFunction const& _function,
std::string _contractName,
std::string _functionName,
bool _implemented,
std::string _returnValue
)
{
@ -182,6 +181,7 @@ SolContractFunction::SolContractFunction(
m_mutability = mutabilityConverter(_function.mut());
m_virtual = _function.virtualfunc();
m_returnValue = _returnValue;
m_implemented = _implemented;
}
bool SolContractFunction::operator==(SolContractFunction const& _rhs) const
@ -198,8 +198,25 @@ bool SolContractFunction::operator!=(SolContractFunction const& _rhs) const
return name() != _rhs.name();
}
bool SolContractFunction::disallowed() const
{
// Private virtual functions are disallowed
if (visibility() == SolFunctionVisibility::PRIVATE && isVirtual())
return true;
// Private payable functions are disallowed
else if (visibility() == SolFunctionVisibility::PRIVATE && mutability() == SolFunctionStateMutability::PAYABLE)
return true;
// Internal payable functions are disallowed
else if (visibility() == SolFunctionVisibility::INTERNAL && mutability() == SolFunctionStateMutability::PAYABLE)
return true;
return false;
}
string SolContractFunction::str() const
{
if (disallowed())
return "";
string bodyStr = Whiskers(R"(
{
return <uint>;
@ -208,16 +225,14 @@ string SolContractFunction::str() const
.render();
return Whiskers(R"(
function <functionName>()<?isOverride> override</isOverride>
<?isVirtual> virtual</isVirtual> <visibility> <stateMutability>
function <functionName>()<?isVirtual> virtual</isVirtual> <visibility> <stateMutability>
returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
("functionName", name())
("isVirtual", isVirtual())
("isOverride", "_override")
("visibility", functionVisibility(visibility()))
("stateMutability", functionMutability(mutability()))
("body", bodyStr)
("isImplemented", "_implement")
("isImplemented", implemented())
.render();
}
@ -253,16 +268,37 @@ string SolLibraryFunction::str() const
.render();
}
SolBaseContract::BaseType SolBaseContract::type() const
{
if (holds_alternative<shared_ptr<SolInterface>>(m_base))
return BaseType::INTERFACE;
else
{
solAssert(holds_alternative<shared_ptr<SolContract>>(m_base), "Sol proto fuzzer: Invalid base contract");
return BaseType::CONTRACT;
}
}
string SolBaseContract::str()
{
switch (type())
{
case BaseType::INTERFACE:
return interface()->str();
case BaseType::CONTRACT:
return contract()->str();
}
}
SolBaseContract::SolBaseContract(ProtoBaseContract _base, string _name, shared_ptr<SolRandomNumGenerator> _prng)
{
if (auto c = get<Contract const*>(_base))
m_base.push_back(
make_shared<SolContract>(SolContract(*c, _name, _prng))
);
else if (auto i = get<Interface const*>(_base))
m_base.push_back(
make_shared<SolInterface>(SolInterface(*i, _name, _prng))
);
if (holds_alternative<Contract const*>(_base))
m_base = make_shared<SolContract>(SolContract(*get<Contract const*>(_base), _name, _prng));
else
{
solAssert(holds_alternative<Interface const*>(_base), "Sol proto adaptor: Invalid base contract");
m_base = make_shared<SolInterface>(SolInterface(*get<Interface const*>(_base), _name, _prng));
}
}
void SolInterface::overrideHelper(
@ -314,7 +350,7 @@ void SolInterface::overrideHelper(
// Use a pseudo-random coin flip to decide whether to override explicitly
// or not. Implicit override means that the overridden function is not
// redeclared with the override keyword.
bool explicitOverride = coinFlip();
bool explicitOverride = coinToss();
// If function has not been overridden, add new override pseudo-randomly
if (!multipleOverride)
m_overrideMap.insert(
@ -478,37 +514,49 @@ interface <programName><?inheritance> is <baseNames></inheritance> {
bool SolContract::validTest() const
{
return m_contractFunctionMap.size() > 0;
// Check if at least one contract has one valid test function
for (auto &c: m_contractFunctionMap)
if (c.second.size() > 1)
return true;
return false;
}
tuple<string, string, string> SolContract::pseudoRandomTest()
tuple<string, string, string> SolContract::validContractTest()
{
solAssert(m_contractFunctionMap.size() > 0, "Sol proto adaptor: Empty contract map");
string chosenContractName{};
string chosenFunctionName{};
string expectedOutput{};
unsigned numFunctions = m_contractFunctionMap.size();
unsigned contractIdx = randomNumber() % numFunctions;
unsigned numContracts = m_contractFunctionMap.size();
unsigned contractIdx = random() % numContracts;
unsigned functionIdx = 0;
unsigned mapIdx = 0;
for (auto &e: m_contractFunctionMap)
{
if (contractIdx == mapIdx)
{
chosenContractName = e.first;
functionIdx = random() % e.second.size();
unsigned functionMapIdx = 0;
for (auto &f: e.second)
// Recurse if chosen contract has no valid test cases
// We can be sure there is at least one contract with
// a valid test case because validTest() has been
// asserted by caller of this function.
if (e.second.size() == 0)
return validContractTest();
else
{
if (functionIdx == functionMapIdx)
chosenContractName = e.first;
functionIdx = random() % e.second.size();
unsigned functionMapIdx = 0;
for (auto &f: e.second)
{
chosenFunctionName = f.first;
expectedOutput = f.second;
break;
if (functionIdx == functionMapIdx)
{
chosenFunctionName = f.first;
expectedOutput = f.second;
break;
}
functionMapIdx++;
}
functionMapIdx++;
break;
}
break;
}
mapIdx++;
}
@ -517,29 +565,261 @@ tuple<string, string, string> SolContract::pseudoRandomTest()
return tuple(chosenContractName, chosenFunctionName, expectedOutput);
}
void SolContract::overrideHelper()
tuple<string, string, string> SolContract::pseudoRandomTest()
{
solAssert(validTest(), "Sol proto adaptor: No valid contract test cases");
return validContractTest();
}
void SolContract::interfaceFunctionOverride(
std::shared_ptr<SolInterface> _base,
std::shared_ptr<SolInterfaceFunction> _function
)
{
string functionName = _function->name();
auto mutability = _function->mutability();
// Check if two or more bases define this function
bool multipleOverride = false;
// If function has already been overridden, add
// new base to list of overridden bases
for (auto &m: m_overriddenInterfaceFunctions)
{
// Must override if two or more bases define the
// same function
if (m.first->operator==(*_function))
{
// Report error if state mutability of identically
// named functions differ
if (m.first->mutability() != mutability)
assertThrow(
false,
langutil::FuzzerError,
"Input specifies multiple function overrides with identical names"
" and parameter types but different mutability."
);
// Should interface function be implemented: May be but if not it must be marked virtual
// Should it be explicitly overridden: Yes
// Should it be marked virtual: May be
bool implement = abstract() ? coinToss() : true;
bool virtualize = coinToss();
if (abstract() && !implement)
virtualize = true;
// Add new base to list of overridden bases
m_overriddenInterfaceFunctions[m.first].push_back(
shared_ptr<IFunctionOverride>(
make_shared<IFunctionOverride>(
IFunctionOverride(
_base,
_function,
this,
implement,
virtualize,
true,
newReturnValue()
)
)
)
);
multipleOverride = true;
break;
}
}
// Use a pseudo-random coin toss to decide whether to override explicitly
// or not. Implicit override means that the overridden function is not
// redeclared with the override keyword.
bool explicitOverride = abstract() ? coinToss() : true;
// If function has not been overridden, add new override pseudo-randomly
// Should it be virtual: May be but only matters for explicit overrides
// Should it be implemented: If non abstract, otherwise may be
bool virtualize = explicitOverride ? coinToss() : false;
bool implement = abstract() ? coinToss() : true;
if (abstract() && explicitOverride && !implement)
virtualize = true;
if (!multipleOverride)
m_overriddenInterfaceFunctions.insert(
pair(
_function,
vector<shared_ptr<IFunctionOverride>>{
make_shared<IFunctionOverride>(
IFunctionOverride(
_base,
_function,
this,
implement,
virtualize,
explicitOverride,
newReturnValue()
)
)
}
)
);
}
void SolContract::contractFunctionOverride(
std::shared_ptr<SolContract> _base,
std::shared_ptr<SolContractFunction> _function
)
{
string functionName = _function->name();
auto mutability = _function->mutability();
auto visibility = _function->visibility();
// Check if two or more bases define this function
bool multipleOverride = false;
// If function has already been overridden, add
// new base to list of overridden bases
for (auto &m: m_overriddenContractFunctions)
{
// Must override if two or more bases define the
// same function
if (m.first->operator==(*_function))
{
// Report error if state mutability of identically
// named functions differ
if (m.first->mutability() != mutability || m.first->visibility() != visibility)
assertThrow(
false,
langutil::FuzzerError,
"Input specifies multiple contract function overrides with identical names"
" and parameter types but different mutability and/or visibility."
);
/* Case 1: Base and derived are abstract
* Case 2: Base and derived not abstract
* Case 3: Derived abstract, base not
* Case 4: Derived non abstract, base abstract
*/
bool implement = abstract() ? coinToss() : true;
bool virtualize = coinToss();
if (abstract() && !implement)
virtualize = true;
// Add new base to list of overridden bases
m_overriddenContractFunctions[m.first].push_back(
shared_ptr<CFunctionOverride>(
make_shared<CFunctionOverride>(
CFunctionOverride(
_base,
_function,
this,
implement,
virtualize,
true,
newReturnValue()
)
)
)
);
multipleOverride = true;
break;
}
}
bool implement;
if (_function->implemented())
implement = true;
else
implement = abstract() ? coinToss() : true;
bool virtualize = coinToss();
if (!implement && abstract())
virtualize = true;
bool explicitOverride = true;
if (_base->abstract() && !implement && abstract())
explicitOverride = coinToss();
if (!multipleOverride)
m_overriddenContractFunctions.insert(
pair(
_function,
vector<shared_ptr<CFunctionOverride>>{
make_shared<CFunctionOverride>(
CFunctionOverride(
_base,
_function,
this,
implement,
virtualize,
explicitOverride,
newReturnValue()
)
)
}
)
);
}
void SolContract::addOverrides()
{
for (auto &base: m_baseContracts)
{
// Check if base is contract or interface
if (base->type() == SolBaseContract::BaseType::INTERFACE)
{
// Override interface functions
for (auto &f: base->interface()->m_interfaceFunctions)
{
interfaceFunctionOverride(base->interface(), f);
}
// Override interface overrides
for (auto &m: base->interface()->m_overrideMap)
{
interfaceFunctionOverride(base->interface(), m.first);
}
}
else
{
solAssert(base->type() == SolBaseContract::BaseType::CONTRACT, "Sol proto fuzzer: Base contract neither interface nor contract");
// Override contract functions
for (auto &f: base->contract()->m_contractFunctions)
{
contractFunctionOverride(base->contract(), f);
}
// Override contract overrides
for (auto &m: base->contract()->m_overriddenContractFunctions)
{
for (auto &f: m.second)
contractFunctionOverride(base->contract(), f->baseFunction());
}
}
}
}
void SolContract::addFunctions(Contract const& _contract)
{
bool abs = abstract();
string contractName = name();
// Add contract to contract function map only if the contract
// is not abstract.
if (!abs)
m_contractFunctionMap.insert(pair(contractName, map<string, string>{}));
// Add functions
for (auto &f: _contract.funcdef())
m_contractFunctions.push_back(
make_unique<SolContractFunction>(
SolContractFunction(
f,
m_contractName,
newFunctionName(),
newReturnValue()
)
{
auto function = make_shared<SolContractFunction>(
SolContractFunction(
f,
contractName,
newFunctionName(),
(abs ? coinToss() : true),
newReturnValue()
)
);
m_contractFunctions.push_back(function);
// If contract is not abstract, add its public and external
// functions to contract function map.
if (!abs)
{
auto visibility = function->visibility();
string functionName = function->name();
string expectedOutput = function->returnValue();
// Register only public and external contract functions because only they can
// be called from a different contract.
if (visibility == SolFunctionVisibility::PUBLIC || visibility == SolFunctionVisibility::EXTERNAL)
{
solAssert(!m_contractFunctionMap[contractName].count(functionName), "Sol proto adaptor: Duplicate contract function");
m_contractFunctionMap[contractName].insert(pair(functionName, expectedOutput));
}
}
}
}
void SolContract::addBases(Contract const& _contract)
@ -550,14 +830,14 @@ void SolContract::addBases(Contract const& _contract)
{
case ContractOrInterface::kC:
m_baseContracts.push_back(
make_unique<SolBaseContract>(
make_shared<SolBaseContract>(
SolBaseContract(&b.c(), newBaseName(), m_prng)
)
);
break;
case ContractOrInterface::kI:
m_baseContracts.push_back(
make_unique<SolBaseContract>(
make_shared<SolBaseContract>(
SolBaseContract(&b.i(), newBaseName(), m_prng)
)
);
@ -568,9 +848,135 @@ void SolContract::addBases(Contract const& _contract)
}
}
string SolContract::contractOverrideStr() const
{
ostringstream overriddenFunctions;
for (auto &f: m_overriddenContractFunctions)
{
string bodyStr = Whiskers(R"(
{
return <uint>;
})")
("uint", f.second[0]->returnValue())
.render();
bool implemented = f.second[0]->implemented();
bool virtualized = f.second[0]->virtualized();
ostringstream overriddenBaseNames;
if (f.second.size() > 1)
{
string sep{};
for (auto &b: f.second)
{
overriddenBaseNames << Whiskers(R"(<sep><name>)")
("sep", sep)
("name", b->baseName())
.render();
if (sep.empty())
sep = ", ";
}
}
else
{
assertThrow(
f.second.size() == 1,
langutil::FuzzerError,
"Inconsistent override map"
);
if (!f.second[0]->explicitlyInherited())
continue;
}
overriddenFunctions << Whiskers(R"(
function <functionName>() <visibility> <stateMutability><?isVirtual> virtual</isVirtual>
override<?multiple>(<baseNames>)</multiple> returns (uint)</isImplemented><body><!isImplemented>;</isImplemented>)")
("functionName", f.first->name())
("visibility", functionVisibility(f.first->visibility()))
("stateMutability", functionMutability(f.first->mutability()))
("isVirtual", virtualized)
("multiple", f.second.size() > 1)
("baseNames", overriddenBaseNames.str())
("isImplemented", implemented)
("body", bodyStr)
.render();
}
return overriddenFunctions.str();
}
string SolContract::interfaceOverrideStr() const
{
ostringstream overriddenFunctions;
for (auto &f: m_overriddenInterfaceFunctions)
{
string bodyStr = Whiskers(R"(
{
return <uint>;
})")
("uint", f.second[0]->returnValue())
.render();
bool implemented = f.second[0]->implemented();
ostringstream overriddenBaseNames;
if (f.second.size() > 1)
{
string sep{};
for (auto &b: f.second)
{
overriddenBaseNames << Whiskers(R"(<sep><name>)")
("sep", sep)
("name", b->baseName())
.render();
if (sep.empty())
sep = ", ";
}
}
else
{
assertThrow(
f.second.size() == 1,
langutil::FuzzerError,
"Inconsistent override map"
);
if (!f.second[0]->explicitlyInherited())
continue;
}
overriddenFunctions << Whiskers(R"(
function <functionName>() external <stateMutability>
override<?multiple>(<baseNames>)</multiple> returns (uint)</isImplemented><body><!isImplemented>;</isImplemented>)")
("functionName", f.first->name())
("stateMutability", functionMutability(f.first->mutability()))
("multiple", f.second.size() > 1)
("baseNames", overriddenBaseNames.str())
("isImplemented", implemented)
("body", bodyStr)
.render();
}
return overriddenFunctions.str();
}
string SolContract::str() const
{
return "";
ostringstream bases;
for (auto &b: m_baseContracts)
bases << b->str();
ostringstream functions;
for (auto &f: m_contractFunctions)
functions << f->str();
functions << interfaceOverrideStr() << contractOverrideStr();
return Whiskers(R"(
<bases>
<?isAbstract>abstract </isAbstract>contract <contractName> {
<functions>
})")
("bases", bases.str())
("isAbstract", abstract())
("contractName", name())
("functions", functions.str())
.render();
}
SolContract::SolContract(
@ -662,50 +1068,25 @@ pair<string, string> SolLibrary::pseudoRandomTest()
return pair(chosenFunction, m_publicFunctionMap[chosenFunction]);
}
CFunctionOverride::CFunctionOverrideType CFunctionOverride::functionType() const
{
if (holds_alternative<unique_ptr<SolContractFunction const>>(m_function.second))
return CFunctionOverrideType::CONTRACT;
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
return CFunctionOverrideType::INTERFACE;
}
string CFunctionOverride::name() const
{
if (holds_alternative<unique_ptr<SolContractFunction const>>(m_function.second))
return get<unique_ptr<SolContractFunction const>>(m_function.second)->name();
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
return get<unique_ptr<SolInterfaceFunction const>>(m_function.second)->name();
}
bool CFunctionOverride::interfaceFunction() const
{
return functionType() == CFunctionOverrideType::INTERFACE;
}
bool CFunctionOverride::contractFunction() const
{
return functionType() == CFunctionOverrideType::CONTRACT;
return m_baseFunction->name();
}
SolFunctionVisibility CFunctionOverride::visibility() const
{
if (contractFunction())
return get<unique_ptr<SolContractFunction const>>(m_function.second)->visibility();
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
return SolFunctionVisibility::EXTERNAL;
return m_baseFunction->visibility();
}
SolFunctionStateMutability CFunctionOverride::mutability() const
{
if (contractFunction())
return get<unique_ptr<SolContractFunction const>>(m_function.second)->mutability();
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
return get<unique_ptr<SolInterfaceFunction const>>(m_function.second)->mutability();
return m_baseFunction->mutability();
}
string CFunctionOverride::str() const
{
solAssert(virtualized() || !implemented(), "Sol proto fuzzer: Invalid virtualization of contract function override");
string bodyStr = Whiskers(R"(
{
return <uint>;
@ -717,7 +1098,7 @@ string CFunctionOverride::str() const
function <functionName>() override <?isVirtual> virtual</isVirtual> <visibility> <stateMutability>
returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
("functionName", name())
("isVirtual", virtualized() || !implemented())
("isVirtual", virtualized())
("visibility", functionVisibility(visibility()))
("stateMutability", functionMutability(mutability()))
("body", bodyStr)
@ -725,37 +1106,10 @@ string CFunctionOverride::str() const
.render();
}
//string CFunctionOverride::commaSeparatedBaseNames()
//{
// ostringstream baseNames;
// string separator{};
// for (auto &override: m_function)
// {
// auto base = override.first;
// string baseName;
// if (auto b = get<SolInterface const*>(base))
// baseName = b->name();
// else
// baseName = get<SolContract const*>(base)->name();
//
// baseNames << Whiskers(R"(<sep><base>)")
// ("sep", separator)
// ("base", baseName)
// .render();
// if (separator.empty())
// separator = ", ";
// }
// return baseNames.str();
//}
//string CFunctionOverride::baseName() const
//{
// auto base = m_function.first;
// if (contractFunction())
// return get<shared_ptr<SolContract const>>(base)->name();
// solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
// return get<shared_ptr<SolInterface const>>(base)->name();
//}
string CFunctionOverride::baseName() const
{
return m_baseContract->name();
}
IFunctionOverride::IFunctionOverride(
std::shared_ptr<SolInterface const> _baseInterface,

View File

@ -115,10 +115,12 @@ struct SolContractFunction
ContractFunction const& _function,
std::string _contractName,
std::string _functionName,
bool _implement,
std::string _returnValue
);
bool operator==(SolContractFunction const& _rhs) const;
bool operator!=(SolContractFunction const& _rhs) const;
bool disallowed() const;
std::string str() const;
std::string name() const
@ -133,6 +135,10 @@ struct SolContractFunction
{
return m_virtual;
}
bool implemented() const
{
return m_implemented;
}
std::string returnValue() const
{
return m_returnValue;
@ -152,6 +158,7 @@ struct SolContractFunction
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
bool m_virtual = false;
std::string m_returnValue;
bool m_implemented = true;
};
struct SolLibraryFunction
@ -235,9 +242,28 @@ struct SolLibrary
struct SolBaseContract
{
enum BaseType
{
INTERFACE,
CONTRACT
};
SolBaseContract(ProtoBaseContract _base, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
BaseContracts m_base;
std::variant<std::vector<std::shared_ptr<SolContractFunction>>, std::vector<std::shared_ptr<SolInterfaceFunction>>>
baseFunctions();
BaseType type() const;
std::string str();
std::shared_ptr<SolInterface> interface()
{
return std::get<std::shared_ptr<SolInterface>>(m_base);
}
std::shared_ptr<SolContract> contract()
{
return std::get<std::shared_ptr<SolContract>>(m_base);
}
std::variant<std::shared_ptr<SolInterface>, std::shared_ptr<SolContract>> m_base;
std::string m_baseName;
std::shared_ptr<SolRandomNumGenerator> m_prng;
};
@ -247,17 +273,33 @@ struct SolContract
SolContract(Contract const& _contract, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
std::string str() const;
std::string interfaceOverrideStr() const;
std::string contractOverrideStr() const;
void addFunctions(Contract const& _contract);
void addBases(Contract const& _contract);
void addOverrides();
void overrideHelper();
void interfaceFunctionOverride(
std::shared_ptr<SolInterface> _base,
std::shared_ptr<SolInterfaceFunction> _function
);
void contractFunctionOverride(
std::shared_ptr<SolContract> _base,
std::shared_ptr<SolContractFunction> _function
);
bool validTest() const;
std::tuple<std::string, std::string, std::string> validContractTest();
std::tuple<std::string, std::string, std::string> pseudoRandomTest();
unsigned randomNumber() const
{
return m_prng->operator()();
}
bool coinToss() const
{
return randomNumber() % 2 == 0;
}
std::string name() const
{
return m_contractName;
@ -295,7 +337,8 @@ struct SolContract
std::string m_lastBaseName;
std::vector<std::shared_ptr<SolContractFunction>> m_contractFunctions;
std::vector<std::shared_ptr<SolBaseContract>> m_baseContracts;
std::vector<std::shared_ptr<CFunctionOverride>> m_overriddenFunctions;
std::map<std::shared_ptr<SolContractFunction>, std::vector<std::shared_ptr<CFunctionOverride>>> m_overriddenContractFunctions;
std::map<std::shared_ptr<SolInterfaceFunction>, std::vector<std::shared_ptr<IFunctionOverride>>> m_overriddenInterfaceFunctions;
/// Maps non abstract contract name to list of publicly exposed function name
/// and their expected output
std::map<std::string, std::map<std::string, std::string>> m_contractFunctionMap;
@ -320,7 +363,7 @@ struct SolInterface
return m_prng->operator()();
}
bool coinFlip() const
bool coinToss() const
{
return randomNumber() % 2 == 0;
}
@ -396,42 +439,36 @@ struct SolInterface
struct CFunctionOverride
{
CFunctionOverride(
BaseContracts _base,
OverrideFunction _function,
bool _implemented,
bool _virtualized,
bool _redeclared,
std::string _returnValue
)
{
m_function = std::make_pair(_base, std::move(_function));
m_implemented = _implemented;
m_virtualized = _virtualized;
m_redeclared = _redeclared;
m_returnValue = _returnValue;
}
enum class DerivedType
{
ABSTRACTCONTRACT,
CONTRACT
};
enum class CFunctionOverrideType
CFunctionOverride(
std::shared_ptr<SolContract> _base,
std::shared_ptr<SolContractFunction> _function,
SolContract* _derived,
bool _implemented,
bool _virtualized,
bool _explicitInheritance,
std::string _returnValue
)
{
INTERFACE,
CONTRACT
};
m_baseContract = _base;
m_baseFunction = _function;
m_derivedProgram = _derived;
m_implemented = _implemented;
m_virtualized = _virtualized;
m_explicitlyInherited = _explicitInheritance;
m_returnValue = _returnValue;
m_derivedType = _derived->abstract() ? DerivedType::ABSTRACTCONTRACT : DerivedType::CONTRACT;
}
std::string str() const;
std::string name() const;
CFunctionOverrideType functionType() const;
bool interfaceFunction() const;
bool contractFunction() const;
SolFunctionVisibility visibility() const;
@ -442,17 +479,30 @@ struct CFunctionOverride
std::string baseName() const;
/// Overridden function
OverrideCFunction m_function;
/// Flag that is true if overridden function is implemented
bool m_implemented = true;
/// Flag that is true if overridden function is marked virtual
std::shared_ptr<SolContract> baseContract() const
{
return m_baseContract;
}
std::shared_ptr<SolContractFunction> baseFunction() const
{
return m_baseFunction;
}
std::shared_ptr<SolContract> m_baseContract;
std::shared_ptr<SolContractFunction> m_baseFunction;
SolContract* m_derivedProgram;
/// Flag that is true if overridden function is implemented in derived contract
bool m_implemented = false;
/// Flag that is true if overridden function implemented in derived contract is
/// marked virtual
bool m_virtualized = false;
/// Flag that is true if overridden function is redeclared but not implemented
bool m_redeclared = false;
/// The uint value to be returned by the overridden function if it is
/// implemented
bool m_explicitlyInherited = false;
/// The uint value to be returned if the overridden interface function is implemented
std::string m_returnValue;
DerivedType m_derivedType;
bool implemented() const
{
@ -464,9 +514,9 @@ struct CFunctionOverride
return m_virtualized;
}
bool redeclared() const
bool explicitlyInherited() const
{
return m_redeclared;
return m_explicitlyInherited;
}
std::string returnValue() const
@ -518,6 +568,21 @@ struct IFunctionOverride
std::string interfaceStr() const;
std::string contractStr() const;
void setImplement()
{
m_implemented = true;
}
void setVirtual()
{
m_virtualized = true;
}
void setExplicitInherit()
{
m_explicitlyInherited = true;
}
bool implemented() const
{
return m_implemented;

View File

@ -76,7 +76,6 @@ string ProtoConverter::visit(TestContract const& _testContract)
testCode = Whiskers(R"(
return 0;)")
.render();
#if 0
else
{
auto testTuple = pseudoRandomContractTest();
@ -90,7 +89,6 @@ string ProtoConverter::visit(TestContract const& _testContract)
("expectedOutput", get<2>(testTuple))
.render();
}
#endif
break;
}
@ -146,8 +144,7 @@ string ProtoConverter::visit(ContractType const& _contractType)
case ContractType::kC:
m_mostDerivedAbstractContract = _contractType.c().abstract();
m_mostDerivedProgram = MostDerivedProgram::CONTRACT;
// return visit(_contractType.c());
return "";
return visit(_contractType.c());
case ContractType::kL:
m_mostDerivedProgram = MostDerivedProgram::LIBRARY;
return visit(_contractType.l());
@ -159,45 +156,6 @@ string ProtoConverter::visit(ContractType const& _contractType)
}
}
string ProtoConverter::visit(ContractOrInterface const& _contractOrInterface)
{
switch (_contractOrInterface.contract_or_interface_oneof_case())
{
case ContractOrInterface::kC:
// return visit(_contractOrInterface.c());
return "";
case ContractOrInterface::kI:
// return visit(_contractOrInterface.i());
return "";
case ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET:
return "";
}
}
bool ProtoConverter::contractFunctionImplemented(
Contract const* _contract,
CIFunc _function
)
{
auto v = m_contractFunctionMap[_contract];
for (auto &e: v)
if (get<0>(e) == _function)
return get<1>(e);
return false;
}
bool ProtoConverter::contractFunctionVirtual(
Contract const* _contract,
CIFunc _function
)
{
auto v = m_contractFunctionMap[_contract];
for (auto &e: v)
if (get<0>(e) == _function)
return get<2>(e);
return false;
}
#if 0
string ProtoConverter::mostDerivedInterfaceOverrides(Interface const& _interface)
{
@ -721,23 +679,6 @@ unsigned ProtoConverter::randomNumber()
}
#if 0
bool ProtoConverter::disallowedContractFunction(SolContractFunction const& _contractFunction, bool _isVirtual)
{
string visibility = functionVisibility(_contractFunction.m_visibility);
string mutability = functionMutability(_contractFunction.m_mutability);
// Private virtual functions are disallowed
if (visibility == "private" && _isVirtual)
return true;
// Private payable functions are disallowed
else if (visibility == "private" && mutability == "payable")
return true;
// Internal payable functions are disallowed
else if (visibility == "internal" && mutability == "payable")
return true;
return false;
}
string ProtoConverter::functionName(CILFunc _function)
{
solAssert(m_functionNameMap.count(_function), "Sol proto fuzzer: Unregistered function");

View File

@ -77,50 +77,10 @@ private:
std::string visit(Program const&);
std::string visit(TestContract const&);
std::string visit(ContractType const&);
std::string visit(ContractOrInterface const&);
std::string visit(Interface const& _interface);
/// Visitor for most derived interface messages.
/// @param _interface is a const reference to interface protobuf message
/// @returns a 3-tuple containing Solidity translation of all base contracts
/// this interface derives from, names of all base contracts, and the Solidity
/// translation of this interface.
std::tuple<std::string, std::string, std::string>
visitMostDerivedInterface(Interface const& _interface);
std::string visit(Contract const&);
/// Define overrides for most derived interface.
std::string mostDerivedInterfaceOverrides(Interface const& _interface);
/// Define overrides for most derived contract.
std::string mostDerivedContractOverrides(Interface const& _interface);
std::string traverseOverrides(Contract const&);
std::string registerAndVisitFunction(
CIL _program,
CILFunc _func,
unsigned _index,
bool _override,
bool _virtual,
bool _implement
);
std::string overrideFunction(CILFunc _function, bool _virtual, bool _implement);
std::pair<bool, bool> contractFunctionParams(
Contract const* _contract,
ContractFunction const* _function
);
std::string visit(CILFunc _function, bool _override, bool _virtual, bool _implement);
std::string visit(Library const&);
std::string visit(Library const& _library);
std::string visit(Contract const& _contract);
std::string programName(CIL _program);
std::string createFunctionName(CIL _program, unsigned _index);
std::string functionName(CILFunc _function);
void registerFunctionName(CIL _program, CILFunc _function, unsigned _index);
std::tuple<std::string, std::string, std::string> visitProgramHelper(CIL _program);
bool contractFunctionImplemented(Contract const* _contract, CIFunc _function);
bool contractFunctionVirtual(Contract const* _contract, CIFunc _function);
std::tuple<bool, bool, bool> mostDerivedContractOverrideParams();
std::pair<bool, bool> contractFunctionOverrideParams(
Contract const* _base,
Contract const* _derived,
CIFunc _baseFunc
);
std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest();
std::tuple<std::string, std::string, std::string> pseudoRandomContractTest();
@ -156,10 +116,6 @@ private:
}
unsigned randomNumber();
#if 0
static bool disallowedContractFunction(SolContractFunction const& _contractFunction, bool _isVirtual);
#endif
unsigned m_numPrograms = 0;
unsigned m_counter = 0;
bool m_mostDerivedAbstractContract = false;
@ -167,15 +123,6 @@ private:
std::shared_ptr<SolRandomNumGenerator> m_randomGen;
MostDerivedProgram m_mostDerivedProgram = MostDerivedProgram::CONTRACT;
/// Map whose key is pointer to protobuf interface message
/// and whose value is its contract name
std::map<Interface const*, std::string> m_interfaceNameMap;
/// Map whose key is pointer to protobuf contract message
/// and whose value is its contract name
std::map<Contract const*, std::string> m_contractNameMap;
/// Map whose key is library name and whose value is the
/// number of implemented functions in it.
std::map<std::string, unsigned> m_libraryFuncMap;
/// Map whose key is a const pointer to protobuf contract
/// message and whose value is a list of 3-tuples that
/// store a const pointer to a protobuf interface or contract
@ -189,21 +136,9 @@ private:
/// assigned to it.
std::map<CILFunc, std::string> m_functionNameMap;
std::map<CIL, std::string> m_programNameMap;
/// Map whose key is a const pointer to protobuf contract or interface
/// function message type and whose value is a pair of const pointer to
/// protobuf contract or interface it belongs to and its declaration
/// position (which is an unsigned integer that starts from 0).
std::map<CIFunc, std::pair<CI, unsigned>> m_functionProgramMap;
std::map<CI, std::vector<std::pair<CIFunc, std::string>>> m_programFunctionNameMap;
std::vector<std::tuple<std::string, std::string, std::string>> m_libraryTests;
std::vector<std::tuple<std::string, std::string, std::string>> m_contractTests;
std::string m_libraryName;
static auto constexpr s_interfaceFunctionPrefix = "i";
static auto constexpr s_libraryFunctionPrefix = "l";
static auto constexpr s_contractFunctionPrefix = "c";
static auto constexpr s_functionPrefix = "func";
};
}