Metadata stamp.

This commit is contained in:
chriseth 2016-11-14 11:46:43 +01:00
parent 55a719a79c
commit 5789eaa78d
16 changed files with 171 additions and 54 deletions

View File

@ -38,13 +38,14 @@ h256 swarmHashSimple(bytesConstRef _data, size_t _size)
return keccak256(toLittleEndian(_size) + _data.toBytes());
}
h256 swarmHashIntermediate(bytes const& _input, size_t _offset, size_t _length)
h256 swarmHashIntermediate(string const& _input, size_t _offset, size_t _length)
{
bytesConstRef ref;
bytes innerNodes;
if (_length <= 0x1000)
return swarmHashSimple(bytesConstRef(_input.data() + _offset, _length), _length);
ref = bytesConstRef(_input).cropped(_offset, _length);
else
{
bytes innerNodes;
size_t maxRepresentedSize = 0x1000;
while (maxRepresentedSize * (0x1000 / 32) < _length)
maxRepresentedSize *= (0x1000 / 32);
@ -53,11 +54,12 @@ h256 swarmHashIntermediate(bytes const& _input, size_t _offset, size_t _length)
size_t size = std::min(maxRepresentedSize, _length - i);
innerNodes += swarmHashIntermediate(_input, _offset + i, size).asBytes();
}
return swarmHashSimple(bytesConstRef(&innerNodes), _length);
ref = bytesConstRef(&innerNodes);
}
return swarmHashSimple(ref, _length);
}
h256 dev::swarmHash(bytes const& _input)
h256 dev::swarmHash(string const& _input)
{
return swarmHashIntermediate(_input, 0, _input.size());
}

View File

@ -20,12 +20,13 @@
#pragma once
#include <libdevcore/FixedHash.h>
#include <libdevcore/Common.h>
#include <string>
namespace dev
{
/// Compute the "swarm hash" of @a _data
h256 swarmHash(bytes const& _data);
h256 swarmHash(std::string const& _data);
}

View File

@ -63,6 +63,14 @@ SourceUnitAnnotation& SourceUnit::annotation() const
return static_cast<SourceUnitAnnotation&>(*m_annotation);
}
string Declaration::sourceUnitName() const
{
ASTNode const* scope = m_scope;
while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration const*>(scope)->m_scope)
scope = dynamic_cast<Declaration const*>(scope)->m_scope;
return dynamic_cast<SourceUnit const&>(*scope).annotation().path;
}
ImportAnnotation& ImportDirective::annotation() const
{
if (!m_annotation)

View File

@ -158,6 +158,10 @@ public:
ASTNode const* scope() const { return m_scope; }
void setScope(ASTNode const* _scope) { m_scope = _scope; }
/// @returns the source name this declaration is present in.
/// Can be combined with annotation().canonicalName to form a globally unique name.
std::string sourceUnitName() const;
virtual bool isLValue() const { return false; }
virtual bool isPartOfExternalInterface() const { return false; }

View File

@ -30,7 +30,8 @@ using namespace dev::solidity;
void Compiler::compileContract(
ContractDefinition const& _contract,
std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts
std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts,
h256 const& _metadataHash
)
{
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize);
@ -43,11 +44,8 @@ void Compiler::compileContract(
m_context.optimise(m_optimize, m_optimizeRuns);
if (_contract.isLibrary())
{
solAssert(m_runtimeSub != size_t(-1), "");
m_context.injectVersionStampIntoSub(m_runtimeSub);
}
solAssert(m_runtimeSub != size_t(-1), "");
m_context.injectMetadataHashIntoSub(m_runtimeSub, _metadataHash);
}
void Compiler::compileClone(

View File

@ -42,7 +42,8 @@ public:
void compileContract(
ContractDefinition const& _contract,
std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts,
h256 const& _metadataHash
);
/// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given
/// contract at runtime, but contains the full creation-time code.

View File

@ -227,6 +227,13 @@ void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
sub.injectStart(fromBigEndian<u256>(binaryVersion()));
}
void CompilerContext::injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash)
{
eth::Assembly& sub = m_asm->sub(_subIndex);
sub.injectStart(Instruction::POP);
sub.injectStart(u256(_metadataHash));
}
FunctionDefinition const& CompilerContext::resolveVirtualFunction(
FunctionDefinition const& _function,
vector<ContractDefinition const*>::const_iterator _searchStart

View File

@ -155,6 +155,9 @@ public:
/// Prepends "PUSH <compiler version number> POP"
void injectVersionStampIntoSub(size_t _subIndex);
/// Prepends "PUSH <metadata hash> POP"
void injectMetadataHashIntoSub(size_t _subIndex, h256 const& _metadataHash);
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); }
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.

View File

@ -38,7 +38,10 @@
#include <libsolidity/formal/Why3Translator.h>
#include <libevmasm/Exceptions.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/SwarmHash.h>
#include <json/json.h>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
@ -79,6 +82,8 @@ void CompilerStack::reset(bool _keepSources)
{
m_sources.clear();
}
m_optimize = false;
m_optimizeRuns = 200;
m_globalContext.reset();
m_sourceOrder.clear();
m_contracts.clear();
@ -217,17 +222,22 @@ vector<string> CompilerStack::contractNames() const
}
bool CompilerStack::compile(bool _optimize, unsigned _runs)
bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries)
{
if (!m_parseSuccessful)
if (!parse())
return false;
m_optimize = _optimize;
m_optimizeRuns = _runs;
m_libraries = _libraries;
map<ContractDefinition const*, eth::Assembly const*> compiledContracts;
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
compileContract(_optimize, _runs, *contract, compiledContracts);
compileContract(*contract, compiledContracts);
this->link();
return true;
}
@ -236,13 +246,13 @@ bool CompilerStack::compile(string const& _sourceCode, bool _optimize)
return parse(_sourceCode) && compile(_optimize);
}
void CompilerStack::link(const std::map<string, h160>& _libraries)
void CompilerStack::link()
{
for (auto& contract: m_contracts)
{
contract.second.object.link(_libraries);
contract.second.runtimeObject.link(_libraries);
contract.second.cloneObject.link(_libraries);
contract.second.object.link(m_libraries);
contract.second.runtimeObject.link(m_libraries);
contract.second.cloneObject.link(m_libraries);
}
}
@ -352,24 +362,31 @@ Json::Value const& CompilerStack::interface(string const& _contractName) const
}
Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
return metadata(contract(_contractName), _type);
}
Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
std::unique_ptr<Json::Value const>* doc;
Contract const& currentContract = contract(_contractName);
// checks wheather we already have the documentation
switch (_type)
{
case DocumentationType::NatspecUser:
doc = &currentContract.userDocumentation;
doc = &_contract.userDocumentation;
break;
case DocumentationType::NatspecDev:
doc = &currentContract.devDocumentation;
doc = &_contract.devDocumentation;
break;
case DocumentationType::ABIInterface:
doc = &currentContract.interface;
doc = &_contract.interface;
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
@ -377,11 +394,19 @@ Json::Value const& CompilerStack::metadata(string const& _contractName, Document
// caches the result
if (!*doc)
doc->reset(new Json::Value(InterfaceHandler::documentation(*currentContract.contract, _type)));
doc->reset(new Json::Value(InterfaceHandler::documentation(*_contract.contract, _type)));
return *(*doc);
}
string const& CompilerStack::onChainMetadata(string const& _contractName) const
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
return contract(_contractName).onChainMetadata;
}
Scanner const& CompilerStack::scanner(string const& _sourceName) const
{
return *source(_sourceName).scanner;
@ -572,8 +597,6 @@ string CompilerStack::absolutePath(string const& _path, string const& _reference
}
void CompilerStack::compileContract(
bool _optimize,
unsigned _runs,
ContractDefinition const& _contract,
map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
)
@ -581,19 +604,21 @@ void CompilerStack::compileContract(
if (_compiledContracts.count(&_contract) || !_contract.annotation().isFullyImplemented)
return;
for (auto const* dependency: _contract.annotation().contractDependencies)
compileContract(_optimize, _runs, *dependency, _compiledContracts);
compileContract(*dependency, _compiledContracts);
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize, _runs);
compiler->compileContract(_contract, _compiledContracts);
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns);
Contract& compiledContract = m_contracts.at(_contract.name());
string onChainMetadata = createOnChainMetadata(compiledContract);
compiler->compileContract(_contract, _compiledContracts, dev::swarmHash(onChainMetadata));
compiledContract.compiler = compiler;
compiledContract.object = compiler->assembledObject();
compiledContract.runtimeObject = compiler->runtimeObject();
compiledContract.onChainMetadata = onChainMetadata;
_compiledContracts[compiledContract.contract] = &compiler->assembly();
try
{
Compiler cloneCompiler(_optimize, _runs);
Compiler cloneCompiler(m_optimize, m_optimizeRuns);
cloneCompiler.compileClone(_contract, _compiledContracts);
compiledContract.cloneObject = cloneCompiler.assembledObject();
}
@ -637,6 +662,43 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co
return it->second;
}
string CompilerStack::createOnChainMetadata(Contract const& _contract) const
{
Json::Value meta;
meta["version"] = 1;
meta["language"] = "Solidity";
meta["compiler"]["version"] = VersionString;
meta["compilationTarget"] =
_contract.contract->sourceUnitName() +
":" +
_contract.contract->annotation().canonicalName;
for (auto const& s: m_sources)
{
solAssert(s.second.scanner, "Scanner not available");
meta["sources"][s.first]["swarm"] =
"0x" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes());
}
meta["settings"]["optimizer"]["enabled"] = m_optimize;
meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
set<string> remappings;
for (auto const& r: m_remappings)
remappings.insert(r.context + ":" + r.prefix + "=" + r.target);
for (auto const& r: remappings)
meta["settings"]["remappings"].append(r);
for (auto const& library: m_libraries)
meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes());
meta["output"]["abi"] = metadata(_contract, DocumentationType::ABIInterface);
meta["output"]["natspec"] = metadata(_contract, DocumentationType::NatspecUser);
Json::FastWriter writer;
writer.omitEndingLineFeed();
return writer.write(meta);
}
string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const
{
string ret;

View File

@ -113,14 +113,15 @@ public:
/// Compiles the source units that were previously added and parsed.
/// @returns false on error.
bool compile(bool _optimize = false, unsigned _runs = 200);
bool compile(
bool _optimize = false,
unsigned _runs = 200,
std::map<std::string, h160> const& _libraries = std::map<std::string, h160>{}
);
/// Parses and compiles the given source code.
/// @returns false on error.
bool compile(std::string const& _sourceCode, bool _optimize = false);
/// Inserts the given addresses into the linker objects of all compiled contracts.
void link(std::map<std::string, h160> const& _libraries);
/// Tries to translate all source files into a language suitable for formal analysis.
/// @param _errors list to store errors - defaults to the internal error list.
/// @returns false on error.
@ -170,6 +171,7 @@ public:
/// @param type The type of the documentation to get.
/// Can be one of 4 types defined at @c DocumentationType
Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const;
std::string const& onChainMetadata(std::string const& _contractName) const;
/// @returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& scanner(std::string const& _sourceName = "") const;
@ -213,6 +215,7 @@ private:
eth::LinkerObject object;
eth::LinkerObject runtimeObject;
eth::LinkerObject cloneObject;
std::string onChainMetadata; ///< The metadata json that will be hashed into the chain.
mutable std::unique_ptr<Json::Value const> interface;
mutable std::unique_ptr<Json::Value const> userDocumentation;
mutable std::unique_ptr<Json::Value const> devDocumentation;
@ -233,16 +236,18 @@ private:
std::string absolutePath(std::string const& _path, std::string const& _reference) const;
/// Compile a single contract and put the result in @a _compiledContracts.
void compileContract(
bool _optimize,
unsigned _runs,
ContractDefinition const& _contract,
std::map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
);
void link();
Contract const& contract(std::string const& _contractName = "") const;
Source const& source(std::string const& _sourceName = "") const;
std::string createOnChainMetadata(Contract const& _contract) const;
std::string computeSourceMapping(eth::AssemblyItems const& _items) const;
Json::Value const& metadata(Contract const&, DocumentationType _type) const;
struct Remapping
{
@ -252,6 +257,9 @@ private:
};
ReadFileCallback m_readFile;
bool m_optimize = false;
size_t m_optimizeRuns = 200;
std::map<std::string, h160> m_libraries;
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
/// "context:prefix=target"
std::vector<Remapping> m_remappings;

View File

@ -80,6 +80,8 @@ public:
void reset() { m_position = 0; }
std::string const& source() const { return m_source; }
///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors
@ -102,6 +104,8 @@ public:
explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); }
std::string source() const { return m_source.source(); }
/// Resets the scanner as if newly constructed with _source and _sourceName as input.
void reset(CharStream const& _source, std::string const& _sourceName);
/// Resets scanner to the start of input.

View File

@ -78,6 +78,7 @@ static string const g_argCloneBinaryStr = "clone-bin";
static string const g_argOpcodesStr = "opcodes";
static string const g_argNatspecDevStr = "devdoc";
static string const g_argNatspecUserStr = "userdoc";
static string const g_argMetadata = "metadata";
static string const g_argAddStandard = "add-std";
static string const g_stdinFileName = "<stdin>";
@ -91,6 +92,7 @@ static set<string> const g_combinedJsonArgs{
"opcodes",
"abi",
"interface",
"metadata",
"asm",
"ast",
"userdoc",
@ -117,6 +119,7 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
for (string const& arg: {
g_argAbiStr,
g_argSignatureHashes,
g_argMetadata,
g_argNatspecUserStr,
g_argAstJson,
g_argNatspecDevStr,
@ -202,6 +205,18 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract)
cout << "Function signatures: " << endl << out;
}
void CommandLineInterface::handleOnChainMetadata(string const& _contract)
{
if (!m_args.count(g_argMetadata))
return;
string data = m_compiler->onChainMetadata(_contract);
if (m_args.count("output-dir"))
createFile(_contract + ".meta", data);
else
cout << "Metadata: " << endl << data << endl;
}
void CommandLineInterface::handleMeta(DocumentationType _type, string const& _contract)
{
std::string argName;
@ -467,6 +482,7 @@ Allowed options)",
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
(g_argNatspecUserStr.c_str(), "Natspec user documentation of all contracts.")
(g_argNatspecDevStr.c_str(), "Natspec developer documentation of all contracts.")
(g_argMetadata.c_str(), "Combined metadata JSON whose swarm hash is stored on-chain.")
("formal", "Translated source suitable for formal analysis.");
desc.add(outputComponents);
@ -581,9 +597,7 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested
bool optimize = m_args.count("optimize") > 0;
unsigned runs = m_args["optimize-runs"].as<unsigned>();
bool successful = m_compiler->compile(optimize, runs);
if (successful)
m_compiler->link(m_libraries);
bool successful = m_compiler->compile(optimize, runs, m_libraries);
if (successful && m_args.count("formal"))
if (!m_compiler->prepareFormalAnalysis())
@ -659,6 +673,8 @@ void CommandLineInterface::handleCombinedJSON()
Json::Value contractData(Json::objectValue);
if (requests.count("abi"))
contractData["abi"] = dev::jsonCompactPrint(m_compiler->interface(contractName));
if (requests.count("metadata"))
contractData["metadata"] = m_compiler->onChainMetadata(contractName);
if (requests.count("bin"))
contractData["bin"] = m_compiler->object(contractName).toHex();
if (requests.count("bin-runtime"))
@ -918,6 +934,7 @@ void CommandLineInterface::outputCompilationResults()
handleBytecode(contract);
handleSignatureHashes(contract);
handleOnChainMetadata(contract);
handleMeta(DocumentationType::ABIInterface, contract);
handleMeta(DocumentationType::NatspecDev, contract);
handleMeta(DocumentationType::NatspecUser, contract);

View File

@ -63,6 +63,7 @@ private:
void handleOpcode(std::string const& _contract);
void handleBytecode(std::string const& _contract);
void handleSignatureHashes(std::string const& _contract);
void handleOnChainMetadata(std::string const& _contract);
void handleMeta(DocumentationType _type, std::string const& _contract);
void handleGasEstimation(std::string const& _contract);
void handleFormal();

View File

@ -218,6 +218,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
contractData["bytecode"] = compiler.object(contractName).toHex();
contractData["runtimeBytecode"] = compiler.runtimeObject(contractName).toHex();
contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode);
contractData["metadata"] = compiler.onChainMetadata(contractName);
contractData["functionHashes"] = functionHashes(compiler.contractDefinition(contractName));
contractData["gasEstimates"] = estimateGas(compiler, contractName);
auto sourceMap = compiler.sourceMapping(contractName);

View File

@ -31,24 +31,24 @@ namespace test
BOOST_AUTO_TEST_SUITE(SwarmHash)
string swarmHashHex(bytes const& _input)
string swarmHashHex(string const& _input)
{
return toHex(swarmHash(_input).asBytes());
}
BOOST_AUTO_TEST_CASE(test_zeros)
{
BOOST_CHECK_EQUAL(swarmHashHex(bytes()), string("011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x1000 - 1, 0)), string("32f0faabc4265ac238cd945087133ce3d7e9bb2e536053a812b5373c54043adb"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x1000, 0)), string("411dd45de7246e94589ff5888362c41e85bd3e582a92d0fda8f0e90b76439bec"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x1000 + 1, 0)), string("69754a0098432bbc2e84fe1205276870748a61a065ab6ef44d6a2e7b13ce044d"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x2000 - 1, 0)), string("69ad3c581043404f775ffa8d6f1b25ad4a9ee812971190e90209c0966116a321"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x2000, 0)), string("f00222373ff82d0a178dc6271c78953e9c88f74130a52d401f5ec51475f63c43"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x2000 + 1, 0)), string("86d6773e79e02fd8145ee1aedba89ace0c15f2566db1249654000039a9a134bf"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x80000, 0)), string("cc0854fe2c6b98e920d5c14b1a88e6d4223e55b8f78883f60939aa2485e361bf"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x80020, 0)), string("ee9ffca246e70d3704740ba4df450fa6988d14a1c2439c7e734c7a77a4eb6fd3"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(0x800020, 0)), string("78b90b20c90559fb904535181a7c28929ea2f30a2329dbc25232de579709f12f"));
BOOST_CHECK_EQUAL(swarmHashHex(bytes(2095104, 0)), string("a9958184589fc11b4027a4c233e777ebe2e99c66f96b74aef2a0638a94dd5439"));
BOOST_CHECK_EQUAL(swarmHashHex(string()), string("011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x1000 - 1, 0)), string("32f0faabc4265ac238cd945087133ce3d7e9bb2e536053a812b5373c54043adb"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x1000, 0)), string("411dd45de7246e94589ff5888362c41e85bd3e582a92d0fda8f0e90b76439bec"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x1000 + 1, 0)), string("69754a0098432bbc2e84fe1205276870748a61a065ab6ef44d6a2e7b13ce044d"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x2000 - 1, 0)), string("69ad3c581043404f775ffa8d6f1b25ad4a9ee812971190e90209c0966116a321"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x2000, 0)), string("f00222373ff82d0a178dc6271c78953e9c88f74130a52d401f5ec51475f63c43"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x2000 + 1, 0)), string("86d6773e79e02fd8145ee1aedba89ace0c15f2566db1249654000039a9a134bf"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x80000, 0)), string("cc0854fe2c6b98e920d5c14b1a88e6d4223e55b8f78883f60939aa2485e361bf"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x80020, 0)), string("ee9ffca246e70d3704740ba4df450fa6988d14a1c2439c7e734c7a77a4eb6fd3"));
BOOST_CHECK_EQUAL(swarmHashHex(string(0x800020, 0)), string("78b90b20c90559fb904535181a7c28929ea2f30a2329dbc25232de579709f12f"));
BOOST_CHECK_EQUAL(swarmHashHex(string(2095104, 0)), string("a9958184589fc11b4027a4c233e777ebe2e99c66f96b74aef2a0638a94dd5439"));
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -75,7 +75,7 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
Compiler compiler;
compiler.compileContract(*contract, map<ContractDefinition const*, Assembly const*>{});
compiler.compileContract(*contract, map<ContractDefinition const*, Assembly const*>{}, h256());
return compiler.runtimeAssemblyItems();
}