| 2011 | } |
| 2012 | |
| 2013 | Json CompilerStack::gasEstimates(std::string const& _contractName) const |
| 2014 | { |
| 2015 | solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful."); |
| 2016 | solUnimplementedAssert(!isExperimentalSolidity()); |
| 2017 | |
| 2018 | if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName)) |
| 2019 | return Json(); |
| 2020 | |
| 2021 | using Gas = GasEstimator::GasConsumption; |
| 2022 | GasEstimator gasEstimator(m_evmVersion); |
| 2023 | Json output = Json::object(); |
| 2024 | |
| 2025 | if (evmasm::AssemblyItems const* items = assemblyItems(_contractName)) |
| 2026 | { |
| 2027 | Gas executionGas = gasEstimator.functionalEstimation(*items); |
| 2028 | Gas codeDepositGas{evmasm::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)}; |
| 2029 | |
| 2030 | Json creation = Json::object(); |
| 2031 | creation["codeDepositCost"] = gasToJson(codeDepositGas); |
| 2032 | creation["executionCost"] = gasToJson(executionGas); |
| 2033 | /// TODO: implement + overload to avoid the need of += |
| 2034 | executionGas += codeDepositGas; |
| 2035 | creation["totalCost"] = gasToJson(executionGas); |
| 2036 | output["creation"] = creation; |
| 2037 | } |
| 2038 | |
| 2039 | if (evmasm::AssemblyItems const* items = runtimeAssemblyItems(_contractName)) |
| 2040 | { |
| 2041 | /// External functions |
| 2042 | ContractDefinition const& contract = contractDefinition(_contractName); |
| 2043 | Json externalFunctions = Json::object(); |
| 2044 | for (auto it: contract.interfaceFunctions()) |
| 2045 | { |
| 2046 | std::string sig = it.second->externalSignature(); |
| 2047 | externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig)); |
| 2048 | } |
| 2049 | |
| 2050 | if (contract.fallbackFunction()) |
| 2051 | /// This needs to be set to an invalid signature in order to trigger the fallback, |
| 2052 | /// without the shortcut (of CALLDATSIZE == 0), and therefore to receive the upper bound. |
| 2053 | /// An empty string ("") would work to trigger the shortcut only. |
| 2054 | externalFunctions[""] = gasToJson(gasEstimator.functionalEstimation(*items, "INVALID")); |
| 2055 | |
| 2056 | if (!externalFunctions.empty()) |
| 2057 | output["external"] = externalFunctions; |
| 2058 | |
| 2059 | /// Internal functions |
| 2060 | Json internalFunctions = Json::object(); |
| 2061 | for (auto const& it: contract.definedFunctions()) |
| 2062 | { |
| 2063 | /// Exclude externally visible functions, constructor, fallback and receive ether function |
| 2064 | if (it->isPartOfExternalInterface() || !it->isOrdinary()) |
| 2065 | continue; |
| 2066 | |
| 2067 | size_t entry = functionEntryPoint(_contractName, *it); |
| 2068 | GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite(); |
| 2069 | if (entry > 0) |
| 2070 | gas = gasEstimator.functionalEstimation(*items, entry, *it); |