mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
More clean up and bug fixes
This commit is contained in:
parent
89b5ac510b
commit
1b4bdb1996
@ -268,6 +268,28 @@ string SolLibraryFunction::str() const
|
||||
.render();
|
||||
}
|
||||
|
||||
unsigned SolBaseContract::functionIndex()
|
||||
{
|
||||
if (type() == BaseType::INTERFACE)
|
||||
return interface()->functionIndex();
|
||||
else
|
||||
{
|
||||
solAssert(type() == BaseType::CONTRACT, "Sol proto adaptor: Invalid base contract");
|
||||
return contract()->functionIndex();
|
||||
}
|
||||
}
|
||||
|
||||
string SolBaseContract::lastBaseName()
|
||||
{
|
||||
if (type() == BaseType::INTERFACE)
|
||||
return interface()->lastBaseName();
|
||||
else
|
||||
{
|
||||
solAssert(type() == BaseType::CONTRACT, "Sol proto adaptor: Invalid base contract");
|
||||
return contract()->lastBaseName();
|
||||
}
|
||||
}
|
||||
|
||||
SolBaseContract::BaseType SolBaseContract::type() const
|
||||
{
|
||||
if (holds_alternative<shared_ptr<SolInterface>>(m_base))
|
||||
@ -290,6 +312,17 @@ string SolBaseContract::str()
|
||||
}
|
||||
}
|
||||
|
||||
string SolBaseContract::name()
|
||||
{
|
||||
if (type() == BaseType::INTERFACE)
|
||||
return interface()->name();
|
||||
else
|
||||
{
|
||||
solAssert(type() == BaseType::CONTRACT, "Sol proto adaptor: Invalid base contract");
|
||||
return contract()->name();
|
||||
}
|
||||
}
|
||||
|
||||
SolBaseContract::SolBaseContract(ProtoBaseContract _base, string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||
{
|
||||
if (holds_alternative<Contract const*>(_base))
|
||||
@ -512,6 +545,19 @@ interface <programName><?inheritance> is <baseNames></inheritance> {
|
||||
.render();
|
||||
}
|
||||
|
||||
string SolContract::baseNames() const
|
||||
{
|
||||
ostringstream bases;
|
||||
string separator{};
|
||||
for (auto &b: m_baseContracts)
|
||||
{
|
||||
bases << separator << b->name();
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
return bases.str();
|
||||
}
|
||||
|
||||
bool SolContract::validTest() const
|
||||
{
|
||||
// Check if at least one contract has one valid test function
|
||||
@ -824,27 +870,27 @@ void SolContract::addFunctions(Contract const& _contract)
|
||||
|
||||
void SolContract::addBases(Contract const& _contract)
|
||||
{
|
||||
shared_ptr<SolBaseContract> base;
|
||||
for (auto &b: _contract.bases())
|
||||
{
|
||||
switch (b.contract_or_interface_oneof_case())
|
||||
{
|
||||
case ContractOrInterface::kC:
|
||||
m_baseContracts.push_back(
|
||||
make_shared<SolBaseContract>(
|
||||
SolBaseContract(&b.c(), newBaseName(), m_prng)
|
||||
)
|
||||
);
|
||||
base = make_shared<SolBaseContract>(SolBaseContract(&b.c(), newBaseName(), m_prng));
|
||||
m_baseContracts.push_back(base);
|
||||
break;
|
||||
case ContractOrInterface::kI:
|
||||
m_baseContracts.push_back(
|
||||
make_shared<SolBaseContract>(
|
||||
SolBaseContract(&b.i(), newBaseName(), m_prng)
|
||||
)
|
||||
);
|
||||
base = make_shared<SolBaseContract>(SolBaseContract(&b.i(), newBaseName(), m_prng));
|
||||
m_baseContracts.push_back(base);
|
||||
break;
|
||||
case ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET:
|
||||
break;
|
||||
}
|
||||
// Worst case, we override all base functions so we
|
||||
// increment derived contract's function index by
|
||||
// this amount.
|
||||
m_functionIndex += base->functionIndex();
|
||||
m_lastBaseName = base->lastBaseName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -889,7 +935,7 @@ string SolContract::contractOverrideStr() const
|
||||
}
|
||||
overriddenFunctions << Whiskers(R"(
|
||||
function <functionName>() <visibility> <stateMutability><?isVirtual> virtual</isVirtual>
|
||||
override<?multiple>(<baseNames>)</multiple> returns (uint)</isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||
override<?multiple>(<baseNames>)</multiple> returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||
("functionName", f.first->name())
|
||||
("visibility", functionVisibility(f.first->visibility()))
|
||||
("stateMutability", functionMutability(f.first->mutability()))
|
||||
@ -943,7 +989,7 @@ string SolContract::interfaceOverrideStr() const
|
||||
}
|
||||
overriddenFunctions << Whiskers(R"(
|
||||
function <functionName>() external <stateMutability>
|
||||
override<?multiple>(<baseNames>)</multiple> returns (uint)</isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||
override<?multiple>(<baseNames>)</multiple> returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||
("functionName", f.first->name())
|
||||
("stateMutability", functionMutability(f.first->mutability()))
|
||||
("multiple", f.second.size() > 1)
|
||||
@ -962,19 +1008,24 @@ string SolContract::str() const
|
||||
bases << b->str();
|
||||
|
||||
ostringstream functions;
|
||||
|
||||
// Print overridden functions
|
||||
functions << interfaceOverrideStr() << contractOverrideStr();
|
||||
|
||||
// Print non-overridden functions
|
||||
for (auto &f: m_contractFunctions)
|
||||
functions << f->str();
|
||||
|
||||
functions << interfaceOverrideStr() << contractOverrideStr();
|
||||
|
||||
return Whiskers(R"(
|
||||
<bases>
|
||||
<?isAbstract>abstract </isAbstract>contract <contractName> {
|
||||
<?isAbstract>abstract </isAbstract>contract <contractName><?inheritance> is <baseNames></inheritance> {
|
||||
<functions>
|
||||
})")
|
||||
("bases", bases.str())
|
||||
("isAbstract", abstract())
|
||||
("contractName", name())
|
||||
("inheritance", m_baseContracts.size() > 0)
|
||||
("baseNames", baseNames())
|
||||
("functions", functions.str())
|
||||
.render();
|
||||
}
|
||||
|
@ -253,6 +253,7 @@ struct SolBaseContract
|
||||
std::variant<std::vector<std::shared_ptr<SolContractFunction>>, std::vector<std::shared_ptr<SolInterfaceFunction>>>
|
||||
baseFunctions();
|
||||
BaseType type() const;
|
||||
std::string name();
|
||||
std::string str();
|
||||
std::shared_ptr<SolInterface> interface()
|
||||
{
|
||||
@ -262,6 +263,8 @@ struct SolBaseContract
|
||||
{
|
||||
return std::get<std::shared_ptr<SolContract>>(m_base);
|
||||
}
|
||||
unsigned functionIndex();
|
||||
std::string lastBaseName();
|
||||
|
||||
std::variant<std::shared_ptr<SolInterface>, std::shared_ptr<SolContract>> m_base;
|
||||
std::string m_baseName;
|
||||
@ -288,6 +291,7 @@ struct SolContract
|
||||
);
|
||||
|
||||
bool validTest() const;
|
||||
std::string baseNames() const;
|
||||
std::tuple<std::string, std::string, std::string> validContractTest();
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomTest();
|
||||
|
||||
|
@ -138,447 +138,19 @@ pragma solidity >=0.0;
|
||||
|
||||
string ProtoConverter::visit(ContractType const& _contractType)
|
||||
{
|
||||
m_mostDerivedAbstractContract = false;
|
||||
switch (_contractType.contract_type_oneof_case())
|
||||
{
|
||||
case ContractType::kC:
|
||||
m_mostDerivedAbstractContract = _contractType.c().abstract();
|
||||
m_mostDerivedProgram = MostDerivedProgram::CONTRACT;
|
||||
return visit(_contractType.c());
|
||||
case ContractType::kL:
|
||||
m_mostDerivedProgram = MostDerivedProgram::LIBRARY;
|
||||
return visit(_contractType.l());
|
||||
case ContractType::kI:
|
||||
m_mostDerivedProgram = MostDerivedProgram::INTERFACE;
|
||||
return visit(_contractType.i());
|
||||
case ContractType::CONTRACT_TYPE_ONEOF_NOT_SET:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
string ProtoConverter::mostDerivedInterfaceOverrides(Interface const& _interface)
|
||||
{
|
||||
ostringstream funcs;
|
||||
|
||||
for (auto base = _interface.bases().rbegin(); base != _interface.bases().rend(); base++)
|
||||
{
|
||||
for (auto& f: base->funcdef())
|
||||
{
|
||||
// An interface may override base interface's function
|
||||
bool override = pseudoRandomCoinFlip();
|
||||
if (!override)
|
||||
continue;
|
||||
funcs << overrideFunction(&f, false, false);
|
||||
}
|
||||
funcs << mostDerivedInterfaceOverrides(*base);
|
||||
}
|
||||
return funcs.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::mostDerivedContractOverrides(Interface const& _interface)
|
||||
{
|
||||
ostringstream funcs;
|
||||
|
||||
for (auto base = _interface.bases().rbegin(); base != _interface.bases().rend(); base++)
|
||||
{
|
||||
for (auto& f: base->funcdef())
|
||||
{
|
||||
bool override = pseudoRandomCoinFlip() || mostDerivedProgramAbstractContract();
|
||||
|
||||
/// We can arrive here from contract through other contracts and interfaces.
|
||||
/// We define most derived contract (MDC) as the most derived contract in
|
||||
/// the inheritence chain to which the visited interface belongs to.
|
||||
|
||||
/// When MDC is not abstract we must implement (with override) all
|
||||
/// interface functions that MDC inherits unless it has been implemented
|
||||
/// by some other contract in the inheritence chain that MDC also derives
|
||||
/// from.
|
||||
/// In other words, if an interface function has never been implemented
|
||||
/// thus far in the inheritence chain, it must be implemented.
|
||||
/// If it has already been implemented, it may be reimplemented provided
|
||||
/// it is virtual.
|
||||
/// When reimplementing, it may be revirtualized.
|
||||
|
||||
/// When MDC is abstract, we may or may not redeclare interface function.
|
||||
/// If interface function has been implemented in the inheritence chain,
|
||||
/// and we redeclare it, we must reimplement it.
|
||||
/// If inheritence function has not been implemented and we redeclare it,
|
||||
/// we may implement it.
|
||||
/// If we implement it, it may be marked virtual.
|
||||
/// If we don't implement it, it must be marked virtual.
|
||||
|
||||
/// . We may virtualize.
|
||||
/// We create a pair <interfaceFunction, virtualized> and add it to list of
|
||||
/// implemented interface functions.
|
||||
|
||||
/// When IAC is abstract:
|
||||
/// - we may redeclare
|
||||
/// - if redeclared, we may implement
|
||||
/// - if we do not implement redeclared function then:
|
||||
/// - we must override and virtualize
|
||||
/// - add to list of unimplemented interface functions
|
||||
/// - if we implement then:
|
||||
/// - we must override
|
||||
/// - we may virtualize
|
||||
/// - create a pair <interfaceFunction, virtualized> and add it to list of
|
||||
/// implemented interface functions.
|
||||
|
||||
|
||||
/// - ancestor contract is not abstract and this interface function
|
||||
/// has been implemented by some other contract in the traversal path
|
||||
/// that also virtualizes the function.
|
||||
/// When we override, we may mark it as virtual.
|
||||
|
||||
/// We may override when ancestor contract is abstract
|
||||
/// If ancestor contract is overriding, we may or may not implement it.
|
||||
/// If we do not implement it, we must mark it virtual since otherwise
|
||||
/// we are left with unimplementable function.
|
||||
/// If we implement it, we may mark it as virtual.
|
||||
string funcStr = visit(
|
||||
f,
|
||||
index++,
|
||||
override,
|
||||
programName(&*base)
|
||||
);
|
||||
|
||||
if (override)
|
||||
funcs << funcStr;
|
||||
}
|
||||
funcs << mostDerivedContractOverrides(*base);
|
||||
}
|
||||
return funcs.str();
|
||||
}
|
||||
|
||||
pair<bool, bool> ProtoConverter::contractFunctionParams(
|
||||
Contract const* _contract,
|
||||
ContractFunction const* _function
|
||||
)
|
||||
{
|
||||
// If contract is abstract, we may implement this function. If contract
|
||||
// is not abstract, we must implement this function.
|
||||
bool implement = !_contract->abstract() || pseudoRandomCoinFlip();
|
||||
// We may mark a non-overridden function as virtual.
|
||||
// We must mark an unimplemented abstract contract function as
|
||||
// virtual.
|
||||
bool virtualFunc = _function->virtualfunc() || (_contract->abstract() && !implement);
|
||||
return pair(implement, virtualFunc);
|
||||
}
|
||||
|
||||
pair<bool, bool> ProtoConverter::contractFunctionOverrideParams(
|
||||
Contract const* _base,
|
||||
Contract const* _derived,
|
||||
CIFunc _f
|
||||
)
|
||||
{
|
||||
bool baseAbstract = _base->abstract();
|
||||
bool derivedAbstract = _derived->abstract();
|
||||
|
||||
bool implement = false;
|
||||
bool revirtualize = false;
|
||||
|
||||
// There are four possibilities here:
|
||||
// 1. both base and derived are abstract,
|
||||
// 2. base abstract, derived not
|
||||
// 3. base not abstract, derived is
|
||||
// 4. both base and derived are not abstract
|
||||
if (baseAbstract && derivedAbstract)
|
||||
{
|
||||
// Case 1: Both base and derived are abstract
|
||||
// virtual base functions may be redeclared (with override)
|
||||
// if redeclared virtual base function has been implemented, it must be reimplemented but
|
||||
// may be revirtualized
|
||||
// if revirtualized, there is nothing to be changed in list of <ContractFunction, bool>
|
||||
// if not revirtualized, we changed the boolean to false in the list of implemented contract
|
||||
// functions.
|
||||
// if redeclared virtual base function has not been implemented, it may be implemented.
|
||||
// if it is implemented (with override), it may be revirtualized.
|
||||
// if it is not implemented, it must be marked virtual.
|
||||
// if virtual base function not redeclared, there is no status change
|
||||
bool virtualImplemented = contractFunctionImplemented(_base, _f);
|
||||
implement = virtualImplemented || pseudoRandomCoinFlip();
|
||||
revirtualize = (!implement && !virtualImplemented) || pseudoRandomCoinFlip();
|
||||
}
|
||||
else if (baseAbstract && !derivedAbstract)
|
||||
{
|
||||
// Case 2: Base abstract, derived not
|
||||
// If base function appears in list of unimplemented virtual contract functions, we
|
||||
// must implement it (with override). Remove from unimplemented virtual contract functions. We may
|
||||
// revirtualize. Add to list of implemented contract functions.
|
||||
|
||||
// Unimplemented virtual functions must be implemented (with override)
|
||||
|
||||
// Implemented virtual functions may be implemented (with override)
|
||||
|
||||
//
|
||||
}
|
||||
else if (!baseAbstract && derivedAbstract)
|
||||
{
|
||||
// Case 3: Base not abstract, derived is
|
||||
// All base functions are implemented. Base functions marked virtual may be overridden.
|
||||
// If they are overridden they must be reimplemented. They may be revirtualized.
|
||||
// Base functions that are not virtual may not be redeclared.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 4: Neither base nor derived are abstract
|
||||
// All base functions are implemented. Base functions marked virtual may be overridden.
|
||||
// If they are overridden they must be reimplemented. They may be revirtualized.
|
||||
// Base functions that are not virtual may not be redeclared.
|
||||
}
|
||||
return pair(implement, revirtualize);
|
||||
}
|
||||
|
||||
string ProtoConverter::traverseOverrides(Contract const& _contract)
|
||||
{
|
||||
ostringstream funcs;
|
||||
|
||||
for (auto base = _contract.bases().rbegin(); base != _contract.bases().rend(); base++)
|
||||
{
|
||||
if (base->contract_or_interface_oneof_case() == ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET)
|
||||
continue;
|
||||
|
||||
if (base->has_c())
|
||||
{
|
||||
for (auto& f: base->c().funcdef())
|
||||
{
|
||||
// We may redeclare virtual functions in base contract
|
||||
bool redeclareVirtual = f.virtualfunc() && pseudoRandomCoinFlip();
|
||||
// If base function is not virtual or if we choose to not
|
||||
// redeclare the virtual function, we skip to the next function
|
||||
// after incrementing the function index.
|
||||
if (!f.virtualfunc() || !redeclareVirtual)
|
||||
continue;
|
||||
|
||||
// Check if overridden function may be implemented/revirtualized
|
||||
// by the derived contract.
|
||||
auto [implement, revirtualize] = contractFunctionOverrideParams(
|
||||
&base->c(),
|
||||
&_contract,
|
||||
&f
|
||||
);
|
||||
funcs << overrideFunction(&f, revirtualize, implement);
|
||||
// Update contract function map
|
||||
m_contractFunctionMap[&_contract].push_back(CITuple(&f, implement, revirtualize));
|
||||
}
|
||||
// Override revirtualized functions.
|
||||
// TODO: Function that returns all revirtualized functions and their implementation
|
||||
// status.
|
||||
for (auto &tuple: m_contractFunctionMap[&base->c()])
|
||||
{
|
||||
auto function = get<0>(tuple);
|
||||
bool overrideRevirtualized = true;
|
||||
if (holds_alternative<ContractFunction const*>(function))
|
||||
{
|
||||
auto contractFunction = get<ContractFunction const*>(function);
|
||||
|
||||
auto [implementRevirtualized, revirtualizeRevirtualized] = contractFunctionOverrideParams(
|
||||
&base->c(),
|
||||
&_contract,
|
||||
get<0>(tuple)
|
||||
);
|
||||
funcs << visit(
|
||||
*contractFunction,
|
||||
index++,
|
||||
overrideRevirtualized,
|
||||
revirtualizeRevirtualized,
|
||||
implementRevirtualized,
|
||||
programName(&base->c())
|
||||
);
|
||||
}
|
||||
}
|
||||
// Traverse base
|
||||
funcs << traverseOverrides(base->c());
|
||||
}
|
||||
else if (base->has_i())
|
||||
{
|
||||
for (auto& f: base->i().funcdef())
|
||||
{
|
||||
bool implement = pseudoRandomCoinFlip();
|
||||
m_counter += base->i().funcdef_size();
|
||||
bool override = pseudoRandomCoinFlip();
|
||||
|
||||
if (_contract.abstract() && !implement && !override)
|
||||
continue;
|
||||
|
||||
funcs << overrideFunction(
|
||||
&f,
|
||||
!_contract.abstract() || implement,
|
||||
pseudoRandomCoinFlip() || (override && _contract.abstract())
|
||||
);
|
||||
}
|
||||
funcs << mostDerivedContractOverrides(base->i(), !_contract.abstract());
|
||||
}
|
||||
}
|
||||
return funcs.str();
|
||||
}
|
||||
|
||||
/// This function is called when root is interface.
|
||||
tuple<string, string, string> ProtoConverter::visitMostDerivedInterface(Interface const& _interface)
|
||||
{
|
||||
ostringstream bases;
|
||||
ostringstream baseNames;
|
||||
ostringstream funcs;
|
||||
|
||||
string separator{};
|
||||
for (auto &base: _interface.bases())
|
||||
{
|
||||
string baseStr = visit(base);
|
||||
if (baseStr.empty())
|
||||
continue;
|
||||
bases << baseStr;
|
||||
baseNames << separator
|
||||
<< programName(&base);
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
// First define overridden functions
|
||||
bool overrides = _interface.bases_size() > 0 && !baseNames.str().empty();
|
||||
if (overrides)
|
||||
funcs << mostDerivedInterfaceOverrides(_interface);
|
||||
|
||||
unsigned index = 0;
|
||||
// Define non-overridden functions
|
||||
for (auto &f: _interface.funcdef())
|
||||
funcs << registerAndVisitFunction(
|
||||
&_interface,
|
||||
&f,
|
||||
index++,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
return make_tuple(bases.str(), baseNames.str(), funcs.str());
|
||||
}
|
||||
|
||||
void ProtoConverter::registerFunctionName(CIL _program, CILFunc _function, unsigned _index)
|
||||
{
|
||||
string pName = programName(_program);
|
||||
string fName = createFunctionName(_program, _index);
|
||||
solAssert(!m_functionNameMap.count(_function), "Sol proto fuzzer: Duplicate function registration");
|
||||
m_functionNameMap.insert(pair(_function, fName));
|
||||
}
|
||||
|
||||
string ProtoConverter::registerAndVisitFunction(
|
||||
CIL _program,
|
||||
CILFunc _function,
|
||||
unsigned _index,
|
||||
bool _override,
|
||||
bool _virtual,
|
||||
bool _implement
|
||||
)
|
||||
{
|
||||
registerFunctionName(_program, _function, _index);
|
||||
return visit(_function, _override, _virtual, _implement);
|
||||
}
|
||||
|
||||
tuple<string, string, string> ProtoConverter::visitProgramHelper(CIL _program)
|
||||
{
|
||||
ostringstream bases;
|
||||
ostringstream funcs;
|
||||
ostringstream baseNames;
|
||||
|
||||
string pName = programName(_program);
|
||||
|
||||
string separator{};
|
||||
if (holds_alternative<Contract const*>(_program))
|
||||
{
|
||||
Contract const* contract = get<Contract const*>(_program);
|
||||
|
||||
for (auto &base: contract->bases())
|
||||
{
|
||||
string baseStr = visit(base);
|
||||
if (baseStr.empty())
|
||||
continue;
|
||||
bases << baseStr;
|
||||
baseNames << separator
|
||||
<< (base.has_c() ? programName(&base.c()) : programName(&base.i()));
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
// First define overridden functions
|
||||
bool overrides = contract->bases_size() > 0 && !baseNames.str().empty();
|
||||
if (overrides)
|
||||
{
|
||||
funcs << traverseOverrides(*contract);
|
||||
}
|
||||
|
||||
// Declare/define non-overridden functions
|
||||
unsigned index = 0;
|
||||
for (auto &f: contract->funcdef())
|
||||
{
|
||||
auto [implement, virtualize] = contractFunctionParams(contract, &f);
|
||||
|
||||
funcs << registerAndVisitFunction(
|
||||
_program,
|
||||
&f,
|
||||
index++,
|
||||
false,
|
||||
virtualize,
|
||||
implement
|
||||
);
|
||||
|
||||
// Update contract function map
|
||||
m_contractFunctionMap[contract].push_back(CITuple(&f, implement, virtualize));
|
||||
}
|
||||
}
|
||||
else if (holds_alternative<Interface const*>(_program))
|
||||
{
|
||||
// If we are here, it means most derived program is a contract.
|
||||
|
||||
auto interface = get<Interface const*>(_program);
|
||||
for (auto &base: interface->bases())
|
||||
{
|
||||
string baseStr = visit(base);
|
||||
if (baseStr.empty())
|
||||
continue;
|
||||
bases << baseStr;
|
||||
baseNames << separator
|
||||
<< programName(&base);
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
// First define overridden functions
|
||||
bool overrides = interface->bases_size() > 0 && !baseNames.str().empty();
|
||||
if (overrides)
|
||||
{
|
||||
funcs << mostDerivedContractOverrides(*interface, false);
|
||||
}
|
||||
|
||||
unsigned index = 0;
|
||||
// Declare non-overridden functions
|
||||
for (auto &f: interface->funcdef())
|
||||
funcs << registerAndVisitFunction(
|
||||
_program,
|
||||
&f,
|
||||
index++,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto library = get<Library const*>(_program);
|
||||
unsigned index = 0;
|
||||
for (auto &f: library->funcdef())
|
||||
funcs << registerAndVisitFunction(
|
||||
_program,
|
||||
&f,
|
||||
index++,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
return make_tuple(bases.str(), baseNames.str(), funcs.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
string ProtoConverter::visit(Contract const& _contract)
|
||||
{
|
||||
if (_contract.funcdef_size() == 0 && _contract.bases_size() == 0)
|
||||
@ -661,9 +233,6 @@ void ProtoConverter::openProgramScope(CIL _program)
|
||||
programNamePrefix = "L";
|
||||
string programName = programNamePrefix + to_string(m_numPrograms++);
|
||||
m_programNameMap.insert(pair(_program, programName));
|
||||
|
||||
if (holds_alternative<Contract const*>(_program))
|
||||
m_contractFunctionMap.insert(pair(get<Contract const*>(_program), vector<CITuple>{}));
|
||||
}
|
||||
|
||||
string ProtoConverter::programName(CIL _program)
|
||||
@ -676,12 +245,4 @@ unsigned ProtoConverter::randomNumber()
|
||||
{
|
||||
solAssert(m_randomGen, "Sol proto fuzzer: Uninitialized random number generator");
|
||||
return m_randomGen->operator()();
|
||||
}
|
||||
|
||||
#if 0
|
||||
string ProtoConverter::functionName(CILFunc _function)
|
||||
{
|
||||
solAssert(m_functionNameMap.count(_function), "Sol proto fuzzer: Unregistered function");
|
||||
return m_functionNameMap[_function];
|
||||
}
|
||||
#endif
|
||||
}
|
@ -46,32 +46,14 @@ public:
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
std::string protoToSolidity(Program const&);
|
||||
|
||||
/// @returns true if test calls a library function, false
|
||||
/// otherwise
|
||||
bool libraryTest() const;
|
||||
/// @returns name of the library under test
|
||||
std::string libraryName() const;
|
||||
private:
|
||||
enum MostDerivedProgram {
|
||||
CONTRACT,
|
||||
INTERFACE,
|
||||
LIBRARY
|
||||
};
|
||||
|
||||
/// Variant type that points to one of contract, interface, library protobuf messages
|
||||
using CIL = std::variant<Contract const*, Interface const*, Library const*>;
|
||||
/// Variant type that points to one of contract, interface, library function protobuf
|
||||
/// messages
|
||||
using CILFunc = std::variant<ContractFunction const*, InterfaceFunction const*, LibraryFunction const*>;
|
||||
/// Variant type that points to one of contract, interface protobuf messages
|
||||
using CI = std::variant<Contract const*, Interface const*>;
|
||||
/// Variant type that points to one of contract, interface function protobuf messages
|
||||
using CIFunc = std::variant<ContractFunction const*, InterfaceFunction const*>;
|
||||
/// Tuple of contract or interface function variant and a boolean stating whether
|
||||
/// the function is implemented (true) or not and a second boolean stating whether
|
||||
/// the function is virtual (true) or not.
|
||||
using CITuple = std::tuple<CIFunc, bool, bool>;
|
||||
/// Protobuf message visitors that accept a const reference to a protobuf message
|
||||
/// type and return its solidity translation.
|
||||
std::string visit(Program const&);
|
||||
@ -83,6 +65,8 @@ private:
|
||||
std::string programName(CIL _program);
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest();
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomContractTest();
|
||||
void openProgramScope(CIL _program);
|
||||
unsigned randomNumber();
|
||||
|
||||
bool emptyLibrary(Library const& _library)
|
||||
{
|
||||
@ -97,46 +81,10 @@ private:
|
||||
return m_contractTests.size() == 0;
|
||||
}
|
||||
|
||||
void openProgramScope(CIL _program);
|
||||
bool pseudoRandomCoinFlip()
|
||||
{
|
||||
return m_counter++ % 2 == 0;
|
||||
}
|
||||
bool mostDerivedProgramContract()
|
||||
{
|
||||
return m_mostDerivedProgram == MostDerivedProgram::CONTRACT;
|
||||
}
|
||||
bool mostDerivedProgramInterface()
|
||||
{
|
||||
return m_mostDerivedProgram == MostDerivedProgram::INTERFACE;
|
||||
}
|
||||
bool mostDerivedProgramAbstractContract()
|
||||
{
|
||||
return m_mostDerivedAbstractContract;
|
||||
}
|
||||
unsigned randomNumber();
|
||||
|
||||
unsigned m_numPrograms = 0;
|
||||
unsigned m_counter = 0;
|
||||
bool m_mostDerivedAbstractContract = false;
|
||||
bool m_libraryTest = false;
|
||||
std::shared_ptr<SolRandomNumGenerator> m_randomGen;
|
||||
|
||||
MostDerivedProgram m_mostDerivedProgram = MostDerivedProgram::CONTRACT;
|
||||
/// 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
|
||||
/// function belonging to the keyed contract, a boolean flag that is
|
||||
/// true when the function is implemented, false otherwise, and
|
||||
/// a second boolean flag that is true when the function is virtualized
|
||||
/// false otherwise.
|
||||
std::map<Contract const*, std::vector<CITuple>> m_contractFunctionMap;
|
||||
/// Map whose key is a const pointer to protobuf contract, interface or
|
||||
/// library function message type and whose value is the function name
|
||||
/// assigned to it.
|
||||
std::map<CILFunc, std::string> m_functionNameMap;
|
||||
std::map<CIL, std::string> m_programNameMap;
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user