Browse Source

Merge pull request #2023 from yann300/gasEstimation

Mix - Functional gas estimation
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
01a2289c85
  1. 2
      mix/ClientModel.cpp
  2. 30
      mix/CodeModel.cpp
  3. 65
      mix/CodeModel.h
  4. 19
      mix/qml/Application.qml
  5. 8
      mix/qml/html/cm/inkpot.css
  6. 31
      mix/qml/html/codeeditor.js

2
mix/ClientModel.cpp

@ -331,7 +331,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
{
QSolidityType const* type = p->type();
QVariant value = transaction.parameterValues.value(p->name());
if (type->type().type == SolidityType::Type::Address)
if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<"))
{
std::pair<QString, int> ctrParamInstance = resolvePair(value.toString());
value = QVariant(resolveToken(ctrParamInstance, deployedContracts));

30
mix/CodeModel.cpp

@ -309,7 +309,7 @@ void CodeModel::runCompilationJob(int _jobId)
sourceNames.push_back(c.first.toStdString());
}
}
cs.compile(false);
cs.compile(m_optimizeCode);
gasEstimation(cs);
collectContracts(cs, sourceNames);
}
@ -380,7 +380,23 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs)
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);
m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Statement);
}
if (contractDefinition.getConstructor() != nullptr)
{
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);
}
for (auto func: contractDefinition.getDefinedFunctions())
{
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);
}
}
}
@ -583,9 +599,15 @@ QString CodeModel::resolveFunctionName(dev::SourceLocation const& _location)
return QString();
}
void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite)
void CodeModel::setOptimizeCode(bool _value)
{
m_optimizeCode = _value;
emit scheduleCompilationJob(++m_backgroundJobId);
}
void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type)
{
GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, this);
GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, this);
m_gasMaps.find(_source).value().push_back(QVariant::fromValue(gas));
}

65
mix/CodeModel.h

@ -28,6 +28,7 @@
#include <QObject>
#include <QThread>
#include <QHash>
#include <QMetaEnum>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libevmasm/Assembly.h>
@ -130,39 +131,60 @@ struct SourceMap
using SourceMaps = QMap<QString, SourceMap>; //by source id
using GasCostsMaps = QMap<QString, QVariantList>; //gas cost by contract name
class GasMapWrapper: public QObject
{
Q_OBJECT
Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT)
public:
GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){}
void push(QString _source, int _start, int _end, QString _value, bool _isInfinite);
bool contains(QString _key);
void insert(QString _source, QVariantList _variantList);
QVariantList gasCostsByDocId(QString _source);
private:
GasCostsMaps m_gasMaps;
};
class GasMap: public QObject
{
Q_OBJECT
Q_ENUMS(type)
Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT)
Q_PROPERTY(QString gas MEMBER m_gas CONSTANT)
Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT)
Q_PROPERTY(QString codeBlockType READ codeBlockType CONSTANT)
public:
GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) {}
enum type
{
Statement,
Function,
Constructor
};
GasMap(int _start, int _end, QString _gas, bool _isInfinite, type _type, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite), m_type(_type) {}
int m_start;
int m_end;
QString m_gas;
bool m_isInfinite;
type m_type;
QString codeBlockType() const
{
QMetaEnum units = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("type"));
if (m_type)
{
const char* key = units.valueToKey(m_type);
return QString(key).toLower();
}
return QString("");
}
};
class GasMapWrapper: public QObject
{
Q_OBJECT
Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT)
public:
GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){}
void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type);
bool contains(QString _key);
void insert(QString _source, QVariantList _variantList);
QVariantList gasCostsByDocId(QString _source);
private:
GasCostsMaps m_gasMaps;
};
/// Code compilation model. Compiles contracts in background an provides compiled contract data
@ -177,6 +199,7 @@ public:
Q_PROPERTY(QVariantMap contracts READ contracts NOTIFY codeChanged)
Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged)
Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged)
Q_PROPERTY(bool optimizeCode MEMBER m_optimizeCode WRITE setOptimizeCode)
/// @returns latest compilation results for contracts
QVariantMap contracts() const;
@ -209,6 +232,7 @@ public:
void gasEstimation(solidity::CompilerStack const& _cs);
/// Gas cost by doc id
Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const;
Q_INVOKABLE void setOptimizeCode(bool _value);
signals:
/// Emited on compilation state change
@ -253,11 +277,10 @@ private:
std::map<QString, dev::bytes> m_compiledContracts; //by name
dev::Mutex x_pendingContracts;
std::map<QString, QString> m_pendingContracts; //name to source
bool m_optimizeCode = false;
friend class BackgroundWorker;
};
}
}
//Q_DECLARE_METATYPE(dev::mix::GasMap)

19
mix/qml/Application.qml

@ -119,6 +119,7 @@ ApplicationWindow {
Menu {
title: qsTr("Tools")
MenuItem { action: gasEstimationAction }
MenuItem { action: optimizeCodeAction }
}
Menu {
title: qsTr("Windows")
@ -419,9 +420,19 @@ ApplicationWindow {
text: qsTr("Display gas estimation")
shortcut: "Ctrl+G"
checkable: true
onTriggered:
{
mainContent.codeEditor.displayGasEstimation(checked);
}
onTriggered: mainContent.codeEditor.displayGasEstimation(checked);
}
Action {
id: optimizeCodeAction
text: qsTr("Enable optimized compilation")
shortcut: "Ctrl+Shift+O"
checkable: true
onTriggered: codeModel.setOptimizeCode(checked);
}
Settings {
property alias gasEstimation: gasEstimationAction.checked
property alias optimizeCode: optimizeCodeAction.checked
}
}

8
mix/qml/html/cm/inkpot.css

@ -68,3 +68,11 @@ span.CodeMirror-selectedtext { color: #ffffff !important; }
font-size: 12px;
}
.CodeMirror-gasCost
{
font-family: monospace;
font-size: 14px;
color: #409090;
text-shadow: none !important;
margin-left: 5px;
}

31
mix/qml/html/codeeditor.js

@ -210,9 +210,8 @@ setFontSize = function(size)
makeGasCostMarker = function(value) {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = value;
marker.className = "CodeMirror-errorannotation-context";
marker.className = "CodeMirror-gasCost";
return marker;
};
@ -252,8 +251,23 @@ displayGasEstimation = function(show)
else
color = colorGradient[colorIndex];
var className = "CodeMirror-gasCosts" + i;
var line = editor.posFromIndex(gasCosts[i].start)
gasMarkText.push(editor.markText(line, editor.posFromIndex(gasCosts[i].end), { inclusiveLeft: true, inclusiveRight: true, handleMouseEvents: true, className: className, css: "background-color:" + color }));
var line = editor.posFromIndex(gasCosts[i].start);
var endChar;
if (gasCosts[i].codeBlockType === "statement" || gasCosts[i].codeBlockType === "")
{
endChar = editor.posFromIndex(gasCosts[i].end);
gasMarkText.push({ line: line, markText: editor.markText(line, endChar, { inclusiveLeft: true, inclusiveRight: true, handleMouseEvents: true, className: className, css: "background-color:" + color })});
}
else if (gasCosts[i].codeBlockType === "function" || gasCosts[i].codeBlockType === "constructor")
{
var l = editor.getLine(line.line);
endChar = { line: line.line, ch: line.ch + l.length };
var marker = document.createElement("div");
marker.innerHTML = " max execution cost: " + gasCosts[i].gas + " gas";
marker.className = "CodeMirror-gasCost";
editor.addWidget(endChar, marker, false, "over");
gasMarkText.push({ line: line.line, widget: marker });
}
gasMarkRef[className] = { line: line.line, value: gasCosts[i] };
}
}
@ -275,7 +289,12 @@ function clearGasMark()
{
if (gasMarkText)
for (var k in gasMarkText)
gasMarkText[k].clear();
{
if (gasMarkText[k] && gasMarkText[k].markText)
gasMarkText[k].markText.clear();
if (gasMarkText[k] && gasMarkText[k].widget)
gasMarkText[k].widget.remove();
}
}
var gasAnnotation;
@ -290,7 +309,7 @@ function listenMouseOver(e)
gasAnnotation.clear();
var cl = getGasCostClass(node);
var gasTitle = gasMarkRef[cl].value.isInfinite ? "infinite" : gasMarkRef[cl].value.gas;
gasTitle = gasTitle + " gas";
gasTitle = " execution cost: " + gasTitle + " gas";
gasAnnotation = editor.addLineWidget(gasMarkRef[cl].line + 1, makeGasCostMarker(gasTitle), { coverGutter: false, above: true });
}
else if (gasAnnotation)

Loading…
Cancel
Save