mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Made proto spec a bit leaner and started work on contracts
This commit is contained in:
parent
3ef6e09258
commit
515939670d
@ -186,12 +186,16 @@ SolContractFunction::SolContractFunction(
|
||||
|
||||
bool SolContractFunction::operator==(SolContractFunction const& _rhs) const
|
||||
{
|
||||
return this->m_visibility == _rhs.m_visibility && this->m_mutability == _rhs.m_mutability;
|
||||
// TODO: Consider function parameters in addition to name once they are
|
||||
// implemented.
|
||||
return name() == _rhs.name();
|
||||
}
|
||||
|
||||
bool SolContractFunction::operator!=(SolContractFunction const& _rhs) const
|
||||
{
|
||||
return this->m_visibility != _rhs.m_visibility || this->m_mutability != _rhs.m_mutability;
|
||||
// TODO: Consider function parameters in addition to name once they are
|
||||
// implemented.
|
||||
return name() != _rhs.name();
|
||||
}
|
||||
|
||||
string SolContractFunction::str() const
|
||||
@ -352,9 +356,6 @@ void SolInterface::addBases(Interface const& _interface)
|
||||
{
|
||||
auto base = make_shared<SolInterface>(SolInterface(b, newBaseName(), m_prng));
|
||||
m_baseInterfaces.push_back(base);
|
||||
#if 0
|
||||
cout << "Added " << base->name() << " as base" << endl;
|
||||
#endif
|
||||
// Worst case, we override all base functions so we
|
||||
// increment derived contract's function index by
|
||||
// this amount.
|
||||
@ -378,9 +379,6 @@ void SolInterface::addFunctions(Interface const& _interface)
|
||||
|
||||
SolInterface::SolInterface(Interface const& _interface, string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||
{
|
||||
#if 0
|
||||
cout << "Constructing " << _name << endl;
|
||||
#endif
|
||||
m_prng = _prng;
|
||||
m_interfaceName = _name;
|
||||
m_lastBaseName = m_interfaceName;
|
||||
@ -430,8 +428,16 @@ string SolInterface::overrideStr() const
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
else if (coinFlip())
|
||||
continue;
|
||||
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);)")
|
||||
("functionName", f.first->name())
|
||||
@ -470,11 +476,18 @@ interface <programName><?inheritance> is <baseNames></inheritance> {
|
||||
.render();
|
||||
}
|
||||
|
||||
SolContract::SolContract(Contract const& _contract, std::string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||
void SolContract::overrideHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SolContract::addOverrides()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SolContract::addFunctions(Contract const& _contract)
|
||||
{
|
||||
m_prng = _prng;
|
||||
m_contractName = _name;
|
||||
m_abstract = _contract.abstract();
|
||||
for (auto &f: _contract.funcdef())
|
||||
m_contractFunctions.push_back(
|
||||
make_unique<SolContractFunction>(
|
||||
@ -486,6 +499,10 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void SolContract::addBases(Contract const& _contract)
|
||||
{
|
||||
for (auto &b: _contract.bases())
|
||||
{
|
||||
switch (b.contract_or_interface_oneof_case())
|
||||
@ -493,14 +510,14 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt
|
||||
case ContractOrInterface::kC:
|
||||
m_baseContracts.push_back(
|
||||
make_unique<SolBaseContract>(
|
||||
SolBaseContract(&b.c(), newContractBaseName(), m_prng)
|
||||
SolBaseContract(&b.c(), newBaseName(), m_prng)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case ContractOrInterface::kI:
|
||||
m_baseContracts.push_back(
|
||||
make_unique<SolBaseContract>(
|
||||
SolBaseContract(&b.i(), newInterfaceBaseName(), m_prng)
|
||||
SolBaseContract(&b.i(), newBaseName(), m_prng)
|
||||
)
|
||||
);
|
||||
break;
|
||||
@ -510,6 +527,25 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt
|
||||
}
|
||||
}
|
||||
|
||||
string SolContract::str() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
SolContract::SolContract(
|
||||
Contract const& _contract,
|
||||
std::string _name,
|
||||
shared_ptr<SolRandomNumGenerator> _prng
|
||||
)
|
||||
{
|
||||
m_prng = _prng;
|
||||
m_contractName = _name;
|
||||
m_abstract = _contract.abstract();
|
||||
addBases(_contract);
|
||||
addOverrides();
|
||||
addFunctions(_contract);
|
||||
}
|
||||
|
||||
void SolLibrary::addFunction(LibraryFunction const& _function)
|
||||
{
|
||||
// Register function name and return value
|
||||
@ -536,9 +572,10 @@ void SolLibrary::addFunction(LibraryFunction const& _function)
|
||||
);
|
||||
}
|
||||
|
||||
SolLibrary::SolLibrary(Library const& _library, string _name)
|
||||
SolLibrary::SolLibrary(Library const& _library, string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||
{
|
||||
m_libraryName = _name;
|
||||
m_prng = _prng;
|
||||
for (LibraryFunction const& f: _library.funcdef())
|
||||
addFunction(f);
|
||||
}
|
||||
@ -564,17 +601,20 @@ bool SolLibrary::validTest() const
|
||||
return m_publicFunctionMap.size() > 0;
|
||||
}
|
||||
|
||||
pair<string, string> SolLibrary::pseudoRandomTest(unsigned _randomIdx)
|
||||
pair<string, string> SolLibrary::pseudoRandomTest()
|
||||
{
|
||||
solAssert(m_publicFunctionMap.size() > 0, "Sol proto adaptor: Empty library map");
|
||||
string chosenFunction;
|
||||
unsigned numFunctions = m_publicFunctionMap.size();
|
||||
unsigned functionIndex = _randomIdx % numFunctions;
|
||||
unsigned functionIndex = randomNumber() % numFunctions;
|
||||
unsigned mapIdx = 0;
|
||||
for (auto &e: m_publicFunctionMap)
|
||||
{
|
||||
if (functionIndex == mapIdx)
|
||||
{
|
||||
chosenFunction = e.first;
|
||||
break;
|
||||
}
|
||||
mapIdx++;
|
||||
}
|
||||
solAssert(m_publicFunctionMap.count(chosenFunction), "Sol proto adaptor: Invalid library function chosen");
|
||||
|
@ -194,7 +194,7 @@ struct SolLibraryFunction
|
||||
|
||||
struct SolLibrary
|
||||
{
|
||||
SolLibrary(Library const& _library, std::string _name);
|
||||
SolLibrary(Library const& _library, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
|
||||
std::vector<std::unique_ptr<SolLibraryFunction>> m_functions;
|
||||
/// Maps publicly exposed function name to expected output
|
||||
std::map<std::string, std::string> m_publicFunctionMap;
|
||||
@ -202,13 +202,15 @@ struct SolLibrary
|
||||
void addFunction(LibraryFunction const& _function);
|
||||
|
||||
bool validTest() const;
|
||||
unsigned randomNumber() const
|
||||
{
|
||||
return m_prng->operator()();
|
||||
}
|
||||
|
||||
/// Returns a pair of function name and expected output
|
||||
/// that is pseudo randomly chosen from the list of all
|
||||
/// library functions.
|
||||
/// @param _randomIdx A pseudo randomly generated number that is
|
||||
/// used to index the list of all library functions.
|
||||
std::pair<std::string, std::string> pseudoRandomTest(unsigned _randomIdx);
|
||||
std::pair<std::string, std::string> pseudoRandomTest();
|
||||
|
||||
std::string str() const;
|
||||
|
||||
@ -228,6 +230,7 @@ struct SolLibrary
|
||||
std::string m_libraryName;
|
||||
unsigned m_functionIndex = 0;
|
||||
unsigned m_returnValue = 0;
|
||||
std::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||
};
|
||||
|
||||
struct SolBaseContract
|
||||
@ -244,8 +247,14 @@ struct SolContract
|
||||
SolContract(Contract const& _contract, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
|
||||
|
||||
std::string str() const;
|
||||
void addFunctions(Contract const& _contract);
|
||||
void addBases(Contract const& _contract);
|
||||
void addOverrides();
|
||||
void overrideHelper();
|
||||
bool validTest();
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomTest();
|
||||
|
||||
unsigned randomNumber()
|
||||
unsigned randomNumber() const
|
||||
{
|
||||
return m_prng->operator()();
|
||||
}
|
||||
@ -253,27 +262,27 @@ struct SolContract
|
||||
{
|
||||
return m_contractName;
|
||||
}
|
||||
|
||||
bool abstract() const
|
||||
{
|
||||
return m_abstract;
|
||||
}
|
||||
|
||||
std::string newFunctionName()
|
||||
{
|
||||
return "f" + std::to_string(m_functionIndex++);
|
||||
}
|
||||
|
||||
std::string newContractBaseName()
|
||||
unsigned functionIndex() const
|
||||
{
|
||||
return name() + "B" + std::to_string(m_baseIndex++);
|
||||
return m_functionIndex;
|
||||
}
|
||||
|
||||
std::string newInterfaceBaseName()
|
||||
std::string newBaseName()
|
||||
{
|
||||
return "IB" + std::to_string(m_baseIndex++);
|
||||
m_lastBaseName += "B";
|
||||
return m_lastBaseName;
|
||||
}
|
||||
std::string lastBaseName() const
|
||||
{
|
||||
return m_lastBaseName;
|
||||
}
|
||||
|
||||
std::string newReturnValue()
|
||||
{
|
||||
return std::to_string(m_returnValue++);
|
||||
@ -281,12 +290,12 @@ struct SolContract
|
||||
|
||||
std::string m_contractName;
|
||||
bool m_abstract = false;
|
||||
unsigned m_baseIndex = 0;
|
||||
unsigned m_functionIndex = 0;
|
||||
unsigned m_returnValue = 0;
|
||||
std::vector<std::unique_ptr<SolContractFunction>> m_contractFunctions;
|
||||
std::vector<std::unique_ptr<SolBaseContract>> m_baseContracts;
|
||||
std::vector<std::unique_ptr<CFunctionOverride>> m_overriddenFunctions;
|
||||
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::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||
};
|
||||
|
||||
@ -375,6 +384,13 @@ struct SolInterface
|
||||
std::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||
};
|
||||
|
||||
/* Contract functions may be overridden by other contracts. Base and derived contracts
|
||||
* may either be abstract or non-abstract. That gives us four possibilities:
|
||||
* - both abstract
|
||||
* - both non abstract
|
||||
* - one of them abstract, the other non abstract
|
||||
*/
|
||||
|
||||
struct CFunctionOverride
|
||||
{
|
||||
CFunctionOverride(
|
||||
@ -393,6 +409,12 @@ struct CFunctionOverride
|
||||
m_returnValue = _returnValue;
|
||||
}
|
||||
|
||||
enum class DerivedType
|
||||
{
|
||||
ABSTRACTCONTRACT,
|
||||
CONTRACT
|
||||
};
|
||||
|
||||
enum class CFunctionOverrideType
|
||||
{
|
||||
INTERFACE,
|
||||
|
@ -54,7 +54,7 @@ string ProtoConverter::visit(TestContract const& _testContract)
|
||||
else
|
||||
{
|
||||
m_libraryTest = true;
|
||||
auto testTuple = pseudoRandomLibraryTest(_testContract.programidx());
|
||||
auto testTuple = pseudoRandomLibraryTest();
|
||||
m_libraryName = get<0>(testTuple);
|
||||
usingLibDecl = Whiskers(R"(
|
||||
using <libraryName> for uint;)")
|
||||
@ -72,20 +72,24 @@ string ProtoConverter::visit(TestContract const& _testContract)
|
||||
break;
|
||||
}
|
||||
case TestContract::CONTRACT:
|
||||
#if 0
|
||||
testCode = Whiskers(R"(
|
||||
<contractName> testContract = new <contractName>();
|
||||
if (testContract.<testFunction>() != <expectedOutput>)
|
||||
return 1;
|
||||
return 0;)")
|
||||
("contractName", "")
|
||||
("testFunction", "")
|
||||
("expectedOutput", "")
|
||||
.render();
|
||||
#else
|
||||
testCode = Whiskers(R"(
|
||||
if (emptyContractTests())
|
||||
testCode = Whiskers(R"(
|
||||
return 0;)")
|
||||
.render();
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
auto testTuple = pseudoRandomContractTest();
|
||||
testCode = Whiskers(R"(
|
||||
<contractName> testContract = new <contractName>();
|
||||
if (testContract.<testFunction>() != <expectedOutput>)
|
||||
return 1;
|
||||
return 0;)")
|
||||
("contractName", get<0>(testTuple))
|
||||
("testFunction", get<1>(testTuple))
|
||||
("expectedOutput", get<2>(testTuple))
|
||||
.render();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -615,25 +619,24 @@ tuple<string, string, string> ProtoConverter::visitProgramHelper(CIL _program)
|
||||
}
|
||||
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)
|
||||
return "";
|
||||
|
||||
openProgramScope(&_contract);
|
||||
auto [bases, baseNames, funcs] = visitProgramHelper(&_contract);
|
||||
return Whiskers(R"(
|
||||
<bases>
|
||||
<?isAbstract>abstract </isAbstract>contract <programName><?inheritance> is <baseNames></inheritance> {
|
||||
<functionDefs>
|
||||
})")
|
||||
("bases", bases)
|
||||
("isAbstract", _contract.abstract())
|
||||
("programName", programName(&_contract))
|
||||
("inheritance", _contract.bases_size() > 0 && !baseNames.empty())
|
||||
("baseNames", baseNames)
|
||||
("functionDefs", funcs)
|
||||
.render();
|
||||
try {
|
||||
auto contract = SolContract(_contract, programName(&_contract), m_randomGen);
|
||||
return contract.str();
|
||||
}
|
||||
catch (langutil::FuzzerError const&)
|
||||
{
|
||||
// Return empty string if input specification is invalid.
|
||||
return "";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
string ProtoConverter::visit(Interface const& _interface)
|
||||
{
|
||||
@ -658,22 +661,29 @@ string ProtoConverter::visit(Library const& _library)
|
||||
return "";
|
||||
|
||||
openProgramScope(&_library);
|
||||
auto lib = SolLibrary(_library, programName(&_library));
|
||||
auto lib = SolLibrary(_library, programName(&_library), m_randomGen);
|
||||
if (lib.validTest())
|
||||
{
|
||||
auto libTestPair = lib.pseudoRandomTest(_library.random());
|
||||
auto libTestPair = lib.pseudoRandomTest();
|
||||
m_libraryTests.push_back({lib.name(), libTestPair.first, libTestPair.second});
|
||||
}
|
||||
return lib.str();
|
||||
}
|
||||
|
||||
tuple<string, string, string> ProtoConverter::pseudoRandomLibraryTest(unsigned _randomIdx)
|
||||
tuple<string, string, string> ProtoConverter::pseudoRandomLibraryTest()
|
||||
{
|
||||
solAssert(m_libraryTests.size() > 0, "Sol proto fuzzer: No library tests found");
|
||||
unsigned index = _randomIdx % m_libraryTests.size();
|
||||
unsigned index = randomNumber() % m_libraryTests.size();
|
||||
return m_libraryTests[index];
|
||||
}
|
||||
|
||||
tuple<string, string, string> ProtoConverter::pseudoRandomContractTest()
|
||||
{
|
||||
solAssert(m_contractTests.size() > 0, "Sol proto fuzzer: No contract tests found");
|
||||
unsigned index = randomNumber() % m_contractTests.size();
|
||||
return m_contractTests[index];
|
||||
}
|
||||
|
||||
void ProtoConverter::openProgramScope(CIL _program)
|
||||
{
|
||||
string programNamePrefix;
|
||||
|
@ -121,7 +121,8 @@ private:
|
||||
Contract const* _derived,
|
||||
CIFunc _baseFunc
|
||||
);
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest(unsigned _randomIdx);
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest();
|
||||
std::tuple<std::string, std::string, std::string> pseudoRandomContractTest();
|
||||
|
||||
bool emptyLibrary(Library const& _library)
|
||||
{
|
||||
@ -131,6 +132,10 @@ private:
|
||||
{
|
||||
return m_libraryTests.size() == 0;
|
||||
}
|
||||
bool emptyContractTests()
|
||||
{
|
||||
return m_contractTests.size() == 0;
|
||||
}
|
||||
|
||||
void openProgramScope(CIL _program);
|
||||
bool pseudoRandomCoinFlip()
|
||||
@ -155,7 +160,6 @@ private:
|
||||
static bool disallowedContractFunction(SolContractFunction const& _contractFunction, bool _isVirtual);
|
||||
#endif
|
||||
|
||||
unsigned m_numMods = 0;
|
||||
unsigned m_numPrograms = 0;
|
||||
unsigned m_counter = 0;
|
||||
bool m_mostDerivedAbstractContract = false;
|
||||
@ -194,6 +198,7 @@ private:
|
||||
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";
|
||||
|
@ -61,7 +61,6 @@ message ContractFunction {
|
||||
|
||||
message Library {
|
||||
repeated LibraryFunction funcdef = 1;
|
||||
required uint64 random = 2;
|
||||
}
|
||||
|
||||
message Interface {
|
||||
@ -96,7 +95,6 @@ message TestContract {
|
||||
CONTRACT = 1;
|
||||
}
|
||||
required Type type = 1;
|
||||
required uint64 programidx = 2;
|
||||
}
|
||||
|
||||
message Program {
|
||||
|
Loading…
Reference in New Issue
Block a user