From 2b4ddf80ab9fd4c1c3ec0391e1e6fade749c7198 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 17:38:26 +0200 Subject: [PATCH] Added fallback function to gas estimation and fixed mix gas estimation. Fixes #2156 --- mix/CodeModel.cpp | 54 ++++++++++++++++++++++++++--------- solc/CommandLineInterface.cpp | 5 ++++ solc/jsonCompiler.cpp | 2 ++ 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 1ca5d9160..a67d2b59c 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -374,29 +374,55 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) dev::solidity::SourceUnit const& sourceUnit = _cs.getAST(*contractDefinition.getLocation().sourceName); AssemblyItems const* items = _cs.getRuntimeAssemblyItems(n); std::map gasCosts = GasEstimator::breakToStatementLevel(GasEstimator::structuralEstimation(*items, std::vector({&sourceUnit})), {&sourceUnit}); + + auto gasToString = [](GasMeter::GasConsumption const& _gas) + { + if (_gas.isInfinite) + return QString("0"); + else + return QString::fromStdString(toString(_gas.value)); + }; + + // Structural gas costs (per opcode) for (auto gasItem = gasCosts.begin(); gasItem != gasCosts.end(); ++gasItem) { SourceLocation const& location = gasItem->first->getLocation(); GasMeter::GasConsumption cost = gasItem->second; - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Statement); + m_gasCostsMaps->push(sourceName, location.start, location.end, gasToString(cost), cost.isInfinite, GasMap::type::Statement); } - if (contractDefinition.getConstructor() != nullptr) + eth::AssemblyItems const& runtimeAssembly = *_cs.getRuntimeAssemblyItems(n); + // Functional gas costs (per function, but also for accessors) + for (auto it: contractDefinition.getInterfaceFunctions()) { - GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), contractDefinition.getConstructor()->externalSignature()); - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, contractDefinition.getConstructor()->getLocation().start, contractDefinition.getConstructor()->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Constructor); + if (!it.second->hasDeclaration()) + continue; + SourceLocation loc = it.second->getDeclaration().getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, it.second->externalSignature()); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); } - - for (auto func: contractDefinition.getDefinedFunctions()) + if (auto const* fallback = contractDefinition.getFallbackFunction()) + { + SourceLocation loc = fallback->getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, "INVALID"); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); + } + for (auto const& it: contractDefinition.getDefinedFunctions()) + { + if (it->isPartOfExternalInterface() || it->isConstructor()) + continue; + SourceLocation loc = it->getLocation(); + size_t entry = _cs.getFunctionEntryPoint(n, *it); + GasEstimator::GasConsumption cost = GasEstimator::GasConsumption::infinite(); + if (entry > 0) + cost = GasEstimator::functionalEstimation(runtimeAssembly, entry, *it); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function); + } + if (auto const* constructor = contractDefinition.getConstructor()) { - GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), func->externalSignature()); - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, func->getLocation().start, func->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Function); + SourceLocation loc = constructor->getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getAssemblyItems(n)); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Constructor); } } } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index ec2a90033..c95f34f62 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -273,6 +273,11 @@ void CommandLineInterface::handleGasEstimation(string const& _contract) GasEstimator::GasConsumption gas = GasEstimator::functionalEstimation(*items, sig); cout << " " << sig << ":\t" << gas << endl; } + if (contract.getFallbackFunction()) + { + GasEstimator::GasConsumption gas = GasEstimator::functionalEstimation(*items, "INVALID"); + cout << " fallback:\t" << gas << endl; + } cout << "internal:" << endl; for (auto const& it: contract.getDefinedFunctions()) { diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 7bde3e47c..340713b1d 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -91,6 +91,8 @@ Json::Value estimateGas(CompilerStack const& _compiler, string const& _contract) string sig = it.second->externalSignature(); externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig)); } + if (contract.getFallbackFunction()) + externalFunctions[""] = gasToJson(GasEstimator::functionalEstimation(*items, "INVALID")); gasEstimates["external"] = externalFunctions; Json::Value internalFunctions(Json::objectValue); for (auto const& it: contract.getDefinedFunctions())