diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 41a9040c4..b79cf000c 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -824,6 +824,14 @@ string const& CompilerStack::metadata(string const& _contractName) const return metadata(contract(_contractName)); } +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 { if (m_stackState < AnalysisPerformed) @@ -1063,10 +1071,7 @@ void CompilerStack::compileContract( shared_ptr compiler = make_shared(m_evmVersion, m_revertStrings, m_optimiserSettings); compiledContract.compiler = compiler; - bytes cborEncodedMetadata = createCBORMetadata( - metadata(compiledContract), - !onlySafeExperimentalFeaturesActivated(_contract.sourceUnit().annotation().experimentalFeatures) - ); + bytes cborEncodedMetadata = createCBORMetadata(compiledContract); try { @@ -1390,18 +1395,24 @@ private: bytes m_data; }; -bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimentalMode) +bytes CompilerStack::createCBORMetadata(Contract const& _contract) const { + bool const experimentalMode = !onlySafeExperimentalFeaturesActivated( + _contract.contract->sourceUnit().annotation().experimentalFeatures + ); + + string meta = metadata(_contract); + MetadataCBOREncoder encoder; if (m_metadataHash == MetadataHash::IPFS) - encoder.pushBytes("ipfs", util::ipfsHash(_metadata)); + encoder.pushBytes("ipfs", util::ipfsHash(meta)); else if (m_metadataHash == MetadataHash::Bzzr1) - encoder.pushBytes("bzzr1", util::bzzr1Hash(_metadata).asBytes()); + encoder.pushBytes("bzzr1", util::bzzr1Hash(meta).asBytes()); else solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash"); - if (_experimentalMode) + if (experimentalMode) encoder.pushBool("experimental", true); if (m_release) encoder.pushBytes("solc", VersionCompactBytes); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index ce0f949b9..37472d907 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -314,6 +314,9 @@ public: /// @returns the Contract Metadata std::string const& metadata(std::string const& _contractName) const; + /// @returns the cbor-encoded metadata. + bytes cborMetadata(std::string const& _contractName) const; + /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions Json::Value gasEstimates(std::string const& _contractName) const; @@ -402,7 +405,7 @@ private: std::string createMetadata(Contract const& _contract) const; /// @returns the metadata CBOR for the given serialised metadata JSON. - bytes createCBORMetadata(std::string const& _metadata, bool _experimentalMode); + bytes createCBORMetadata(Contract const& _contract) const; /// @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. diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index bb86aaa83..946a5d8a4 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -39,18 +39,18 @@ namespace solidity::frontend::test #define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt, _evmVersion) \ do \ { \ - u256 ipfsCost = GasMeter::dataGas(util::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true, _evmVersion); \ + u256 metaCost = GasMeter::dataGas(m_compiler.cborMetadata(m_compiler.lastContractName()), true, _evmVersion); \ u256 gasOpt{_gasOpt}; \ u256 gasNoOpt{_gasNoOpt}; \ u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \ BOOST_CHECK_MESSAGE( \ - m_gasUsed >= ipfsCost, \ + m_gasUsed >= metaCost, \ "Gas used: " + \ m_gasUsed.str() + \ - " is less than the data cost for the IPFS hash: " + \ - u256(ipfsCost).str() \ + " is less than the data cost for the cbor metadata: " + \ + u256(metaCost).str() \ ); \ - u256 gasUsed = m_gasUsed - ipfsCost; \ + u256 gasUsed = m_gasUsed - metaCost; \ BOOST_CHECK_MESSAGE( \ gas == gasUsed, \ "Gas used: " + \ @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(string_storage) auto evmVersion = solidity::test::CommonOptions::get().evmVersion(); if (evmVersion <= EVMVersion::byzantium()) - CHECK_DEPLOY_GAS(134145, 130831, evmVersion); + CHECK_DEPLOY_GAS(133045, 129731, evmVersion); // This is only correct on >=Constantinople. else if (CommonOptions::get().useABIEncoderV2) { @@ -105,22 +105,22 @@ BOOST_AUTO_TEST_CASE(string_storage) { // Costs with 0 are cases which cannot be triggered in tests. if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(0, 123969, evmVersion); + CHECK_DEPLOY_GAS(0, 122869, evmVersion); else - CHECK_DEPLOY_GAS(0, 110969, evmVersion); + CHECK_DEPLOY_GAS(0, 110701, evmVersion); } else { if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(147835, 123969, evmVersion); + CHECK_DEPLOY_GAS(146671, 123969, evmVersion); else - CHECK_DEPLOY_GAS(131871, 110969, evmVersion); + CHECK_DEPLOY_GAS(131591, 110969, evmVersion); } } else if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(126929, 119659, evmVersion); + CHECK_DEPLOY_GAS(125829, 118559, evmVersion); else - CHECK_DEPLOY_GAS(114345, 107335, evmVersion); + CHECK_DEPLOY_GAS(114077, 107067, evmVersion); if (evmVersion >= EVMVersion::byzantium()) {