mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Provide different options for reason strings.
This commit is contained in:
parent
108992c335
commit
138ee647f1
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
63
libsolidity/interface/DebugSettings.h
Normal file
63
libsolidity/interface/DebugSettings.h
Normal 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 {};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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&>(
|
||||
|
Loading…
Reference in New Issue
Block a user