Generate separate metadata for the old and the new codegen

This commit is contained in:
Kamil Śliwak 2021-09-10 15:54:32 +02:00
parent 83b3bd0227
commit 405a9e9971
3 changed files with 52 additions and 32 deletions

View File

@ -1000,20 +1000,12 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
return methodIdentifiers; return methodIdentifiers;
} }
string const& CompilerStack::metadata(string const& _contractName) const bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const
{ {
if (m_stackState < AnalysisPerformed) if (m_stackState < AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
return metadata(contract(_contractName)); return createCBORMetadata(contract(_contractName), _forIR);
}
bytes CompilerStack::cborMetadata(string const& _contractName) const
{
if (m_stackState < AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
return createCBORMetadata(contract(_contractName));
} }
string const& CompilerStack::metadata(Contract const& _contract) const string const& CompilerStack::metadata(Contract const& _contract) const
@ -1023,7 +1015,7 @@ string const& CompilerStack::metadata(Contract const& _contract) const
solAssert(_contract.contract, ""); solAssert(_contract.contract, "");
return _contract.metadata.init([&]{ return createMetadata(_contract); }); return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); });
} }
CharStream const& CompilerStack::charStream(string const& _sourceName) const CharStream const& CompilerStack::charStream(string const& _sourceName) const
@ -1283,7 +1275,8 @@ void CompilerStack::compileContract(
shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings); shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings);
compiledContract.compiler = compiler; compiledContract.compiler = compiler;
bytes cborEncodedMetadata = createCBORMetadata(compiledContract); solAssert(!m_viaIR, "");
bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false);
try try
{ {
@ -1332,7 +1325,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this); IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this);
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run( tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(
_contract, _contract,
createCBORMetadata(compiledContract), createCBORMetadata(compiledContract, /* _forIR */ true),
otherYulSources otherYulSources
); );
} }
@ -1434,7 +1427,7 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co
return it->second; return it->second;
} }
string CompilerStack::createMetadata(Contract const& _contract) const string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) const
{ {
Json::Value meta; Json::Value meta;
meta["version"] = 1; meta["version"] = 1;
@ -1510,8 +1503,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const
static vector<string> hashes{"ipfs", "bzzr1", "none"}; static vector<string> hashes{"ipfs", "bzzr1", "none"};
meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash)); meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash));
if (m_viaIR) if (_forIR)
meta["settings"]["viaIR"] = m_viaIR; meta["settings"]["viaIR"] = _forIR;
meta["settings"]["evmVersion"] = m_evmVersion.name(); meta["settings"]["evmVersion"] = m_evmVersion.name();
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] = meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
*_contract.contract->annotation().canonicalName; *_contract.contract->annotation().canonicalName;
@ -1617,7 +1610,7 @@ private:
bytes m_data; bytes m_data;
}; };
bytes CompilerStack::createCBORMetadata(Contract const& _contract) const bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) const
{ {
if (m_metadataFormat == MetadataFormat::NoMetadata) if (m_metadataFormat == MetadataFormat::NoMetadata)
return bytes{}; return bytes{};
@ -1626,7 +1619,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract) const
_contract.contract->sourceUnit().annotation().experimentalFeatures _contract.contract->sourceUnit().annotation().experimentalFeatures
); );
string meta = metadata(_contract); string meta = (_forIR == m_viaIR ? metadata(_contract) : createMetadata(_contract, _forIR));
MetadataCBOREncoder encoder; MetadataCBOREncoder encoder;
@ -1637,7 +1630,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract) const
else else
solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash"); solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash");
if (experimentalMode || m_viaIR) if (experimentalMode || _forIR)
encoder.pushBool("experimental", true); encoder.pushBool("experimental", true);
if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag) if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag)
encoder.pushBytes("solc", VersionCompactBytes); encoder.pushBytes("solc", VersionCompactBytes);

View File

@ -326,11 +326,16 @@ public:
/// @returns a JSON representing a map of method identifiers (hashes) to function names. /// @returns a JSON representing a map of method identifiers (hashes) to function names.
Json::Value methodIdentifiers(std::string const& _contractName) const; Json::Value methodIdentifiers(std::string const& _contractName) const;
/// @returns the Contract Metadata /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
std::string const& metadata(std::string const& _contractName) const; std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }
/// @returns the cbor-encoded metadata. /// @returns the CBOR-encoded metadata matching the pipeline selected using the viaIR setting.
bytes cborMetadata(std::string const& _contractName) const; bytes cborMetadata(std::string const& _contractName) const { return cborMetadata(_contractName, m_viaIR); }
/// @returns the CBOR-encoded metadata.
/// @param _forIR If true, the metadata for the IR codegen is used. Otherwise it's the metadata
/// for the EVM codegen
bytes cborMetadata(std::string const& _contractName, bool _forIR) const;
/// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions
Json::Value gasEstimates(std::string const& _contractName) const; Json::Value gasEstimates(std::string const& _contractName) const;
@ -339,6 +344,7 @@ public:
/// This is mostly a workaround to avoid bytecode and gas differences between compiler builds /// This is mostly a workaround to avoid bytecode and gas differences between compiler builds
/// caused by differences in metadata. Should only be used for testing. /// caused by differences in metadata. Should only be used for testing.
void setMetadataFormat(MetadataFormat _metadataFormat) { m_metadataFormat = _metadataFormat; } void setMetadataFormat(MetadataFormat _metadataFormat) { m_metadataFormat = _metadataFormat; }
private: private:
/// The state per source unit. Filled gradually during parsing. /// The state per source unit. Filled gradually during parsing.
struct Source struct Source
@ -437,11 +443,14 @@ private:
/// Can only be called after state is SourcesSet. /// Can only be called after state is SourcesSet.
Source const& source(std::string const& _sourceName) const; Source const& source(std::string const& _sourceName) const;
/// @param _forIR If true, include a flag that indicates that the bytecode comes from the
/// experimental IR codegen.
/// @returns the metadata JSON as a compact string for the given contract. /// @returns the metadata JSON as a compact string for the given contract.
std::string createMetadata(Contract const& _contract) const; std::string createMetadata(Contract const& _contract, bool _forIR) const;
/// @returns the metadata CBOR for the given serialised metadata JSON. /// @returns the metadata CBOR for the given serialised metadata JSON.
bytes createCBORMetadata(Contract const& _contract) const; /// @param _forIR If true, use the metadata for the IR codegen. Otherwise the one for EVM codegen.
bytes createCBORMetadata(Contract const& _contract, bool _forIR) const;
/// @returns the contract ABI as a JSON object. /// @returns the contract ABI as a JSON object.
/// This will generate the JSON object and store it in the Contract object if it is not present yet. /// This will generate the JSON object and store it in the Contract object if it is not present yet.
@ -459,9 +468,9 @@ private:
/// This will generate the JSON object and store it in the Contract object if it is not present yet. /// This will generate the JSON object and store it in the Contract object if it is not present yet.
Json::Value const& natspecDev(Contract const&) const; Json::Value const& natspecDev(Contract const&) const;
/// @returns the Contract Metadata /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
/// This will generate the metadata and store it in the Contract object if it is not present yet. /// This will generate the metadata and store it in the Contract object if it is not present yet.
std::string const& metadata(Contract const&) const; std::string const& metadata(Contract const& _contract) const;
/// @returns the offset of the entry point of the given function into the list of assembly items /// @returns the offset of the entry point of the given function into the list of assembly items
/// or zero if it is not found or does not exist. /// or zero if it is not found or does not exist.

View File

@ -344,24 +344,42 @@ BOOST_AUTO_TEST_CASE(metadata_viair)
} }
)"; )";
auto check = [](char const* _src, bool _viair) auto check = [](char const* _src, bool _viaIR)
{ {
CompilerStack compilerStack; CompilerStack compilerStack;
compilerStack.setSources({{"", std::string(_src)}}); compilerStack.setSources({{"", std::string(_src)}});
compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
compilerStack.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); compilerStack.setOptimiserSettings(solidity::test::CommonOptions::get().optimize);
compilerStack.setViaIR(_viair); compilerStack.setViaIR(_viaIR);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
string metadata_str = compilerStack.metadata("test");
Json::Value metadata; Json::Value metadata;
BOOST_REQUIRE(util::jsonParseStrict(metadata_str, metadata)); BOOST_REQUIRE(util::jsonParseStrict(compilerStack.metadata("test"), metadata));
BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK(solidity::test::isValidMetadata(metadata));
BOOST_CHECK(metadata.isMember("settings")); BOOST_CHECK(metadata.isMember("settings"));
if (_viair) if (_viaIR)
{ {
BOOST_CHECK(metadata["settings"].isMember("viaIR")); BOOST_CHECK(metadata["settings"].isMember("viaIR"));
BOOST_CHECK(metadata["settings"]["viaIR"].asBool()); BOOST_CHECK(metadata["settings"]["viaIR"].asBool());
} }
else
BOOST_CHECK(!metadata["settings"].isMember("viaIR"));
BOOST_CHECK(compilerStack.cborMetadata("test") == compilerStack.cborMetadata("test", _viaIR));
BOOST_CHECK(compilerStack.cborMetadata("test") != compilerStack.cborMetadata("test", !_viaIR));
map<string, string> const parsedCBORMetadata = requireParsedCBORMetadata(
compilerStack.runtimeObject("test").bytecode,
CompilerStack::MetadataFormat::WithReleaseVersionTag
);
if (_viaIR)
{
BOOST_CHECK(parsedCBORMetadata.count("experimental") == 1);
BOOST_CHECK(parsedCBORMetadata.at("experimental") == "true");
}
else
BOOST_CHECK(parsedCBORMetadata.count("experimental") == 0);
}; };
check(sourceCode, true); check(sourceCode, true);