diff --git a/Changelog.md b/Changelog.md index 641eefc0c..7cd79ab47 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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) diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index efa323b92..bfed31f30 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -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) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 384d3cb6c..aeef9271d 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -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 diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 55db6290d..121470e28 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.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); diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index 34bae7a27..c93fa5df1 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 4036a44f7..2ff92510c 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -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); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index c781b44f8..494cc3503 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 3d4383301..a8050c695 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -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: // 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; } diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index c29794858..ab13523d2 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -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 m_currentLValue; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 3aadf9a32..551e55585 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -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 = make_shared(m_evmVersion, m_optimiserSettings); + shared_ptr compiler = make_shared(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; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 3fd01df9d..35bda446e 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -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> m_requestedContractNames; bool m_generateIR; diff --git a/libsolidity/interface/DebugSettings.h b/libsolidity/interface/DebugSettings.h new file mode 100644 index 000000000..5b3e00850 --- /dev/null +++ b/libsolidity/interface/DebugSettings.h @@ -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 . +*/ +/** + * Settings to aid debugging. + */ + +#pragma once + +#include +#include +#include + +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 revertStringsFromString(std::string const& _str) +{ + for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug}) + if (revertStringsToString(i) == _str) + return i; + return {}; +} + +} +} diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 229e21da2..70c9e3430 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -350,7 +350,7 @@ std::optional checkAuxiliaryInputKeys(Json::Value const& _input) std::optional checkSettingsKeys(Json::Value const& _input) { - static set keys{"parserErrorRecovery", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; + static set keys{"parserErrorRecovery", "debug", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; return checkKeys(_input, keys, "settings"); } @@ -649,6 +649,27 @@ boost::variant 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 = 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; diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 454efab7d..030ade0f1 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -65,6 +65,7 @@ private: std::map smtLib2Responses; langutil::EVMVersion evmVersion; std::vector remappings; + RevertStrings revertStrings = RevertStrings::Default; OptimiserSettings optimiserSettings = OptimiserSettings::minimal(); std::map libraries; bool metadataLiteralSources = false; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e2a6f6026..f4cbbe103 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -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 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)", ":
[, or whitespace] ...\n" "Address is interpreted as a hex string optionally prefixed by 0x." ) + ( + g_strRevertStrings.c_str(), + po::value()->value_name(boost::join(g_revertStringsArgs, ",")), + "Strip revert (and require) reason strings or add additional debugging information." + ) ( (g_argOutputDir + ",o").c_str(), po::value()->value_name("path"), @@ -797,6 +814,23 @@ Allowed options)", return false; } + if (m_args.count(g_strRevertStrings)) + { + string revertStringsString = m_args[g_strRevertStrings].as(); + std::optional 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 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)); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 87ac8efd8..cca76c53f 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -111,6 +112,8 @@ private: std::unique_ptr 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. diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 5019c0fbc..20b1de5e5 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -25,6 +25,7 @@ #include #include +#include #include @@ -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 m_evmHost; diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index db3b395a5..84988c228 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -87,6 +87,7 @@ eth::AssemblyItems compileContract(std::shared_ptr _sourceCode) { Compiler compiler( dev::test::Options::get().evmVersion(), + RevertStrings::Default, dev::test::Options::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal() ); compiler.compileContract(*contract, map>{}, bytes()); diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 3bd8f662e..b30286a65 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -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() } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 314808429..8ff090c2c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -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() } diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index 0948dbb9b..eea3978f9 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -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); diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 551596456..349072878 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -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 const& function: _functions) context << context.functionEntryLabel(dynamic_cast(