Provide different options for reason strings.

This commit is contained in:
chriseth 2019-09-18 16:44:36 +02:00
parent 108992c335
commit 138ee647f1
22 changed files with 300 additions and 22 deletions

View File

@ -31,6 +31,9 @@ Language Features:
* Modify ``push(element)`` for dynamic storage arrays such that it does not return the new length anymore.
* Yul: Introduce ``leave`` statement that exits the current function.
Compiler Features:
* Allow revert strings to be stripped from the binary using the ``--revert-strings`` option or the ``settings.debug.revertStrings`` setting.
### 0.5.13 (unreleased)

View File

@ -234,6 +234,16 @@ Input Description
// Affects type checking and code generation. Can be homestead,
// tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul or berlin
"evmVersion": "byzantium",
// Optional: Debugging settings
"debug": {
// How to treat revert (and require) reason strings. Settings are
// "default", "strip", "debug" and "verboseDebug".
// "default" does not inject compiler-generated revert strings and keeps user-supplied ones.
// "strip" removes all revert strings (if possible, i.e. if literals are used) keeping side-effects
// "debug" injects strings for compiler-generated internal reverts (not yet implemented)
// "verboseDebug" even appends further information to user-supplied revert strings (not yet implemented)
"revertStrings": "default"
}
// Metadata settings (optional)
"metadata": {
// Use only literal content and not URLs (false by default)

View File

@ -101,6 +101,7 @@ set(sources
interface/ABI.h
interface/CompilerStack.cpp
interface/CompilerStack.h
interface/DebugSettings.h
interface/GasEstimator.cpp
interface/GasEstimator.h
interface/Natspec.cpp

View File

@ -35,7 +35,7 @@ void Compiler::compileContract(
bytes const& _metadata
)
{
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimiserSettings);
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimiserSettings, m_revertStrings);
runtimeCompiler.compileContract(_contract, _otherCompilers);
m_runtimeContext.appendAuxiliaryData(_metadata);
@ -45,7 +45,7 @@ void Compiler::compileContract(
// The creation code will be executed at most once, so we modify the optimizer
// settings accordingly.
creationSettings.expectedExecutionsPerDeployment = 1;
ContractCompiler creationCompiler(&runtimeCompiler, m_context, creationSettings);
ContractCompiler creationCompiler(&runtimeCompiler, m_context, creationSettings, m_revertStrings);
m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers);
m_context.optimise(m_optimiserSettings);

View File

@ -24,6 +24,7 @@
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/interface/OptimiserSettings.h>
#include <libsolidity/interface/DebugSettings.h>
#include <liblangutil/EVMVersion.h>
#include <libevmasm/Assembly.h>
#include <functional>
@ -35,8 +36,9 @@ namespace solidity {
class Compiler
{
public:
explicit Compiler(langutil::EVMVersion _evmVersion, OptimiserSettings _optimiserSettings):
Compiler(langutil::EVMVersion _evmVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings):
m_optimiserSettings(std::move(_optimiserSettings)),
m_revertStrings(_revertStrings),
m_runtimeContext(_evmVersion),
m_context(_evmVersion, &m_runtimeContext)
{ }
@ -79,6 +81,7 @@ public:
private:
OptimiserSettings const m_optimiserSettings;
RevertStrings const m_revertStrings;
CompilerContext m_runtimeContext;
size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present.
CompilerContext m_context;

View File

@ -512,7 +512,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
for (VariableDeclaration const* variable: _contract.stateVariables())
if (variable->value() && !variable->isConstant())
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable);
ExpressionCompiler(m_context, m_revertStrings, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable);
}
bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
@ -525,9 +525,11 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
m_continueTags.clear();
if (_variableDeclaration.isConstant())
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendConstStateVariableAccessor(_variableDeclaration);
ExpressionCompiler(m_context, m_revertStrings, m_optimiserSettings.runOrderLiterals)
.appendConstStateVariableAccessor(_variableDeclaration);
else
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableAccessor(_variableDeclaration);
ExpressionCompiler(m_context, m_revertStrings, m_optimiserSettings.runOrderLiterals)
.appendStateVariableAccessor(_variableDeclaration);
return false;
}
@ -1308,7 +1310,7 @@ void ContractCompiler::appendStackVariableInitialisation(VariableDeclaration con
void ContractCompiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
{
ExpressionCompiler expressionCompiler(m_context, m_optimiserSettings.runOrderLiterals);
ExpressionCompiler expressionCompiler(m_context, m_revertStrings, m_optimiserSettings.runOrderLiterals);
expressionCompiler.compile(_expression);
if (_targetType)
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);

View File

@ -24,6 +24,7 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/interface/DebugSettings.h>
#include <libevmasm/Assembly.h>
#include <functional>
#include <ostream>
@ -43,9 +44,11 @@ public:
explicit ContractCompiler(
ContractCompiler* _runtimeCompiler,
CompilerContext& _context,
OptimiserSettings _optimiserSettings
OptimiserSettings _optimiserSettings,
RevertStrings _revertStrings
):
m_optimiserSettings(std::move(_optimiserSettings)),
m_revertStrings(_revertStrings),
m_runtimeCompiler(_runtimeCompiler),
m_context(_context)
{
@ -138,6 +141,7 @@ private:
void storeStackHeight(ASTNode const* _node);
OptimiserSettings const m_optimiserSettings;
RevertStrings const m_revertStrings;
/// Pointer to the runtime compiler in case this is a creation compiler.
ContractCompiler* m_runtimeCompiler = nullptr;
CompilerContext& m_context;

View File

@ -703,16 +703,28 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case FunctionType::Kind::Revert:
{
if (!arguments.empty())
if (arguments.empty())
m_context.appendRevert();
else
{
// function-sel(Error(string)) + encoding
solAssert(arguments.size() == 1, "");
solAssert(function.parameterTypes().size() == 1, "");
arguments.front()->accept(*this);
utils().revertWithStringData(*arguments.front()->annotation().type);
if (m_revertStrings == RevertStrings::Strip)
{
if (!arguments.front()->annotation().isPure)
{
arguments.front()->accept(*this);
utils().popStackElement(*arguments.front()->annotation().type);
}
m_context.appendRevert();
}
else
{
arguments.front()->accept(*this);
utils().revertWithStringData(*arguments.front()->annotation().type);
}
}
else
m_context.appendRevert();
break;
}
case FunctionType::Kind::KECCAK256:
@ -977,6 +989,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::Require:
{
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), false);
bool haveReasonString = arguments.size() > 1 && m_revertStrings != RevertStrings::Strip;
if (arguments.size() > 1)
{
// Users probably expect the second argument to be evaluated
@ -984,8 +999,19 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// function call.
solAssert(arguments.size() == 2, "");
solAssert(function.kind() == FunctionType::Kind::Require, "");
arguments.at(1)->accept(*this);
utils().moveIntoStack(1, arguments.at(1)->annotation().type->sizeOnStack());
if (m_revertStrings == RevertStrings::Strip)
{
if (!arguments.at(1)->annotation().isPure)
{
arguments.at(1)->accept(*this);
utils().popStackElement(*arguments.at(1)->annotation().type);
}
}
else
{
arguments.at(1)->accept(*this);
utils().moveIntoStack(1, arguments.at(1)->annotation().type->sizeOnStack());
}
}
// Stack: <error string (unconverted)> <condition>
// jump if condition was met
@ -994,7 +1020,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (function.kind() == FunctionType::Kind::Assert)
// condition was not met, flag an error
m_context.appendInvalid();
else if (arguments.size() > 1)
else if (haveReasonString)
{
utils().revertWithStringData(*arguments.at(1)->annotation().type);
// Here, the argument is consumed, but in the other branch, it is still there.
@ -1004,7 +1030,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context.appendRevert();
// the success branch
m_context << success;
if (arguments.size() > 1)
if (haveReasonString)
utils().popStackElement(*arguments.at(1)->annotation().type);
break;
}

View File

@ -25,6 +25,7 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/LValue.h>
#include <libsolidity/interface/DebugSettings.h>
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceLocation.h>
#include <libdevcore/Common.h>
@ -55,8 +56,15 @@ class ArrayType;
class ExpressionCompiler: private ASTConstVisitor
{
public:
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimiseOrderLiterals):
m_optimiseOrderLiterals(_optimiseOrderLiterals), m_context(_compilerContext) {}
ExpressionCompiler(
CompilerContext& _compilerContext,
RevertStrings _revertStrings,
bool _optimiseOrderLiterals
):
m_revertStrings(_revertStrings),
m_optimiseOrderLiterals(_optimiseOrderLiterals),
m_context(_compilerContext)
{}
/// Compile the given @a _expression and leave its value on the stack.
void compile(Expression const& _expression);
@ -130,6 +138,7 @@ private:
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
RevertStrings m_revertStrings;
bool m_optimiseOrderLiterals;
CompilerContext& m_context;
std::unique_ptr<LValue> m_currentLValue;

View File

@ -152,6 +152,14 @@ void CompilerStack::setOptimiserSettings(OptimiserSettings _settings)
m_optimiserSettings = std::move(_settings);
}
void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings)
{
if (m_stackState >= ParsingPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set revert string settings before parsing."));
solUnimplementedAssert(_revertStrings == RevertStrings::Default || _revertStrings == RevertStrings::Strip, "");
m_revertStrings = _revertStrings;
}
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
{
if (m_stackState >= ParsingPerformed)
@ -187,6 +195,7 @@ void CompilerStack::reset(bool _keepSettings)
m_evmVersion = langutil::EVMVersion();
m_generateIR = false;
m_generateEWasm = false;
m_revertStrings = RevertStrings::Default;
m_optimiserSettings = OptimiserSettings::minimal();
m_metadataLiteralSources = false;
m_metadataHash = MetadataHash::IPFS;
@ -972,7 +981,7 @@ void CompilerStack::compileContract(
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_optimiserSettings);
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings);
compiledContract.compiler = compiler;
bytes cborEncodedMetadata = createCBORMetadata(
@ -1171,6 +1180,9 @@ string CompilerStack::createMetadata(Contract const& _contract) const
meta["settings"]["optimizer"]["details"] = std::move(details);
}
if (m_revertStrings != RevertStrings::Default)
meta["settings"]["debug"]["revertStrings"] = revertStringsToString(m_revertStrings);
if (m_metadataLiteralSources)
meta["settings"]["metadata"]["useLiteralContent"] = true;

View File

@ -26,6 +26,7 @@
#include <libsolidity/interface/ReadFile.h>
#include <libsolidity/interface/OptimiserSettings.h>
#include <libsolidity/interface/Version.h>
#include <libsolidity/interface/DebugSettings.h>
#include <liblangutil/ErrorReporter.h>
#include <liblangutil/EVMVersion.h>
@ -145,6 +146,9 @@ public:
/// Must be set before parsing.
void setOptimiserSettings(OptimiserSettings _settings);
/// Sets whether to strip revert strings, add additional strings or do nothing at all.
void setRevertStringBehaviour(RevertStrings _revertStrings);
/// Set whether or not parser error is desired.
/// When called without an argument it will revert to the default.
/// Must be set before parsing.
@ -414,6 +418,7 @@ private:
ReadCallback::Callback m_readFile;
OptimiserSettings m_optimiserSettings;
RevertStrings m_revertStrings = RevertStrings::Default;
langutil::EVMVersion m_evmVersion;
std::map<std::string, std::set<std::string>> m_requestedContractNames;
bool m_generateIR;

View File

@ -0,0 +1,63 @@
/*
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/>.
*/
/**
* Settings to aid debugging.
*/
#pragma once
#include <cstddef>
#include <string>
#include <optional>
namespace dev
{
namespace solidity
{
enum class RevertStrings
{
Default, // no compiler-generated strings, keep user-supplied strings
Strip, // no compiler-generated strings, remove user-supplied strings (if possible)
Debug, // add strings for internal reverts, keep user-supplied strings
VerboseDebug // add strings for internal reverts, add user-supplied strings if not provided
};
inline std::string revertStringsToString(RevertStrings _str)
{
switch (_str)
{
case RevertStrings::Default: return "default";
case RevertStrings::Strip: return "strip";
case RevertStrings::Debug: return "debug";
case RevertStrings::VerboseDebug: return "verboseDebug";
}
// Cannot reach this.
return "INVALID";
}
inline std::optional<RevertStrings> revertStringsFromString(std::string const& _str)
{
for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug})
if (revertStringsToString(i) == _str)
return i;
return {};
}
}
}

View File

@ -350,7 +350,7 @@ std::optional<Json::Value> checkAuxiliaryInputKeys(Json::Value const& _input)
std::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
{
static set<string> keys{"parserErrorRecovery", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"};
static set<string> keys{"parserErrorRecovery", "debug", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"};
return checkKeys(_input, keys, "settings");
}
@ -649,6 +649,27 @@ boost::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompile
ret.evmVersion = *version;
}
if (settings.isMember("debug"))
{
if (auto result = checkKeys(settings["debug"], {"revertStrings"}, "settings.debug"))
return *result;
if (settings["debug"].isMember("revertStrings"))
{
if (!settings["debug"]["revertStrings"].isString())
return formatFatalError("JSONError", "settings.debug.revertStrings must be a string.");
std::optional<RevertStrings> revertStrings = revertStringsFromString(settings["debug"]["revertStrings"].asString());
if (!revertStrings)
return formatFatalError("JSONError", "Invalid value for settings.debug.revertStrings.");
if (*revertStrings != RevertStrings::Default && *revertStrings != RevertStrings::Strip)
return formatFatalError(
"UnimplementedFeatureError",
"Only \"default\" and \"strip\" are implemented for settings.debug.revertStrings for now."
);
ret.revertStrings = *revertStrings;
}
}
if (settings.isMember("remappings") && !settings["remappings"].isArray())
return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings.");
@ -751,6 +772,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
compilerStack.setParserErrorRecovery(_inputsAndSettings.parserErrorRecovery);
compilerStack.setRemappings(_inputsAndSettings.remappings);
compilerStack.setOptimiserSettings(std::move(_inputsAndSettings.optimiserSettings));
compilerStack.setRevertStringBehaviour(_inputsAndSettings.revertStrings);
compilerStack.setLibraries(_inputsAndSettings.libraries);
compilerStack.useMetadataLiteralSources(_inputsAndSettings.metadataLiteralSources);
compilerStack.setMetadataHash(_inputsAndSettings.metadataHash);
@ -990,6 +1012,8 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
return formatFatalError("JSONError", "Field \"settings.remappings\" cannot be used for Yul.");
if (!_inputsAndSettings.libraries.empty())
return formatFatalError("JSONError", "Field \"settings.libraries\" cannot be used for Yul.");
if (_inputsAndSettings.revertStrings != RevertStrings::Default)
return formatFatalError("JSONError", "Field \"settings.debug.revertStrings\" cannot be used for Yul.");
Json::Value output = Json::objectValue;

View File

@ -65,6 +65,7 @@ private:
std::map<h256, std::string> smtLib2Responses;
langutil::EVMVersion evmVersion;
std::vector<CompilerStack::Remapping> remappings;
RevertStrings revertStrings = RevertStrings::Default;
OptimiserSettings optimiserSettings = OptimiserSettings::minimal();
std::map<std::string, h160> libraries;
bool metadataLiteralSources = false;

View File

@ -32,6 +32,7 @@
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/StandardCompiler.h>
#include <libsolidity/interface/GasEstimator.h>
#include <libsolidity/interface/DebugSettings.h>
#include <libyul/AssemblyStack.h>
@ -140,6 +141,17 @@ static string const g_strOptimizeRuns = "optimize-runs";
static string const g_strOptimizeYul = "optimize-yul";
static string const g_strOutputDir = "output-dir";
static string const g_strOverwrite = "overwrite";
static string const g_strRevertStrings = "revert-strings";
/// Possible arguments to for --revert-strings
static set<string> const g_revertStringsArgs
{
revertStringsToString(RevertStrings::Default),
revertStringsToString(RevertStrings::Strip),
revertStringsToString(RevertStrings::Debug),
revertStringsToString(RevertStrings::VerboseDebug)
};
static string const g_strSignatureHashes = "hashes";
static string const g_strSources = "sources";
static string const g_strSourceList = "sourceList";
@ -677,6 +689,11 @@ Allowed options)",
"<libraryName>:<address> [, or whitespace] ...\n"
"Address is interpreted as a hex string optionally prefixed by 0x."
)
(
g_strRevertStrings.c_str(),
po::value<string>()->value_name(boost::join(g_revertStringsArgs, ",")),
"Strip revert (and require) reason strings or add additional debugging information."
)
(
(g_argOutputDir + ",o").c_str(),
po::value<string>()->value_name("path"),
@ -797,6 +814,23 @@ Allowed options)",
return false;
}
if (m_args.count(g_strRevertStrings))
{
string revertStringsString = m_args[g_strRevertStrings].as<string>();
std::optional<RevertStrings> revertStrings = revertStringsFromString(revertStringsString);
if (!revertStrings)
{
serr() << "Invalid option for --" << g_strRevertStrings << ": " << revertStringsString << endl;
return false;
}
if (*revertStrings != RevertStrings::Default && *revertStrings != RevertStrings::Strip)
{
serr() << "Only \"default\" and \"strip\" are implemented for --" << g_strRevertStrings << " for now." << endl;
return false;
}
m_revertStrings = *revertStrings;
}
if (m_args.count(g_argCombinedJson))
{
vector<string> requests;
@ -985,6 +1019,7 @@ bool CommandLineInterface::processInput()
m_compiler->setLibraries(m_libraries);
m_compiler->setParserErrorRecovery(m_args.count(g_argErrorRecovery));
m_compiler->setEVMVersion(m_evmVersion);
m_compiler->setRevertStringBehaviour(m_revertStrings);
// TODO: Perhaps we should not compile unless requested
m_compiler->enableIRGeneration(m_args.count(g_argIR));

View File

@ -22,6 +22,7 @@
#pragma once
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/DebugSettings.h>
#include <libyul/AssemblyStack.h>
#include <liblangutil/EVMVersion.h>
@ -111,6 +112,8 @@ private:
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
/// EVM version to use
langutil::EVMVersion m_evmVersion;
/// How to handle revert strings
RevertStrings m_revertStrings = RevertStrings::Default;
/// Chosen hash method for the bytecode metadata.
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
/// Whether or not to colorize diagnostics output.

View File

@ -25,6 +25,7 @@
#include <test/Options.h>
#include <libsolidity/interface/OptimiserSettings.h>
#include <libsolidity/interface/DebugSettings.h>
#include <liblangutil/EVMVersion.h>
@ -269,6 +270,7 @@ protected:
bytes const& logData(size_t _logIdx) const;
langutil::EVMVersion m_evmVersion;
solidity::RevertStrings m_revertStrings = solidity::RevertStrings::Default;
solidity::OptimiserSettings m_optimiserSettings = solidity::OptimiserSettings::minimal();
bool m_showMessages = false;
std::shared_ptr<EVMHost> m_evmHost;

View File

@ -87,6 +87,7 @@ eth::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
{
Compiler compiler(
dev::test::Options::get().evmVersion(),
RevertStrings::Default,
dev::test::Options::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()
);
compiler.compileContract(*contract, map<ContractDefinition const*, shared_ptr<Compiler const>>{}, bytes());

View File

@ -284,6 +284,26 @@ BOOST_AUTO_TEST_CASE(metadata_useLiteralContent)
check(sourceCode, false);
}
BOOST_AUTO_TEST_CASE(metadata_revert_strings)
{
CompilerStack compilerStack;
char const* sourceCodeA = R"(
pragma solidity >=0.0;
contract A {
}
)";
compilerStack.setSources({{"A", std::string(sourceCodeA)}});
compilerStack.setRevertStringBehaviour(RevertStrings::Strip);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
std::string const& serialisedMetadata = compilerStack.metadata("A");
BOOST_CHECK(dev::test::isValidMetadata(serialisedMetadata));
Json::Value metadata;
BOOST_REQUIRE(jsonParseStrict(serialisedMetadata, metadata));
BOOST_CHECK_EQUAL(metadata["settings"]["debug"]["revertStrings"], "strip");
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -14800,6 +14800,55 @@ BOOST_AUTO_TEST_CASE(try_catch_library_call)
}
}
BOOST_AUTO_TEST_CASE(strip_reason_strings)
{
char const* sourceCode = R"(
contract C {
function f(bool _x) public pure returns (uint) {
require(_x, "some reason");
return 7;
}
function g(bool _x) public pure returns (uint) {
string memory x = "some indirect reason";
require(_x, x);
return 8;
}
function f1(bool _x) public pure returns (uint) {
if (!_x) revert( /* */ "some reason" /* */ );
return 9;
}
function g1(bool _x) public pure returns (uint) {
string memory x = "some indirect reason";
if (!_x) revert(x);
return 10;
}
}
)";
m_revertStrings = RevertStrings::Default;
compileAndRun(sourceCode, 0, "C");
if (
m_optimiserSettings == OptimiserSettings::minimal() ||
m_optimiserSettings == OptimiserSettings::none()
)
// check that the reason string IS part of the binary.
BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") != std::string::npos);
m_revertStrings = RevertStrings::Strip;
compileAndRun(sourceCode, 0, "C");
// check that the reason string is NOT part of the binary.
BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") == std::string::npos);
ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(7));
ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs());
ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(8));
ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs());
ABI_CHECK(callContractFunction("f1(bool)", true), encodeArgs(9));
ABI_CHECK(callContractFunction("f1(bool)", false), encodeArgs());
ABI_CHECK(callContractFunction("g1(bool)", true), encodeArgs(10));
ABI_CHECK(callContractFunction("g1(bool)", false), encodeArgs());
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -47,6 +47,7 @@ bytes SolidityExecutionFramework::compileContract(
m_compiler.reset();
m_compiler.setSources({{"", sourceCode}});
m_compiler.setLibraries(_libraryAddresses);
m_compiler.setRevertStringBehaviour(m_revertStrings);
m_compiler.setEVMVersion(m_evmVersion);
m_compiler.setOptimiserSettings(m_optimiserSettings);
m_compiler.enableIRGeneration(m_compileViaYul);

View File

@ -152,7 +152,11 @@ bytes compileFirstExpression(
parametersSize--
);
ExpressionCompiler(context, dev::test::Options::get().optimize).compile(*extractor.expression());
ExpressionCompiler(
context,
RevertStrings::Default,
dev::test::Options::get().optimize
).compile(*extractor.expression());
for (vector<string> const& function: _functions)
context << context.functionEntryLabel(dynamic_cast<FunctionDefinition const&>(