Skip to content

Commit 01a2289

Browse files
committed
Merge pull request ethereum#2023 from yann300/gasEstimation
Mix - Functional gas estimation
2 parents 9302eb1 + 4ee8aa8 commit 01a2289

6 files changed

Lines changed: 119 additions & 36 deletions

File tree

mix/ClientModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
331331
{
332332
QSolidityType const* type = p->type();
333333
QVariant value = transaction.parameterValues.value(p->name());
334-
if (type->type().type == SolidityType::Type::Address)
334+
if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<"))
335335
{
336336
std::pair<QString, int> ctrParamInstance = resolvePair(value.toString());
337337
value = QVariant(resolveToken(ctrParamInstance, deployedContracts));

mix/CodeModel.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ void CodeModel::runCompilationJob(int _jobId)
309309
sourceNames.push_back(c.first.toStdString());
310310
}
311311
}
312-
cs.compile(false);
312+
cs.compile(m_optimizeCode);
313313
gasEstimation(cs);
314314
collectContracts(cs, sourceNames);
315315
}
@@ -380,7 +380,23 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs)
380380
GasMeter::GasConsumption cost = gasItem->second;
381381
std::stringstream v;
382382
v << cost.value;
383-
m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite);
383+
m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Statement);
384+
}
385+
386+
if (contractDefinition.getConstructor() != nullptr)
387+
{
388+
GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), contractDefinition.getConstructor()->externalSignature());
389+
std::stringstream v;
390+
v << cost.value;
391+
m_gasCostsMaps->push(sourceName, contractDefinition.getConstructor()->getLocation().start, contractDefinition.getConstructor()->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Constructor);
392+
}
393+
394+
for (auto func: contractDefinition.getDefinedFunctions())
395+
{
396+
GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), func->externalSignature());
397+
std::stringstream v;
398+
v << cost.value;
399+
m_gasCostsMaps->push(sourceName, func->getLocation().start, func->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Function);
384400
}
385401
}
386402
}
@@ -583,9 +599,15 @@ QString CodeModel::resolveFunctionName(dev::SourceLocation const& _location)
583599
return QString();
584600
}
585601

586-
void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite)
602+
void CodeModel::setOptimizeCode(bool _value)
603+
{
604+
m_optimizeCode = _value;
605+
emit scheduleCompilationJob(++m_backgroundJobId);
606+
}
607+
608+
void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type)
587609
{
588-
GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, this);
610+
GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, this);
589611
m_gasMaps.find(_source).value().push_back(QVariant::fromValue(gas));
590612
}
591613

mix/CodeModel.h

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <QObject>
2929
#include <QThread>
3030
#include <QHash>
31+
#include <QMetaEnum>
3132
#include <libdevcore/Common.h>
3233
#include <libdevcore/Guards.h>
3334
#include <libevmasm/Assembly.h>
@@ -130,39 +131,60 @@ struct SourceMap
130131
using SourceMaps = QMap<QString, SourceMap>; //by source id
131132
using GasCostsMaps = QMap<QString, QVariantList>; //gas cost by contract name
132133

133-
class GasMapWrapper: public QObject
134-
{
135-
Q_OBJECT
136-
137-
Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT)
138-
139-
public:
140-
GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){}
141-
void push(QString _source, int _start, int _end, QString _value, bool _isInfinite);
142-
bool contains(QString _key);
143-
void insert(QString _source, QVariantList _variantList);
144-
QVariantList gasCostsByDocId(QString _source);
145-
146-
private:
147-
GasCostsMaps m_gasMaps;
148-
};
149-
150134
class GasMap: public QObject
151135
{
152136
Q_OBJECT
153-
137+
Q_ENUMS(type)
154138
Q_PROPERTY(int start MEMBER m_start CONSTANT)
155139
Q_PROPERTY(int end MEMBER m_end CONSTANT)
156140
Q_PROPERTY(QString gas MEMBER m_gas CONSTANT)
157141
Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT)
142+
Q_PROPERTY(QString codeBlockType READ codeBlockType CONSTANT)
158143

159144
public:
160-
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) {}
145+
146+
enum type
147+
{
148+
Statement,
149+
Function,
150+
Constructor
151+
};
152+
153+
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) {}
161154

162155
int m_start;
163156
int m_end;
164157
QString m_gas;
165158
bool m_isInfinite;
159+
type m_type;
160+
161+
QString codeBlockType() const
162+
{
163+
QMetaEnum units = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("type"));
164+
if (m_type)
165+
{
166+
const char* key = units.valueToKey(m_type);
167+
return QString(key).toLower();
168+
}
169+
return QString("");
170+
}
171+
};
172+
173+
class GasMapWrapper: public QObject
174+
{
175+
Q_OBJECT
176+
177+
Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT)
178+
179+
public:
180+
GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){}
181+
void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type);
182+
bool contains(QString _key);
183+
void insert(QString _source, QVariantList _variantList);
184+
QVariantList gasCostsByDocId(QString _source);
185+
186+
private:
187+
GasCostsMaps m_gasMaps;
166188
};
167189

168190
/// Code compilation model. Compiles contracts in background an provides compiled contract data
@@ -177,6 +199,7 @@ class CodeModel: public QObject
177199
Q_PROPERTY(QVariantMap contracts READ contracts NOTIFY codeChanged)
178200
Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged)
179201
Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged)
202+
Q_PROPERTY(bool optimizeCode MEMBER m_optimizeCode WRITE setOptimizeCode)
180203

181204
/// @returns latest compilation results for contracts
182205
QVariantMap contracts() const;
@@ -209,6 +232,7 @@ class CodeModel: public QObject
209232
void gasEstimation(solidity::CompilerStack const& _cs);
210233
/// Gas cost by doc id
211234
Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const;
235+
Q_INVOKABLE void setOptimizeCode(bool _value);
212236

213237
signals:
214238
/// Emited on compilation state change
@@ -253,11 +277,10 @@ public slots:
253277
std::map<QString, dev::bytes> m_compiledContracts; //by name
254278
dev::Mutex x_pendingContracts;
255279
std::map<QString, QString> m_pendingContracts; //name to source
280+
bool m_optimizeCode = false;
256281
friend class BackgroundWorker;
257282
};
258283

259284
}
260285

261286
}
262-
263-
//Q_DECLARE_METATYPE(dev::mix::GasMap)

mix/qml/Application.qml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ ApplicationWindow {
119119
Menu {
120120
title: qsTr("Tools")
121121
MenuItem { action: gasEstimationAction }
122+
MenuItem { action: optimizeCodeAction }
122123
}
123124
Menu {
124125
title: qsTr("Windows")
@@ -419,9 +420,19 @@ ApplicationWindow {
419420
text: qsTr("Display gas estimation")
420421
shortcut: "Ctrl+G"
421422
checkable: true
422-
onTriggered:
423-
{
424-
mainContent.codeEditor.displayGasEstimation(checked);
425-
}
423+
onTriggered: mainContent.codeEditor.displayGasEstimation(checked);
424+
}
425+
426+
Action {
427+
id: optimizeCodeAction
428+
text: qsTr("Enable optimized compilation")
429+
shortcut: "Ctrl+Shift+O"
430+
checkable: true
431+
onTriggered: codeModel.setOptimizeCode(checked);
432+
}
433+
434+
Settings {
435+
property alias gasEstimation: gasEstimationAction.checked
436+
property alias optimizeCode: optimizeCodeAction.checked
426437
}
427438
}

mix/qml/html/cm/inkpot.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,11 @@ span.CodeMirror-selectedtext { color: #ffffff !important; }
6868
font-size: 12px;
6969
}
7070

71+
.CodeMirror-gasCost
72+
{
73+
font-family: monospace;
74+
font-size: 14px;
75+
color: #409090;
76+
text-shadow: none !important;
77+
margin-left: 5px;
78+
}

mix/qml/html/codeeditor.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,8 @@ setFontSize = function(size)
210210

211211
makeGasCostMarker = function(value) {
212212
var marker = document.createElement("div");
213-
marker.style.color = "#822";
214213
marker.innerHTML = value;
215-
marker.className = "CodeMirror-errorannotation-context";
214+
marker.className = "CodeMirror-gasCost";
216215
return marker;
217216
};
218217

@@ -252,8 +251,23 @@ displayGasEstimation = function(show)
252251
else
253252
color = colorGradient[colorIndex];
254253
var className = "CodeMirror-gasCosts" + i;
255-
var line = editor.posFromIndex(gasCosts[i].start)
256-
gasMarkText.push(editor.markText(line, editor.posFromIndex(gasCosts[i].end), { inclusiveLeft: true, inclusiveRight: true, handleMouseEvents: true, className: className, css: "background-color:" + color }));
254+
var line = editor.posFromIndex(gasCosts[i].start);
255+
var endChar;
256+
if (gasCosts[i].codeBlockType === "statement" || gasCosts[i].codeBlockType === "")
257+
{
258+
endChar = editor.posFromIndex(gasCosts[i].end);
259+
gasMarkText.push({ line: line, markText: editor.markText(line, endChar, { inclusiveLeft: true, inclusiveRight: true, handleMouseEvents: true, className: className, css: "background-color:" + color })});
260+
}
261+
else if (gasCosts[i].codeBlockType === "function" || gasCosts[i].codeBlockType === "constructor")
262+
{
263+
var l = editor.getLine(line.line);
264+
endChar = { line: line.line, ch: line.ch + l.length };
265+
var marker = document.createElement("div");
266+
marker.innerHTML = " max execution cost: " + gasCosts[i].gas + " gas";
267+
marker.className = "CodeMirror-gasCost";
268+
editor.addWidget(endChar, marker, false, "over");
269+
gasMarkText.push({ line: line.line, widget: marker });
270+
}
257271
gasMarkRef[className] = { line: line.line, value: gasCosts[i] };
258272
}
259273
}
@@ -275,7 +289,12 @@ function clearGasMark()
275289
{
276290
if (gasMarkText)
277291
for (var k in gasMarkText)
278-
gasMarkText[k].clear();
292+
{
293+
if (gasMarkText[k] && gasMarkText[k].markText)
294+
gasMarkText[k].markText.clear();
295+
if (gasMarkText[k] && gasMarkText[k].widget)
296+
gasMarkText[k].widget.remove();
297+
}
279298
}
280299

281300
var gasAnnotation;
@@ -290,7 +309,7 @@ function listenMouseOver(e)
290309
gasAnnotation.clear();
291310
var cl = getGasCostClass(node);
292311
var gasTitle = gasMarkRef[cl].value.isInfinite ? "infinite" : gasMarkRef[cl].value.gas;
293-
gasTitle = gasTitle + " gas";
312+
gasTitle = " execution cost: " + gasTitle + " gas";
294313
gasAnnotation = editor.addLineWidget(gasMarkRef[cl].line + 1, makeGasCostMarker(gasTitle), { coverGutter: false, above: true });
295314
}
296315
else if (gasAnnotation)

0 commit comments

Comments
 (0)