Skip to content

Commit ff28c82

Browse files
committed
[solc] Add support to import evm assembly json.
1 parent 1f645f1 commit ff28c82

File tree

4 files changed

+88
-14
lines changed

4 files changed

+88
-14
lines changed

solc/CommandLineInterface.cpp

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ using namespace solidity::langutil;
9191
namespace
9292
{
9393

94-
set<frontend::InputMode> const CompilerInputModes{
94+
set<frontend::InputMode> const CompilerInputModes {
9595
frontend::InputMode::Compiler,
96-
frontend::InputMode::CompilerWithASTImport
96+
frontend::InputMode::CompilerWithASTImport,
97+
frontend::InputMode::CompilerWithEvmAssemblyJsonImport
9798
};
9899

99100
} // anonymous namespace
@@ -203,7 +204,7 @@ void CommandLineInterface::handleOpcode(string const& _contract)
203204
else
204205
{
205206
sout() << "Opcodes:" << endl;
206-
sout() << std::uppercase << evmasm::disassemble(m_compiler->object(_contract).bytecode);
207+
sout() << uppercase << evmasm::disassemble(m_compiler->object(_contract).bytecode);
207208
sout() << endl;
208209
}
209210
}
@@ -352,8 +353,8 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra
352353
solAssert(CompilerInputModes.count(m_options.input.mode) == 1);
353354

354355
bool enabled = false;
355-
std::string suffix;
356-
std::string title;
356+
string suffix;
357+
string title;
357358

358359
if (_natspecDev)
359360
{
@@ -370,7 +371,7 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra
370371

371372
if (enabled)
372373
{
373-
std::string output = jsonPrint(
374+
string output = jsonPrint(
374375
removeNullMembers(
375376
_natspecDev ?
376377
m_compiler->natspecDev(_contract) :
@@ -462,7 +463,7 @@ void CommandLineInterface::readInputFiles()
462463
for (boost::filesystem::path const& allowedDirectory: m_options.input.allowedDirectories)
463464
m_fileReader.allowDirectory(allowedDirectory);
464465

465-
map<std::string, set<boost::filesystem::path>> collisions =
466+
map<string, set<boost::filesystem::path>> collisions =
466467
m_fileReader.detectSourceUnitNameCollisions(m_options.input.paths);
467468
if (!collisions.empty())
468469
{
@@ -552,7 +553,7 @@ map<string, Json::Value> CommandLineInterface::parseAstFromInput()
552553

553554
for (auto& src: ast["sources"].getMemberNames())
554555
{
555-
std::string astKey = ast["sources"][src].isMember("ast") ? "ast" : "AST";
556+
string astKey = ast["sources"][src].isMember("ast") ? "ast" : "AST";
556557

557558
astAssert(ast["sources"][src].isMember(astKey), "astkey is not member");
558559
astAssert(ast["sources"][src][astKey]["nodeType"].asString() == "SourceUnit", "Top-level node should be a 'SourceUnit'");
@@ -567,6 +568,25 @@ map<string, Json::Value> CommandLineInterface::parseAstFromInput()
567568
return sourceJsons;
568569
}
569570

571+
map<string, Json::Value> CommandLineInterface::parseEvmAssemblyJsonFromInput()
572+
{
573+
solAssert(m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport);
574+
solAssert(m_fileReader.sourceUnits().size() == 1);
575+
576+
map<string, Json::Value> sourceJsons;
577+
578+
for (auto const& iter: m_fileReader.sourceUnits())
579+
{
580+
Json::Value evmAsmJson;
581+
astAssert(jsonParseStrict(iter.second, evmAsmJson), "Input file could not be parsed to JSON");
582+
astAssert(evmAsmJson.isMember(".code"), "Invalid Format for assembly-JSON: Must have '.code'-object");
583+
astAssert(evmAsmJson.isMember(".data"), "Invalid Format for assembly-JSON: Must have '.data'-object");
584+
sourceJsons[iter.first] = evmAsmJson;
585+
}
586+
587+
return sourceJsons;
588+
}
589+
570590
void CommandLineInterface::createFile(string const& _fileName, string const& _data)
571591
{
572592
namespace fs = boost::filesystem;
@@ -670,6 +690,7 @@ void CommandLineInterface::processInput()
670690
break;
671691
case InputMode::Compiler:
672692
case InputMode::CompilerWithASTImport:
693+
case InputMode::CompilerWithEvmAssemblyJsonImport:
673694
compile();
674695
outputCompilationResults();
675696
}
@@ -738,7 +759,18 @@ void CommandLineInterface::compile()
738759

739760
m_compiler->setOptimiserSettings(m_options.optimiserSettings());
740761

741-
if (m_options.input.mode == InputMode::CompilerWithASTImport)
762+
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
763+
{
764+
try
765+
{
766+
m_compiler->importEvmAssemblyJson(parseEvmAssemblyJsonFromInput());
767+
}
768+
catch (Exception const& _exc)
769+
{
770+
solThrow(CommandLineExecutionError, "Failed to import Evm Assembly JSON: "s + _exc.what());
771+
}
772+
}
773+
else if (m_options.input.mode == InputMode::CompilerWithASTImport)
742774
{
743775
try
744776
{

solc/CommandLineInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class CommandLineInterface
115115
/// or standard-json output
116116
std::map<std::string, Json::Value> parseAstFromInput();
117117

118+
std::map<std::string, Json::Value> parseEvmAssemblyJsonFromInput();
119+
118120
/// Create a file in the given directory
119121
/// @arg _fileName the name of the file
120122
/// @arg _data to be written

solc/CommandLineParser.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static string const g_strExperimentalViaIR = "experimental-via-ir";
5252
static string const g_strGas = "gas";
5353
static string const g_strHelp = "help";
5454
static string const g_strImportAst = "import-ast";
55+
static string const g_strImportEvmAssemblerJson = "import-asm-json";
5556
static string const g_strInputFile = "input-file";
5657
static string const g_strYul = "yul";
5758
static string const g_strYulDialect = "yul-dialect";
@@ -139,6 +140,7 @@ static map<InputMode, string> const g_inputModeName = {
139140
{InputMode::StandardJson, "standard JSON"},
140141
{InputMode::Linker, "linker"},
141142
{InputMode::LanguageServer, "language server (LSP)"},
143+
{InputMode::CompilerWithEvmAssemblyJsonImport, "assembler (EVM ASM JSON import)"},
142144
};
143145

144146
void CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
@@ -463,6 +465,13 @@ void CommandLineParser::parseOutputSelection()
463465
CompilerOutputs::componentName(&CompilerOutputs::ewasm),
464466
CompilerOutputs::componentName(&CompilerOutputs::ewasmIR),
465467
};
468+
static set<string> const evmAssemblyJsonImportModeOutputs = {
469+
CompilerOutputs::componentName(&CompilerOutputs::asm_),
470+
CompilerOutputs::componentName(&CompilerOutputs::binary),
471+
CompilerOutputs::componentName(&CompilerOutputs::binaryRuntime),
472+
CompilerOutputs::componentName(&CompilerOutputs::opcodes),
473+
CompilerOutputs::componentName(&CompilerOutputs::asmJson),
474+
};
466475

467476
switch (_mode)
468477
{
@@ -474,6 +483,8 @@ void CommandLineParser::parseOutputSelection()
474483
case InputMode::Compiler:
475484
case InputMode::CompilerWithASTImport:
476485
return util::contains(compilerModeOutputs, _outputName);
486+
case InputMode::CompilerWithEvmAssemblyJsonImport:
487+
return util::contains(evmAssemblyJsonImportModeOutputs, _outputName);
477488
case InputMode::Assembler:
478489
return util::contains(assemblerModeOutputs, _outputName);
479490
case InputMode::StandardJson:
@@ -652,6 +663,10 @@ General Information)").c_str(),
652663
"Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by "
653664
"--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str()
654665
)
666+
(
667+
g_strImportEvmAssemblerJson.c_str(),
668+
"Import EVM Assembly JSON, assumes input holds the EVM Assembly in JSON format."
669+
)
655670
(
656671
g_strLSP.c_str(),
657672
"Switch to language server mode (\"LSP\"). Allows the compiler to be used as an analysis backend "
@@ -912,6 +927,8 @@ void CommandLineParser::processArgs()
912927
m_options.input.mode = InputMode::Linker;
913928
else if (m_args.count(g_strImportAst) > 0)
914929
m_options.input.mode = InputMode::CompilerWithASTImport;
930+
else if (m_args.count(g_strImportEvmAssemblerJson) > 0)
931+
m_options.input.mode = InputMode::CompilerWithEvmAssemblyJsonImport;
915932
else
916933
m_options.input.mode = InputMode::Compiler;
917934

@@ -977,9 +994,27 @@ void CommandLineParser::processArgs()
977994
for (auto& option: conflictingWithStopAfter)
978995
checkMutuallyExclusive({g_strStopAfter, option});
979996

997+
array<string, 11> const conflictingWithAsmJsonImport{
998+
CompilerOutputs::componentName(&CompilerOutputs::ir),
999+
CompilerOutputs::componentName(&CompilerOutputs::irOptimized),
1000+
CompilerOutputs::componentName(&CompilerOutputs::ewasm),
1001+
CompilerOutputs::componentName(&CompilerOutputs::ewasmIR),
1002+
g_strGas,
1003+
CompilerOutputs::componentName(&CompilerOutputs::metadata),
1004+
CompilerOutputs::componentName(&CompilerOutputs::natspecDev),
1005+
CompilerOutputs::componentName(&CompilerOutputs::natspecUser),
1006+
CompilerOutputs::componentName(&CompilerOutputs::signatureHashes),
1007+
CompilerOutputs::componentName(&CompilerOutputs::storageLayout),
1008+
CompilerOutputs::componentName(&CompilerOutputs::astCompactJson),
1009+
};
1010+
1011+
for (auto& option: conflictingWithAsmJsonImport)
1012+
checkMutuallyExclusive({g_strImportEvmAssemblerJson, option});
1013+
9801014
if (
9811015
m_options.input.mode != InputMode::Compiler &&
9821016
m_options.input.mode != InputMode::CompilerWithASTImport &&
1017+
m_options.input.mode != InputMode::CompilerWithEvmAssemblyJsonImport &&
9831018
m_options.input.mode != InputMode::Assembler
9841019
)
9851020
{
@@ -1013,7 +1048,7 @@ void CommandLineParser::processArgs()
10131048
if (m_args.count(g_strRevertStrings))
10141049
{
10151050
string revertStringsString = m_args[g_strRevertStrings].as<string>();
1016-
std::optional<RevertStrings> revertStrings = revertStringsFromString(revertStringsString);
1051+
optional<RevertStrings> revertStrings = revertStringsFromString(revertStringsString);
10171052
if (!revertStrings)
10181053
solThrow(
10191054
CommandLineValidationError,
@@ -1107,7 +1142,7 @@ void CommandLineParser::processArgs()
11071142
if (m_args.count(g_strEVMVersion))
11081143
{
11091144
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
1110-
std::optional<langutil::EVMVersion> versionOption = langutil::EVMVersion::fromString(versionOptionStr);
1145+
optional<langutil::EVMVersion> versionOption = langutil::EVMVersion::fromString(versionOptionStr);
11111146
if (!versionOption)
11121147
solThrow(CommandLineValidationError, "Invalid option for --" + g_strEVMVersion + ": " + versionOptionStr);
11131148
m_options.output.evmVersion = *versionOption;
@@ -1311,7 +1346,11 @@ void CommandLineParser::processArgs()
13111346
if (m_options.input.mode == InputMode::Compiler)
13121347
m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0);
13131348

1314-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport);
1349+
solAssert(
1350+
m_options.input.mode == InputMode::Compiler ||
1351+
m_options.input.mode == InputMode::CompilerWithASTImport ||
1352+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport
1353+
);
13151354
}
13161355

13171356
void CommandLineParser::parseCombinedJsonOption()

solc/CommandLineParser.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ enum class InputMode
5656
StandardJson,
5757
Linker,
5858
Assembler,
59-
LanguageServer
59+
LanguageServer,
60+
CompilerWithEvmAssemblyJsonImport
6061
};
6162

6263
struct CompilerOutputs
@@ -294,4 +295,4 @@ class CommandLineParser
294295
boost::program_options::variables_map m_args;
295296
};
296297

297-
}
298+
} // namespace solidity::frontend

0 commit comments

Comments
 (0)