solidity/test/tools/ossfuzz/SolProtoAdaptor.h
2020-05-11 12:48:48 +02:00

608 lines
14 KiB
C++

/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <test/tools/ossfuzz/protoToSol.h>
#include <iostream>
#include <string>
#include <utility>
#include <variant>
#include <boost/variant/static_visitor.hpp>
namespace solidity::test::solprotofuzzer::adaptor
{
/// Forward declarations
/// Solidity contract abstraction class
struct SolContract;
/// Solidity interface abstraction class
struct SolInterface;
/// Solidity library abstraction class
struct SolLibrary;
/// Solidity interface function abstraction class
struct SolInterfaceFunction;
/// Solidity contract function abstraction class
struct SolContractFunction;
/// Solidity library function abstraction class
struct SolLibraryFunction;
/// Variant type that points to one of contract, interface protobuf messages
using ProtoBaseContract = std::variant<Contract const*, Interface const*>;
enum class SolFunctionVisibility
{
PUBLIC,
PRIVATE,
INTERNAL,
EXTERNAL
};
enum class SolFunctionStateMutability
{
PURE,
VIEW,
PAYABLE,
NONPAYABLE
};
enum class SolLibraryFunctionStateMutability
{
PURE,
VIEW,
NONPAYABLE
};
struct SolInterfaceFunction
{
enum class Type
{
MEMBERFUNCTION,
IMPLICITOVERRIDE,
EXPLICITOVERRIDE
};
SolInterfaceFunction(
std::string _functionName,
SolFunctionStateMutability _mutability,
Type _type,
std::string _contractName
);
bool operator==(SolInterfaceFunction const& _rhs) const;
bool operator!=(SolInterfaceFunction const& _rhs) const;
bool operator==(SolContractFunction const& _rhs) const;
bool operator!=(SolContractFunction const& _rhs) const;
void merge(SolInterfaceFunction const& _rhs);
bool namesake(SolInterfaceFunction const& _rhs) const;
bool namesake(SolContractFunction const& _rhs) const;
void markExplicitOverride(std::string _contractName);
std::string overriddenFromBaseNames() const;
unsigned numOverriddenFromBases() const
{
return m_overriddenFrom.size();
}
void resetOverriddenBases()
{
m_overriddenFrom.clear();
m_overriddenFrom.push_back(m_contractName);
}
std::string str() const;
std::string name() const
{
return m_functionName;
}
SolFunctionStateMutability mutability() const
{
return m_mutability;
}
bool explicitOverride() const
{
return m_type == Type::EXPLICITOVERRIDE;
}
bool implicitOverride() const
{
return m_type == Type::IMPLICITOVERRIDE;
}
bool memberFunction() const
{
return m_type == Type::MEMBERFUNCTION;
}
void markImplicitOverride()
{
m_type = Type::IMPLICITOVERRIDE;
}
bool multipleBases() const
{
return m_overriddenFrom.size() > 1;
}
std::string m_functionName;
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
std::vector<std::string> m_overriddenFrom;
std::string m_contractName;
Type m_type;
};
struct SolContractFunction
{
enum class Type
{
MEMBERFUNCTION,
IMPLICITOVERRIDECONTRACT,
IMPLICITOVERRIDEINTERFACE,
EXPLICITOVERRIDECONTRACT,
EXPLICITOVERRIDEINTERFACE
};
SolContractFunction(
ContractFunction const& _function,
std::string _contractName,
std::string _functionName,
Type _type,
bool _implement,
std::string _returnValue
);
SolContractFunction(
std::vector<std::string> _overriddenFrom,
SolFunctionStateMutability _mutability,
std::string _contractName,
std::string _functionName,
Type _type,
bool _implement,
bool _virtual,
std::string _returnValue,
SolFunctionVisibility _vis = SolFunctionVisibility::EXTERNAL
);
bool memberFunction() const
{
return m_type == Type::MEMBERFUNCTION;
}
bool explicitInterfaceOverride() const
{
return m_type == Type::EXPLICITOVERRIDEINTERFACE;
}
bool explicitContractOverride() const
{
return m_type == Type::EXPLICITOVERRIDECONTRACT;
}
bool implicitInterfaceOverride() const
{
return m_type == Type::IMPLICITOVERRIDEINTERFACE;
}
bool implicitContractOverride() const
{
return m_type == Type::IMPLICITOVERRIDECONTRACT;
}
bool explicitOverride() const
{
return explicitContractOverride() || explicitInterfaceOverride();
}
bool implicitOverride() const
{
return implicitContractOverride() || implicitInterfaceOverride();
}
void markImplicitContractOverride()
{
m_type = Type::IMPLICITOVERRIDECONTRACT;
}
void markImplicitInterfaceOverride()
{
m_type = Type::IMPLICITOVERRIDEINTERFACE;
}
void markExplicitContractOverride(std::string _contractName)
{
m_type = Type::EXPLICITOVERRIDECONTRACT;
m_contractName = _contractName;
m_overriddenFrom.clear();
m_overriddenFrom.push_back(m_contractName);
}
void markExplicitInterfaceOverride(std::string _contractName)
{
m_type = Type::EXPLICITOVERRIDEINTERFACE;
m_contractName = _contractName;
m_overriddenFrom.clear();
m_overriddenFrom.push_back(m_contractName);
}
std::string overriddenFromBaseNames() const;
unsigned numOverriddenFromBases() const
{
return m_overriddenFrom.size();
}
void resetOverriddenBases()
{
m_overriddenFrom.clear();
m_overriddenFrom.push_back(m_contractName);
}
bool namesake(SolContractFunction const& _rhs) const;
bool namesake(SolInterfaceFunction const& _rhs) const;
bool operator==(SolContractFunction const& _rhs) const;
bool operator!=(SolContractFunction const& _rhs) const;
bool operator==(SolInterfaceFunction const& _rhs) const;
bool operator!=(SolInterfaceFunction const& _rhs) const;
void merge(SolContractFunction const& _rhs);
void merge(SolInterfaceFunction const& _rhs);
bool disallowed() const;
std::string str() const;
std::string name() const
{
return m_functionName;
}
std::string contractName() const
{
return m_contractName;
}
bool isVirtual() const
{
return m_virtual;
}
bool implemented() const
{
return m_implemented;
}
std::string returnValue() const
{
return m_returnValue;
}
SolFunctionVisibility visibility() const
{
return m_visibility;
}
SolFunctionStateMutability mutability() const
{
return m_mutability;
}
std::string m_contractName;
std::string m_functionName;
SolFunctionVisibility m_visibility = SolFunctionVisibility::PUBLIC;
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
bool m_virtual = false;
std::string m_returnValue;
bool m_implemented = true;
Type m_type;
std::vector<std::string> m_overriddenFrom;
};
struct SolLibraryFunction
{
SolLibraryFunction(
LibraryFunction const& _function,
std::string _libraryName,
std::string _functionName,
std::string _returnValue
);
std::string str() const;
std::string name() const
{
return m_functionName;
}
std::string returnValue() const
{
return m_returnValue;
}
SolFunctionVisibility visibility() const
{
return m_visibility;
}
SolLibraryFunctionStateMutability mutability() const
{
return m_mutability;
}
std::string m_libraryName;
std::string m_functionName;
SolFunctionVisibility m_visibility = SolFunctionVisibility::PUBLIC;
SolLibraryFunctionStateMutability m_mutability = SolLibraryFunctionStateMutability::PURE;
std::string m_returnValue;
};
struct SolLibrary
{
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;
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.
std::pair<std::string, std::string> pseudoRandomTest();
std::string str() const;
std::string name() const
{
return m_libraryName;
}
std::string newFunctionName()
{
return "f" + std::to_string(m_functionIndex++);
}
std::string newReturnValue()
{
return std::to_string(random());
}
std::string m_libraryName;
unsigned m_functionIndex = 0;
unsigned m_returnValue = 0;
std::shared_ptr<SolRandomNumGenerator> m_prng;
};
struct SolBaseContract
{
enum BaseType
{
INTERFACE,
CONTRACT
};
SolBaseContract(
ProtoBaseContract _base,
std::string _name,
std::shared_ptr<SolRandomNumGenerator> _prng
);
SolBaseContract(
ProtoBaseContract _base,
std::string _name,
std::shared_ptr<SolBaseContract> _cyclicBase,
std::shared_ptr<SolRandomNumGenerator> _prng
);
SolBaseContract(std::shared_ptr<SolInterface> _base);
BaseType type() const;
std::string name();
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::shared_ptr<SolBaseContract> randomBase();
bool atleastOneBase();
unsigned functionIndex();
std::string lastBaseName();
std::variant<std::shared_ptr<SolInterface>, std::shared_ptr<SolContract>> m_base;
};
struct SolContract
{
enum class Function
{
INTERFACE,
CONTRACT
};
using FunctionType = std::variant<std::shared_ptr<SolContractFunction>, std::shared_ptr<SolInterfaceFunction>>;
using FunctionList = std::vector<FunctionType>;
SolContract(
Contract const& _contract,
std::string _name,
std::shared_ptr<SolBaseContract> _cyclicBase,
std::shared_ptr<SolRandomNumGenerator> _prng
);
bool mergeFunctionBasetoContract(FunctionType _f1, FunctionType _f2);
void explicitOverrides();
template <typename T1, typename T2>
bool requiresMerge(T1 _f1, T2 _f2)
{
return _f1->namesake(*_f2);
}
std::shared_ptr<SolBaseContract> randomBase()
{
return m_baseContracts[randomNumber() % m_baseContracts.size()];
}
bool atleastOneBase();
void merge();
std::string str();
void addFunctions(Contract const& _contract);
void addBases(Contract const& _contract);
void copyFunctions(std::shared_ptr<SolBaseContract> _base, FunctionList& _globalList);
bool validTest();
std::string baseNames() const;
void validContractTests(
std::map<std::string, std::map<std::string, std::string>>& _testSet
);
unsigned randomNumber() const
{
return m_prng->operator()();
}
bool coinToss() const
{
return randomNumber() % 2 == 0;
}
std::string name() const
{
return m_contractName;
}
bool abstract() const
{
return m_abstract;
}
std::string newFunctionName()
{
return "f" + std::to_string(m_functionIndex++);
}
unsigned functionIndex() const
{
return m_functionIndex;
}
std::string newBaseName()
{
m_lastBaseName += "B";
return m_lastBaseName;
}
std::string lastBaseName() const
{
return m_lastBaseName;
}
std::string newReturnValue()
{
return std::to_string(randomNumber());
}
Function functionType(FunctionType _type)
{
if (std::holds_alternative<std::shared_ptr<SolContractFunction>>(_type))
return Function::CONTRACT;
else
return Function::INTERFACE;
}
bool contractFunction(FunctionType _type)
{
return functionType(_type) == Function::CONTRACT;
}
bool interfaceFunction(FunctionType _type)
{
return functionType(_type) == Function::INTERFACE;
}
std::shared_ptr<SolContractFunction> getContractFunction(FunctionType _type)
{
return std::get<std::shared_ptr<SolContractFunction>>(_type);
}
std::shared_ptr<SolInterfaceFunction> getInterfaceFunction(FunctionType _type)
{
return std::get<std::shared_ptr<SolInterfaceFunction>>(_type);
}
std::string m_contractName;
bool m_abstract = false;
unsigned m_functionIndex = 0;
unsigned m_returnValue = 0;
std::string m_lastBaseName;
FunctionList m_functions;
std::vector<std::shared_ptr<SolBaseContract>> m_baseContracts;
/// Maps non abstract contract name to list of publicly exposed function name
/// and their expected output
std::map<std::string, std::string> m_contractFunctionMap;
std::shared_ptr<SolRandomNumGenerator> m_prng;
std::shared_ptr<SolBaseContract> m_cyclicBase;
};
struct SolInterface
{
SolInterface(
Interface const& _interface,
std::string _interfaceName,
std::shared_ptr<SolInterface> _cyclicBase,
std::shared_ptr<SolRandomNumGenerator> _prng
);
void merge();
std::string name() const
{
return m_interfaceName;
}
unsigned randomNumber() const
{
return m_prng->operator()();
}
bool coinToss() const
{
return randomNumber() % 2 == 0;
}
bool atleastOneBase()
{
return !m_baseInterfaces.empty();
}
std::shared_ptr<SolInterface> randomBase()
{
return m_baseInterfaces[randomNumber() % m_baseInterfaces.size()];
}
std::string newFunctionName()
{
return "f" + std::to_string(m_functionIndex++);
}
unsigned functionIndex() const
{
return m_functionIndex;
}
std::string newBaseName()
{
m_lastBaseName += "B";
return m_lastBaseName;
}
std::string lastBaseName()
{
return m_lastBaseName;
}
std::string str() const;
/// Returns the Solidity code for all base interfaces
/// inherited by this interface.
std::string baseInterfaceStr() const;
std::string functionStr() const;
bool bases() const
{
return m_baseInterfaces.size() > 0;
}
/// Returns comma-space separated names of base interfaces inherited by
/// this interface.
std::string baseNames() const;
/// Add base contracts in a depth-first manner
void addBases(Interface const& _interface);
/// Add functions
void addFunctions(Interface const& _interface);
unsigned m_functionIndex = 0;
std::string m_lastBaseName;
std::string m_interfaceName;
std::vector<std::shared_ptr<SolInterfaceFunction>> m_functions;
std::vector<std::shared_ptr<SolInterface>> m_baseInterfaces;
std::shared_ptr<SolInterface> m_cyclicBaseInterface;
std::shared_ptr<SolRandomNumGenerator> m_prng;
};
}