From bf26d3be5a3ef5c9ed222a25fcf479974ab9444f Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 22 Nov 2022 13:05:20 +0100 Subject: [PATCH] Add experimental EOF options for CLI and Standard JSON. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil ƚliwak --- libsolidity/codegen/ir/IRGenerator.cpp | 1 + libsolidity/codegen/ir/IRGenerator.h | 3 ++ libsolidity/interface/CompilerStack.cpp | 26 ++++++++++++- libsolidity/interface/CompilerStack.h | 5 +++ libsolidity/interface/StandardCompiler.cpp | 11 ++++++ libsolidity/interface/StandardCompiler.h | 1 + libyul/YulStack.cpp | 2 +- libyul/YulStack.h | 4 ++ libyul/backends/evm/EVMObjectCompiler.cpp | 17 ++++++-- libyul/backends/evm/EVMObjectCompiler.h | 16 ++++++-- solc/CommandLineInterface.cpp | 2 + solc/CommandLineParser.cpp | 27 ++++++++++++- solc/CommandLineParser.h | 5 ++- test/Common.cpp | 13 ++++++- test/Common.h | 2 + test/TestCase.h | 1 + test/libsolidity/InlineAssembly.cpp | 3 ++ test/libsolidity/Metadata.cpp | 39 +++++++++++++++++++ test/libsolidity/SemanticTest.cpp | 7 ++-- test/libsolidity/SemanticTest.h | 2 + .../SolidityExecutionFramework.cpp | 2 + test/libsolidity/SolidityExecutionFramework.h | 3 ++ test/libyul/Common.cpp | 1 + test/libyul/EVMCodeTransformTest.cpp | 4 +- test/libyul/EwasmTranslationTest.cpp | 1 + test/libyul/ObjectCompilerTest.cpp | 1 + test/libyul/ObjectParser.cpp | 2 + test/libyul/YulInterpreterTest.cpp | 1 + test/soltest.cpp | 1 + test/tools/isoltest.cpp | 1 + .../tools/ossfuzz/StackReuseCodegenFuzzer.cpp | 4 +- test/tools/ossfuzz/YulEvmoneInterface.h | 6 ++- .../ossfuzz/strictasm_assembly_ossfuzz.cpp | 1 + test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp | 1 + test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp | 1 + test/tools/ossfuzz/yulProtoFuzzer.cpp | 1 + test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp | 1 + test/tools/yulrun.cpp | 1 + 38 files changed, 198 insertions(+), 22 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index a13a35301..371301804 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -97,6 +97,7 @@ pair IRGenerator::run( yul::YulStack asmStack( m_evmVersion, + m_eofVersion, yul::YulStack::Language::StrictAssembly, m_optimiserSettings, m_context.debugInfoSelection() diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index f89dc127a..00387842e 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -46,6 +46,7 @@ public: IRGenerator( langutil::EVMVersion _evmVersion, + std::optional _eofVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, std::map _sourceIndices, @@ -53,6 +54,7 @@ public: langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), + m_eofVersion(_eofVersion), m_optimiserSettings(_optimiserSettings), m_context( _evmVersion, @@ -138,6 +140,7 @@ private: std::string dispenseLocationComment(ASTNode const& _node); langutil::EVMVersion const m_evmVersion; + std::optional const m_eofVersion; OptimiserSettings const m_optimiserSettings; IRGenerationContext m_context; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a936b055d..96a298bf0 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -225,6 +225,15 @@ void CompilerStack::setEVMVersion(langutil::EVMVersion _version) m_evmVersion = _version; } +void CompilerStack::setEOFVersion(std::optional _version) +{ + if (m_stackState >= CompilationSuccessful) + solThrow(CompilerError, "Must set EOF version before compiling."); + if (_version && _version != 1) + solThrow(CompilerError, "Invalid EOF version."); + m_eofVersion = _version; +} + void CompilerStack::setModelCheckerSettings(ModelCheckerSettings _settings) { if (m_stackState >= ParsedAndImported) @@ -1299,6 +1308,7 @@ void CompilerStack::compileContract( ) { solAssert(!m_viaIR, ""); + solUnimplementedAssert(!m_eofVersion.has_value(), "Experimental EOF support is only available for via-IR compilation."); solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) solThrow(CompilerError, "Called compile with errors."); @@ -1364,7 +1374,15 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) for (auto const& pair: m_contracts) otherYulSources.emplace(pair.second.contract, pair.second.yulIR); - IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), m_debugInfoSelection, this); + IRGenerator generator( + m_evmVersion, + m_eofVersion, + m_revertStrings, + m_optimiserSettings, + sourceIndices(), + m_debugInfoSelection, + this + ); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run( _contract, createCBORMetadata(compiledContract, /* _forIR */ true), @@ -1389,6 +1407,7 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) // Re-parse the Yul IR in EVM dialect yul::YulStack stack( m_evmVersion, + m_eofVersion, yul::YulStack::Language::StrictAssembly, m_optimiserSettings, m_debugInfoSelection @@ -1421,6 +1440,7 @@ void CompilerStack::generateEwasm(ContractDefinition const& _contract) // Re-parse the Yul IR in EVM dialect yul::YulStack stack( m_evmVersion, + m_eofVersion, yul::YulStack::Language::StrictAssembly, m_optimiserSettings, m_debugInfoSelection @@ -1571,6 +1591,8 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con if (_forIR) meta["settings"]["viaIR"] = _forIR; meta["settings"]["evmVersion"] = m_evmVersion.name(); + if (m_eofVersion.has_value()) + meta["settings"]["eofVersion"] = *m_eofVersion; meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] = *_contract.contract->annotation().canonicalName; @@ -1695,7 +1717,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) else solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash"); - if (experimentalMode) + if (experimentalMode || m_eofVersion.has_value()) encoder.pushBool("experimental", true); if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag) encoder.pushBytes("solc", VersionCompactBytes); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 2ca7ba091..099c1f003 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -181,6 +181,10 @@ public: /// Must be set before parsing. void setEVMVersion(langutil::EVMVersion _version = langutil::EVMVersion{}); + /// Set the EOF version used before running compile. + /// If set to std::nullopt (the default), legacy non-EOF bytecode is generated. + void setEOFVersion(std::optional version); + /// Set model checker settings. void setModelCheckerSettings(ModelCheckerSettings _settings); @@ -498,6 +502,7 @@ private: State m_stopAfter = State::CompilationSuccessful; bool m_viaIR = false; langutil::EVMVersion m_evmVersion; + std::optional m_eofVersion; ModelCheckerSettings m_modelCheckerSettings; std::map> m_requestedContractNames; bool m_generateEvmBytecode = true; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 676f02d62..823c7c2f2 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -800,6 +800,16 @@ std::variant StandardCompiler: ret.evmVersion = *version; } + if (settings.isMember("eofVersion")) + { + if (!settings["eofVersion"].isUInt()) + return formatFatalError(Error::Type::JSONError, "eofVersion must be an unsigned integer."); + auto eofVersion = settings["evmVersion"].asUInt(); + if (eofVersion != 1) + return formatFatalError(Error::Type::JSONError, "Invalid EOF version requested."); + ret.eofVersion = 1; + } + if (settings.isMember("debug")) { if (auto result = checkKeys(settings["debug"], {"revertStrings", "debugInfo"}, "settings.debug")) @@ -1413,6 +1423,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) YulStack stack( _inputsAndSettings.evmVersion, + _inputsAndSettings.eofVersion, YulStack::Language::StrictAssembly, _inputsAndSettings.optimiserSettings, _inputsAndSettings.debugInfoSelection.has_value() ? diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 3e94f0231..f06dd0c5a 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -77,6 +77,7 @@ private: std::map sources; std::map smtLib2Responses; langutil::EVMVersion evmVersion; + std::optional eofVersion; std::vector remappings; RevertStrings revertStrings = RevertStrings::Default; OptimiserSettings optimiserSettings = OptimiserSettings::minimal(); diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 9bd80d256..b33026949 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -164,7 +164,7 @@ void YulStack::compileEVM(AbstractAssembly& _assembly, bool _optimize) const break; } - EVMObjectCompiler::compile(*m_parserResult, _assembly, *dialect, _optimize); + EVMObjectCompiler::compile(*m_parserResult, _assembly, *dialect, _optimize, m_eofVersion); } void YulStack::optimize(Object& _object, bool _isCreation) diff --git a/libyul/YulStack.h b/libyul/YulStack.h index 77d0025f1..5c57b56fa 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -72,6 +72,7 @@ public: YulStack(): YulStack( langutil::EVMVersion{}, + std::nullopt, Language::Assembly, solidity::frontend::OptimiserSettings::none(), langutil::DebugInfoSelection::Default() @@ -80,12 +81,14 @@ public: YulStack( langutil::EVMVersion _evmVersion, + std::optional _eofVersion, Language _language, solidity::frontend::OptimiserSettings _optimiserSettings, langutil::DebugInfoSelection const& _debugInfoSelection ): m_language(_language), m_evmVersion(_evmVersion), + m_eofVersion(_eofVersion), m_optimiserSettings(std::move(_optimiserSettings)), m_debugInfoSelection(_debugInfoSelection), m_errorReporter(m_errors) @@ -146,6 +149,7 @@ private: Language m_language = Language::Assembly; langutil::EVMVersion m_evmVersion; + std::optional m_eofVersion; solidity::frontend::OptimiserSettings m_optimiserSettings; langutil::DebugInfoSelection m_debugInfoSelection{}; diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index 4dbf5cc1a..e7eae69ba 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -35,9 +35,15 @@ using namespace solidity::yul; using namespace std; -void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _optimize) +void EVMObjectCompiler::compile( + Object& _object, + AbstractAssembly& _assembly, + EVMDialect const& _dialect, + bool _optimize, + std::optional _eofVersion +) { - EVMObjectCompiler compiler(_assembly, _dialect); + EVMObjectCompiler compiler(_assembly, _dialect, _eofVersion); compiler.run(_object, _optimize); } @@ -54,7 +60,7 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name.str()); context.subIDs[subObject->name] = subAssemblyAndID.second; subObject->subId = subAssemblyAndID.second; - compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize); + compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize, m_eofVersion); } else { @@ -68,6 +74,11 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) yulAssert(_object.analysisInfo, "No analysis info."); yulAssert(_object.code, "No code."); + if (m_eofVersion.has_value()) + yulAssert( + _optimize && (m_dialect.evmVersion() == langutil::EVMVersion()), + "Experimental EOF support is only available for optimized via-IR compilation and the most recent EVM version." + ); if (_optimize && m_dialect.evmVersion().canOverchargeGasForCall()) { auto stackErrors = OptimizedEVMCodeTransform::run( diff --git a/libyul/backends/evm/EVMObjectCompiler.h b/libyul/backends/evm/EVMObjectCompiler.h index 02ccc9181..df8d71c2c 100644 --- a/libyul/backends/evm/EVMObjectCompiler.h +++ b/libyul/backends/evm/EVMObjectCompiler.h @@ -21,6 +21,9 @@ #pragma once +#include +#include + namespace solidity::yul { struct Object; @@ -30,16 +33,23 @@ struct EVMDialect; class EVMObjectCompiler { public: - static void compile(Object& _object, AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _optimize); + static void compile( + Object& _object, + AbstractAssembly& _assembly, + EVMDialect const& _dialect, + bool _optimize, + std::optional _eofVersion + ); private: - EVMObjectCompiler(AbstractAssembly& _assembly, EVMDialect const& _dialect): - m_assembly(_assembly), m_dialect(_dialect) + EVMObjectCompiler(AbstractAssembly& _assembly, EVMDialect const& _dialect, std::optional _eofVersion): + m_assembly(_assembly), m_dialect(_dialect), m_eofVersion(_eofVersion) {} void run(Object& _object, bool _optimize); AbstractAssembly& m_assembly; EVMDialect const& m_dialect; + std::optional m_eofVersion; }; } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 3e44f22c0..0f751c203 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -708,6 +708,7 @@ void CommandLineInterface::compile() m_compiler->setLibraries(m_options.linker.libraries); m_compiler->setViaIR(m_options.output.viaIR); m_compiler->setEVMVersion(m_options.output.evmVersion); + m_compiler->setEOFVersion(m_options.output.eofVersion); m_compiler->setRevertStringBehaviour(m_options.output.revertStrings); if (m_options.output.debugInfoSelection.has_value()) m_compiler->selectDebugInfo(m_options.output.debugInfoSelection.value()); @@ -1042,6 +1043,7 @@ void CommandLineInterface::assemble(yul::YulStack::Language _language, yul::YulS auto& stack = yulStacks[src.first] = yul::YulStack( m_options.output.evmVersion, + m_options.output.eofVersion, _language, m_options.optimiserSettings(), m_options.output.debugInfoSelection.has_value() ? diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 2a1ce0228..406e8111d 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -47,6 +47,7 @@ static string const g_strErrorRecovery = "error-recovery"; static string const g_strEVM = "evm"; static string const g_strEVMVersion = "evm-version"; static string const g_strEwasm = "ewasm"; +static string const g_strEOFVersion = "experimental-eof-version"; static string const g_strViaIR = "via-ir"; static string const g_strExperimentalViaIR = "experimental-via-ir"; static string const g_strGas = "gas"; @@ -231,6 +232,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex output.revertStrings == _other.output.revertStrings && output.debugInfoSelection == _other.output.debugInfoSelection && output.stopAfter == _other.output.stopAfter && + output.eofVersion == _other.output.eofVersion && input.mode == _other.input.mode && assembly.targetMachine == _other.assembly.targetMachine && assembly.inputLanguage == _other.assembly.inputLanguage && @@ -509,9 +511,11 @@ void CommandLineParser::parseOutputSelection() "The following outputs are not supported in " + g_inputModeName.at(m_options.input.mode) + " mode: " + joinOptionNames(unsupportedOutputs) + "." ); + + // TODO: restrict EOF version to correct EVM version. } -po::options_description CommandLineParser::optionsDescription() +po::options_description CommandLineParser::optionsDescription(bool _forHelp) { // Declare the supported options. po::options_description desc((R"(solc, the Solidity commandline compiler. @@ -588,6 +592,18 @@ General Information)").c_str(), "Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, " "byzantium, constantinople, petersburg, istanbul, berlin, london or paris." ) + ; + if (!_forHelp) // Note: We intentionally keep this undocumented for now. + outputOptions.add_options() + ( + g_strEOFVersion.c_str(), + // Declared as uint64_t, since uint8_t will be parsed as character by boost. + po::value()->value_name("version")->implicit_value(1), + "Select desired EOF version. Currently the only valid value is 1. " + "If not specified, legacy non-EOF bytecode will be generated." + ) + ; + outputOptions.add_options() ( g_strExperimentalViaIR.c_str(), "Deprecated synonym of --via-ir." @@ -1113,6 +1129,15 @@ void CommandLineParser::processArgs() m_options.output.evmVersion = *versionOption; } + if (m_args.count(g_strEOFVersion)) + { + // Request as uint64_t, since uint8_t will be parsed as character by boost. + uint64_t versionOption = m_args[g_strEOFVersion].as(); + if (versionOption != 1) + solThrow(CommandLineValidationError, "Invalid option for --" + g_strEOFVersion + ": " + to_string(versionOption)); + m_options.output.eofVersion = 1; + } + m_options.optimizer.enabled = (m_args.count(g_strOptimize) > 0); m_options.optimizer.noOptimizeYul = (m_args.count(g_strNoOptimizeYul) > 0); if (!m_args[g_strOptimizeRuns].defaulted()) diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index d695a6eb6..7bcc8a0f0 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -186,6 +186,7 @@ struct CommandLineOptions RevertStrings revertStrings = RevertStrings::Default; std::optional debugInfoSelection; CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful; + std::optional eofVersion; } output; struct @@ -247,12 +248,12 @@ public: CommandLineOptions const& options() const { return m_options; } - static void printHelp(std::ostream& _out) { _out << optionsDescription(); } + static void printHelp(std::ostream& _out) { _out << optionsDescription(true /* _forHelp */); } private: /// @returns a specification of all named command-line options accepted by the compiler. /// The object can be used to parse command-line arguments or to generate the help screen. - static boost::program_options::options_description optionsDescription(); + static boost::program_options::options_description optionsDescription(bool _forHelp = false); /// @returns a specification of all positional command-line arguments accepted by the compiler. /// The object can be used to parse command-line arguments or to generate the help screen. diff --git a/test/Common.cpp b/test/Common.cpp index 7cd869934..3af23c782 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -103,7 +103,9 @@ CommonOptions::CommonOptions(std::string _caption): void CommonOptions::addOptions() { options.add_options() - ("evm-version", po::value(&evmVersionString), "which evm version to use") + ("evm-version", po::value(&evmVersionString), "which EVM version to use") + // "eof-version" is declared as uint64_t, since uint8_t will be parsed as character by boost. + ("eof-version", po::value()->implicit_value(1u), "which EOF version to use") ("testpath", po::value(&this->testPath)->default_value(solidity::test::testPath()), "path to test files") ("vm", po::value>(&vmPaths), "path to evmc library, can be supplied multiple times.") ("ewasm", po::bool_switch(&ewasm)->default_value(ewasm), "tries to automatically find an ewasm vm and enable ewasm test-execution.") @@ -170,6 +172,14 @@ bool CommonOptions::parse(int argc, char const* const* argv) auto parsedOptions = cmdLineParser.run(); po::store(parsedOptions, arguments); po::notify(arguments); + if (arguments.count("eof-version")) + { + // Request as uint64_t, since uint8_t will be parsed as character by boost. + uint64_t eofVersion = arguments["eof-version"].as(); + if (eofVersion != 1) + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid EOF version: " + to_string(eofVersion))); + m_eofVersion = 1; + } for (auto const& parsedOption: parsedOptions.options) if (parsedOption.position_key >= 0) @@ -261,7 +271,6 @@ langutil::EVMVersion CommonOptions::evmVersion() const return langutil::EVMVersion(); } - CommonOptions const& CommonOptions::get() { if (!m_singleton) diff --git a/test/Common.h b/test/Common.h index d428e0261..91858d4b4 100644 --- a/test/Common.h +++ b/test/Common.h @@ -72,6 +72,7 @@ struct CommonOptions size_t selectedBatch = 0; langutil::EVMVersion evmVersion() const; + std::optional eofVersion() const { return m_eofVersion; } virtual void addOptions(); // @returns true if the program should continue, false if it should exit immediately without @@ -98,6 +99,7 @@ protected: private: std::string evmVersionString; + std::optional m_eofVersion; static std::unique_ptr m_singleton; }; diff --git a/test/TestCase.h b/test/TestCase.h index 181fb0120..7a5c75c50 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -39,6 +39,7 @@ public: { std::string filename; langutil::EVMVersion evmVersion; + std::optional eofVersion; std::vector vmPaths; bool enforceCompileToEwasm = false; bool enforceGasCost = false; diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 314a0d760..4a8a9d617 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -62,6 +62,7 @@ std::optional parseAndReturnFirstError( { YulStack stack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), _language, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::None() @@ -133,6 +134,7 @@ void parsePrintCompare(string const& _source, bool _canWarn = false) { YulStack stack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::Assembly, OptimiserSettings::none(), DebugInfoSelection::None() @@ -223,6 +225,7 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode) string parsed = "object \"object\" {\n code { let x := \"\\xe1\\xae\\xac\" }\n}\n"; YulStack stack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::Assembly, OptimiserSettings::none(), DebugInfoSelection::None() diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 6814ae80a..1dc3dfd26 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -226,6 +226,45 @@ BOOST_AUTO_TEST_CASE(metadata_stamp_experimental) } } +BOOST_AUTO_TEST_CASE(metadata_eof_experimental) +{ + // Check that setting an EOF version results in the experimental flag being set. + char const* sourceCode = R"( + pragma solidity >=0.0; + contract test { + function g(function(uint) external returns (uint) x) public {} + } + )"; + for (auto metadataFormat: std::set{ + CompilerStack::MetadataFormat::NoMetadata, + CompilerStack::MetadataFormat::WithReleaseVersionTag, + CompilerStack::MetadataFormat::WithPrereleaseVersionTag + }) + { + CompilerStack compilerStack; + compilerStack.setMetadataFormat(metadataFormat); + compilerStack.setSources({{"", sourceCode}}); + compilerStack.setEVMVersion({}); + compilerStack.setViaIR(true); + compilerStack.setEOFVersion(1); + compilerStack.setOptimiserSettings(true); + BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); + bytes const& bytecode = compilerStack.runtimeObject("test").bytecode; + string const& metadata = compilerStack.metadata("test"); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); + + auto const cborMetadata = requireParsedCBORMetadata(bytecode, metadataFormat); + + if (metadataFormat == CompilerStack::MetadataFormat::NoMetadata) + BOOST_CHECK(cborMetadata.count("experimental") == 0); + else + { + BOOST_CHECK(cborMetadata.count("experimental") == 1); + BOOST_CHECK(cborMetadata.at("experimental") == "true"); + } + } +} + BOOST_AUTO_TEST_CASE(metadata_relevant_sources) { CompilerStack compilerStack; diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 0749f5714..4746999a3 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -48,12 +48,13 @@ namespace fs = boost::filesystem; SemanticTest::SemanticTest( string const& _filename, langutil::EVMVersion _evmVersion, + optional _eofVersion, vector const& _vmPaths, bool _enforceCompileToEwasm, bool _enforceGasCost, u256 _enforceGasCostMinValue ): - SolidityExecutionFramework(_evmVersion, _vmPaths, false), + SolidityExecutionFramework(_evmVersion, _eofVersion, _vmPaths, false), EVMVersionRestrictedTestCase(_filename), m_sources(m_reader.sources()), m_lineOffset(m_reader.lineNumber()), @@ -296,13 +297,13 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref { TestResult result = TestResult::Success; - if (m_testCaseWantsLegacyRun) + if (m_testCaseWantsLegacyRun && !m_eofVersion.has_value()) result = runTest(_stream, _linePrefix, _formatted, false, false); if (m_testCaseWantsYulRun && result == TestResult::Success) result = runTest(_stream, _linePrefix, _formatted, true, false); - if ((m_testCaseWantsEwasmRun || m_enforceCompileToEwasm) && result == TestResult::Success) + if (!m_eofVersion.has_value() && (m_testCaseWantsEwasmRun || m_enforceCompileToEwasm) && result == TestResult::Success) { // TODO: Once we have full Ewasm support, we could remove try/catch here. try diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index dd189f1b5..c5abb93e2 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -51,6 +51,7 @@ public: return std::make_unique( _options.filename, _options.evmVersion, + _options.eofVersion, _options.vmPaths, _options.enforceCompileToEwasm, _options.enforceGasCost, @@ -61,6 +62,7 @@ public: explicit SemanticTest( std::string const& _filename, langutil::EVMVersion _evmVersion, + std::optional _eofVersion, std::vector const& _vmPaths, bool _enforceCompileToEwasm = false, bool _enforceGasCost = false, diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index 0450f290a..3e8372ef7 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -58,6 +58,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( m_compiler.setLibraries(_libraryAddresses); m_compiler.setRevertStringBehaviour(m_revertStrings); m_compiler.setEVMVersion(m_evmVersion); + m_compiler.setEOFVersion(m_eofVersion); m_compiler.setOptimiserSettings(m_optimiserSettings); m_compiler.enableEvmBytecodeGeneration(!m_compileViaYul); m_compiler.enableIRGeneration(m_compileViaYul); @@ -102,6 +103,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( yul::YulStack asmStack( m_evmVersion, + m_eofVersion, yul::YulStack::Language::StrictAssembly, optimiserSettings, DebugInfoSelection::All() diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index a273f2ad1..4865c68a2 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -42,10 +42,12 @@ public: SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} explicit SolidityExecutionFramework( langutil::EVMVersion _evmVersion, + std::optional _eofVersion, std::vector const& _vmPaths, bool _appendCBORMetadata = true ): ExecutionFramework(_evmVersion, _vmPaths), + m_eofVersion(_eofVersion), m_showMetadata(solidity::test::CommonOptions::get().showMetadata), m_appendCBORMetadata(_appendCBORMetadata) {} @@ -82,6 +84,7 @@ public: static std::string addPreamble(std::string const& _sourceCode); protected: using CompilerStack = solidity::frontend::CompilerStack; + std::optional m_eofVersion; CompilerStack m_compiler; bool m_compileViaYul = false; bool m_compileToEwasm = false; diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index f40f422a8..11896d2f9 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -57,6 +57,7 @@ pair, shared_ptr> yul::test::parse(strin { YulStack stack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), _yul ? YulStack::Language::Yul : YulStack::Language::StrictAssembly, solidity::test::CommonOptions::get().optimize ? solidity::frontend::OptimiserSettings::standard() : diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index c1f6ae5df..744fa8c03 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -53,6 +53,7 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _ settings.optimizeStackAllocation = m_stackOpt; YulStack stack( EVMVersion{}, + nullopt, YulStack::Language::StrictAssembly, settings, DebugInfoSelection::All() @@ -71,7 +72,8 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _ *stack.parserResult(), adapter, EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}), - m_stackOpt + m_stackOpt, + nullopt ); std::ostringstream output; diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index 075d11795..f40bc2e42 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -82,6 +82,7 @@ bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bo { m_stack = YulStack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::All() diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index dcb7158c2..190001a57 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -65,6 +65,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li { YulStack stack( EVMVersion(), + nullopt, m_wasm ? YulStack::Language::Ewasm : YulStack::Language::StrictAssembly, OptimiserSettings::preset(m_optimisationPreset), DebugInfoSelection::All() diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 9e429177d..e78a8b0eb 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -59,6 +59,7 @@ pair parse(string const& _source) { YulStack asmStack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::All() @@ -181,6 +182,7 @@ BOOST_AUTO_TEST_CASE(to_string) expectation = boost::replace_all_copy(expectation, "\t", " "); YulStack asmStack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::All() diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index 47b167c91..3d1974e96 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -68,6 +68,7 @@ bool YulInterpreterTest::parse(ostream& _stream, string const& _linePrefix, bool { YulStack stack( solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::All() diff --git a/test/soltest.cpp b/test/soltest.cpp index c104cd8b4..2120acc2d 100644 --- a/test/soltest.cpp +++ b/test/soltest.cpp @@ -144,6 +144,7 @@ int registerTests( TestCase::Config config{ fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), + solidity::test::CommonOptions::get().eofVersion(), solidity::test::CommonOptions::get().vmPaths, _enforceCompileToEwasm, solidity::test::CommonOptions::get().enforceGasTest, diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index cf1588b44..c2035ab18 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -159,6 +159,7 @@ TestTool::Result TestTool::process() m_test = m_testCaseCreator(TestCase::Config{ m_path.string(), m_options.evmVersion(), + m_options.eofVersion(), m_options.vmPaths, m_options.enforceCompileToEwasm, m_options.enforceGasTest, diff --git a/test/tools/ossfuzz/StackReuseCodegenFuzzer.cpp b/test/tools/ossfuzz/StackReuseCodegenFuzzer.cpp index 10ce76f48..d7779a58d 100644 --- a/test/tools/ossfuzz/StackReuseCodegenFuzzer.cpp +++ b/test/tools/ossfuzz/StackReuseCodegenFuzzer.cpp @@ -80,7 +80,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) bytes unoptimisedByteCode; try { - unoptimisedByteCode = YulAssembler{version, settings, yul_source}.assemble(); + unoptimisedByteCode = YulAssembler{version, nullopt, settings, yul_source}.assemble(); } catch (solidity::yul::StackTooDeepError const&) { @@ -123,7 +123,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) bytes optimisedByteCode; try { - optimisedByteCode = YulAssembler{version, settings, yul_source}.assemble(); + optimisedByteCode = YulAssembler{version, nullopt, settings, yul_source}.assemble(); } catch (solidity::yul::StackTooDeepError const&) { diff --git a/test/tools/ossfuzz/YulEvmoneInterface.h b/test/tools/ossfuzz/YulEvmoneInterface.h index a875eeb81..9224a949d 100644 --- a/test/tools/ossfuzz/YulEvmoneInterface.h +++ b/test/tools/ossfuzz/YulEvmoneInterface.h @@ -31,12 +31,14 @@ class YulAssembler { public: YulAssembler( - langutil::EVMVersion _version, + langutil::EVMVersion _evmVersion, + std::optional _eofVersion, solidity::frontend::OptimiserSettings _optSettings, std::string const& _yulSource ): m_stack( - _version, + _evmVersion, + _eofVersion, solidity::yul::YulStack::Language::StrictAssembly, _optSettings, langutil::DebugInfoSelection::All() diff --git a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp index a353ca10b..b9473f613 100644 --- a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp @@ -39,6 +39,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) string input(reinterpret_cast(_data), _size); YulStack stack( langutil::EVMVersion(), + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), langutil::DebugInfoSelection::All() diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index dd66102c1..5c923a3ea 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -62,6 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) YulStack stack( langutil::EVMVersion(), + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), DebugInfoSelection::All() diff --git a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp index 94a837d5a..db35cc865 100644 --- a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp @@ -40,6 +40,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) string input(reinterpret_cast(_data), _size); YulStack stack( langutil::EVMVersion(), + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), DebugInfoSelection::All() diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp index 74183aa3f..c2ac68093 100644 --- a/test/tools/ossfuzz/yulProtoFuzzer.cpp +++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp @@ -64,6 +64,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) // YulStack entry point YulStack stack( version, + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), DebugInfoSelection::All() diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index 2335bfbf5..b1725a8fa 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -63,6 +63,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) // YulStack entry point YulStack stack( version, + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::full(), DebugInfoSelection::All() diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index eee342470..2e1bcc013 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -59,6 +59,7 @@ pair, shared_ptr> parse(string const& _source { YulStack stack( langutil::EVMVersion(), + nullopt, YulStack::Language::StrictAssembly, solidity::frontend::OptimiserSettings::none(), DebugInfoSelection::Default()