Browse Source

completed transaction management

cl-refactor
arkpar 10 years ago
parent
commit
2363cc0f96
  1. 4
      mix/AssemblyDebuggerCtrl.cpp
  2. 8
      mix/AssemblyDebuggerModel.cpp
  3. 12
      mix/CodeEditorExtensionManager.cpp
  4. 6
      mix/DebuggingStateWrapper.cpp
  5. 2
      mix/DebuggingStateWrapper.h
  6. 2
      mix/QBasicNodeDefinition.h
  7. 6
      mix/QFunctionDefinition.h
  8. 2
      mix/QVariableDeclaration.h
  9. 141
      mix/TransactionListModel.cpp
  10. 93
      mix/TransactionListModel.h
  11. 2
      mix/TransactionListView.cpp
  12. 2
      mix/TransactionListView.h
  13. 8
      mix/qml/BasicContent.qml
  14. 4
      mix/qml/MainContent.qml
  15. 72
      mix/qml/TransactionDialog.qml
  16. 2
      mix/qml/TransactionList.qml

4
mix/AssemblyDebuggerCtrl.cpp

@ -78,10 +78,10 @@ void AssemblyDebuggerCtrl::keyPressed(int _key)
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
for (int i = 0; i < debuggingContent.machineStates.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes(), this);
s->setState(debuggingContent.states.at(i));
s->setState(debuggingContent.machineStates.at(i));
wStates.append(s);
}
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);

8
mix/AssemblyDebuggerModel.cpp

@ -38,7 +38,7 @@ AssemblyDebuggerModel::AssemblyDebuggerModel()
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
{
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
Transaction tr(_rawTransaction);
m_currentExecution->create(tr.sender(), tr.value(), tr.gasPrice(), tr.gas(), &tr.data(), tr.sender());
std::vector<DebuggingState const*> levels;
@ -58,11 +58,11 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
}
if (levels.size() < ext.depth)
levels.push_back(&states.back());
levels.push_back(&machineStates.back());
else
levels.resize(ext.depth);
states.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
@ -70,7 +70,7 @@ DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::by
m_currentExecution->finalize(onOp);
DebuggingContent d;
d.states = states;
d.machineStates = machineStates;
d.executionCode = code;
d.executionData = data;
d.contentAvailable = true;

12
mix/CodeEditorExtensionManager.cpp

@ -49,7 +49,17 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
{
QQuickTextDocument* qqdoc = doc.value<QQuickTextDocument*>();
if (qqdoc)
m_doc = qqdoc->textDocument();
{
m_doc = qqdoc->textDocument();
auto args = QApplication::arguments();
if (args.length() > 1)
{
QString path = args[1];
QFile file(path);
if (file.exists() && file.open(QFile::ReadOnly))
m_doc->setPlainText(file.readAll());
}
}
}
}
catch (...)

6
mix/DebuggingStateWrapper.cpp

@ -44,7 +44,7 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << hex << std::setw(4) << std::setfill('0') << i;
out << std::hex << std::setw(4) << std::setfill('0') << i;
codeMapping[i] = codeStr.size();
int line = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
@ -103,7 +103,7 @@ QStringList DebuggingStateWrapper::levels()
std::ostringstream out;
out << m_state.cur.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << hex << m_state.curPC;
out << " " << instructionInfo(m_state.inst).name << " @0x" << std::hex << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
}
return levelsStr;
@ -112,7 +112,7 @@ QStringList DebuggingStateWrapper::levels()
QString DebuggingStateWrapper::headerInfo()
{
std::ostringstream ss;
ss << dec << " STEP: " << m_state.steps << " | PC: 0x" << hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << dec << m_state.newMemSize << " words | COST: " << dec << m_state.gasCost << " | GAS: " << dec << m_state.gas;
ss << std::dec << " STEP: " << m_state.steps << " | PC: 0x" << std::hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << std::dec << m_state.newMemSize << " words | COST: " << std::dec << m_state.gasCost << " | GAS: " << std::dec << m_state.gas;
return QString::fromStdString(ss.str());
}

2
mix/DebuggingStateWrapper.h

@ -49,7 +49,7 @@ struct DebuggingState
struct DebuggingContent
{
QList<DebuggingState> states;
QList<DebuggingState> machineStates;
bytes executionCode;
bytesConstRef executionData;
bool contentAvailable;

2
mix/QBasicNodeDefinition.h

@ -38,7 +38,7 @@ public:
QBasicNodeDefinition(): QObject() {}
~QBasicNodeDefinition() {}
QBasicNodeDefinition(std::shared_ptr<dev::solidity::Declaration> _d, QObject* _parent): QObject(_parent), m_dec(_d) {}
QString name() { return QString::fromStdString(m_dec.get()->getName()); }
QString name() const { return QString::fromStdString(m_dec.get()->getName()); }
protected:
std::shared_ptr<dev::solidity::Declaration> m_dec;

6
mix/QFunctionDefinition.h

@ -38,9 +38,9 @@ class QFunctionDefinition: public QBasicNodeDefinition
public:
QFunctionDefinition(std::shared_ptr<dev::solidity::FunctionDefinition> _f, QObject* _parent, int _index): QBasicNodeDefinition(_f, _parent), m_index(_index) { initQParameters(); }
QList<QObject*> parameters() { return m_parameters; }
QList<QObject*> returnParameters() { return m_returnParameters; }
int index() { return m_index; }
QList<QObject*> parameters() const { return m_parameters; }
QList<QObject*> returnParameters() const { return m_returnParameters; }
int index() const { return m_index; }
private:
QList<QObject*> m_parameters;

2
mix/QVariableDeclaration.h

@ -36,7 +36,7 @@ class QVariableDeclaration: public QBasicNodeDefinition
public:
QVariableDeclaration(std::shared_ptr<dev::solidity::VariableDeclaration> _v, QObject* _parent): QBasicNodeDefinition(_v, _parent), m_var(_v) {}
QString type() { return QString::fromStdString(m_var.get()->getType()->toString()); }
QString type() const { return QString::fromStdString(m_var.get()->getType()->toString()); }
private:
std::shared_ptr<dev::solidity::VariableDeclaration> m_var;

141
mix/TransactionListModel.cpp

@ -22,23 +22,45 @@
#include <QObject>
#include <QQmlEngine>
#include <QTextDocument>
#include <QAbstractListModel>
#include "TransactionListModel.h"
#include "QContractDefinition.h"
#include "QFunctionDefinition.h"
#include "QVariableDeclaration.h"
#include "libdevcore/CommonJS.h"
namespace dev
{
namespace mix
{
TransactionListModel::TransactionListModel(QObject* _parent) :
QAbstractListModel(_parent)
u256 fromQString(QString const& _s)
{
return dev::jsToU256(_s.toStdString());
}
QString toQString(u256 _value)
{
m_transactions.push_back(Transaction(0, "testTr", 0, 0, 0));
std::ostringstream s;
s << _value;
return QString::fromStdString(s.str());
}
TransactionListItem::TransactionListItem(int _index, Transaction const& _t, QObject* _parent):
QObject(_parent), m_index(_index), m_title(_t.title), m_functionId(_t.functionId), m_value(toQString(_t.value)),
m_gas(toQString(_t.gas)), m_gasPrice(toQString(_t.gasPrice))
{}
TransactionListModel::TransactionListModel(QObject* _parent, QTextDocument* _document):
QAbstractListModel(_parent), m_document(_document)
{}
QHash<int, QByteArray> TransactionListModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[TitleRole] = "title";
roles[IdRole] = "transactionId";
roles[IdRole] = "transactionIndex";
return roles;
}
@ -48,26 +70,98 @@ int TransactionListModel::rowCount(QModelIndex const& _parent) const
return m_transactions.size();
}
QVariant TransactionListModel::data(QModelIndex const& _index, int role) const
QVariant TransactionListModel::data(QModelIndex const& _index, int _role) const
{
if(_index.row() < 0 || _index.row() >= (int)m_transactions.size())
return QVariant();
auto const& transaction = m_transactions.at(_index.row());
switch(role)
switch(_role)
{
case TitleRole:
return QVariant(transaction.title);
case IdRole:
return QVariant(transaction.id);
return QVariant(_index.row());
default:
return QVariant();
}
}
//TODO: get parameters from code model
QList<TransactionParameterItem*> buildParameters(QTextDocument* _document, Transaction const& _transaction, QString const& _functionId)
{
QList<TransactionParameterItem*> params;
try
{
QString code = _document->toPlainText().replace("\n", ""); //TODO: is this required?
std::unique_ptr<QContractDefinition> contract(QContractDefinition::Contract(code, nullptr));
auto functions = contract->functions();
for(auto qf : functions)
{
QFunctionDefinition const& f = (QFunctionDefinition const&) *qf;
if (f.name() != _functionId)
continue;
auto parameters = f.parameters();
for(auto qp : parameters)
{
QVariableDeclaration const& p = (QVariableDeclaration const&) *qp;
QString paramValue;
if (f.name() == _transaction.functionId)
{
auto paramValueIter = _transaction.parameterValues.find(p.name());
if (paramValueIter != _transaction.parameterValues.cend())
paramValue = toQString(paramValueIter->second);
}
TransactionParameterItem* item = new TransactionParameterItem(p.name(), p.type(), paramValue);
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
params.append(item);
}
}
}
catch (boost::exception const&)
{
//TODO:
}
return params;
}
//TODO: get fnctions from code model
QList<QString> TransactionListModel::getFunctions()
{
QList<QString> functionNames;
try
{
QString code = m_document->toPlainText().replace("\n", ""); //TODO: is this required?
std::unique_ptr<QContractDefinition> contract(QContractDefinition::Contract(code, nullptr));
auto functions = contract->functions();
for(auto qf : functions)
{
QFunctionDefinition const& f = (QFunctionDefinition const&) *qf;
functionNames.append(f.name());
}
}
catch (boost::exception const&)
{
}
return functionNames;
}
QVariantList TransactionListModel::getParameters(int _index, QString const& _functionId)
{
Transaction const& transaction = (_index >=0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : Transaction();
auto plist = buildParameters(m_document, transaction, _functionId);
QVariantList vl;
for(QObject* p : plist)
vl.append(QVariant::fromValue(p));
return vl;
}
QObject* TransactionListModel::getItem(int _index)
{
Transaction const& transaction = (_index >=0 && _index < (int)m_transactions.size()) ? m_transactions[_index] : Transaction();
QObject* item = new TransactionListItem(transaction, nullptr);
TransactionListItem* item = new TransactionListItem(_index, transaction, nullptr);
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
return item;
}
@ -75,21 +169,34 @@ QObject* TransactionListModel::getItem(int _index)
void TransactionListModel::edit(QObject* _data)
{
//these properties come from TransactionDialog QML object
int id = _data->property("transactionId").toInt();
const QString title = _data->property("transactionTitle").toString();
int index = _data->property("transactionIndex").toInt();
QString title = _data->property("transactionTitle").toString();
QString gas = _data->property("gas").toString();
QString gasPrice = _data->property("gasPrice").toString();
QString value = _data->property("transactionValue").toString();
QString functionId = _data->property("functionId").toString();
QAbstractListModel* paramsModel = qvariant_cast<QAbstractListModel*>(_data->property("transactionParams"));
Transaction transaction(title, functionId, fromQString(value), fromQString(gas), fromQString(gasPrice));
int paramCount = paramsModel->rowCount(QModelIndex());
for(int p = 0; p < paramCount; ++p)
{
QString paramName = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole).toString();
QString paramValue = paramsModel->data(paramsModel->index(p, 0), Qt::DisplayRole + 2).toString();
if (!paramValue.isEmpty() && !paramName.isEmpty())
transaction.parameterValues[paramName] = fromQString(paramValue);
}
if (id >= 0 && id < (int)m_transactions.size())
if (index >= 0 && index < (int)m_transactions.size())
{
beginRemoveRows(QModelIndex(), id, id);
m_transactions.erase(m_transactions.begin() + id);
beginRemoveRows(QModelIndex(), index, index);
m_transactions.erase(m_transactions.begin() + index);
endRemoveRows();
}
else
id = rowCount(QModelIndex());
index = rowCount(QModelIndex());
beginInsertRows(QModelIndex(), id, id);
m_transactions.push_back(Transaction(id, title, 0, 0, 0));
beginInsertRows(QModelIndex(), index, index);
m_transactions.push_back(transaction);
emit transactionAdded();
emit countChanged();
endInsertRows();

93
mix/TransactionListModel.h

@ -29,54 +29,96 @@
#include <QByteArray>
#include <libdevcore/Common.h>
class QTextDocument;
namespace dev
{
namespace mix
{
struct TransacionParameterValue
{
QVariant value;
};
/// Backend transaction config class
struct Transaction
{
Transaction():
id(-1), value(0), gas(10000), gasPrice(10) {}
value(0), gas(10000), gasPrice(10) {}
Transaction(int _id, QString const& _title, u256 _value, u256 _gas, u256 _gasPrice):
id(_id), title(_title), value(_value), gas(_gas), gasPrice(_gasPrice) {}
Transaction(QString const& _title, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
title(_title), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
int id;
/// User specified transaction title
QString title;
/// Contract function name
QString functionId;
/// Transaction value
u256 value;
/// Gas
u256 gas;
/// Gas price
u256 gasPrice;
QString functionId;
std::vector<TransacionParameterValue> parameterValues;
/// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues;
};
/// QML transaction parameter class
class TransactionParameterItem: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString type READ type CONSTANT)
Q_PROPERTY(QString value READ value CONSTANT)
public:
TransactionParameterItem(QString const& _name, QString const& _type, QString const& _value):
m_name(_name), m_type(_type), m_value(_value) {}
/// Parameter name, set by contract definition
QString name() { return m_name; }
/// Parameter type, set by contract definition
QString type() { return m_type; }
/// Parameter value, set by user
QString value() { return m_value; }
private:
QString m_name;
QString m_type;
QString m_value;
};
class TransactionListItem: public QObject
{
Q_OBJECT
Q_PROPERTY(int transactionId READ transactionId CONSTANT)
Q_PROPERTY(int index READ index CONSTANT)
Q_PROPERTY(QString title READ title CONSTANT)
Q_PROPERTY(bool selected READ selected CONSTANT)
Q_PROPERTY(QString functionId READ functionId CONSTANT)
Q_PROPERTY(QString gas READ gas CONSTANT)
Q_PROPERTY(QString gasPrice READ gasPrice CONSTANT)
Q_PROPERTY(QString value READ value CONSTANT)
public:
TransactionListItem(Transaction const& _t, QObject* _parent):
QObject(_parent), m_id(_t.id), m_title(_t.title), m_selected(false) {}
TransactionListItem(int _index, Transaction const& _t, QObject* _parent);
/// User specified transaction title
QString title() { return m_title; }
int transactionId() { return m_id; }
bool selected() { return m_selected; }
/// Gas
QString gas() { return m_gas; }
/// Gas cost
QString gasPrice() { return m_gasPrice; }
/// Transaction value
QString value() { return m_value; }
/// Contract function name
QString functionId() { return m_functionId; }
/// Index of this transaction in the transactions list
int index() { return m_index; }
private:
int m_id;
int m_index;
QString m_title;
bool m_selected;
QString m_functionId;
QString m_value;
QString m_gas;
QString m_gasPrice;
};
/// QML model for a list of transactions
class TransactionListModel: public QAbstractListModel
{
Q_OBJECT
@ -89,15 +131,22 @@ enum Roles
};
public:
TransactionListModel(QObject* _parent);
TransactionListModel(QObject* _parent, QTextDocument* _document);
~TransactionListModel() {}
QHash<int, QByteArray> roleNames() const override;
int rowCount(QModelIndex const& _parent) const override;
QVariant data(QModelIndex const& _index, int _role) const override;
int getCount() const;
/// Apply changes from transaction dialog. Argument is a dialog model as defined in TransactionDialog.qml
/// @todo Change that to transaction item
Q_INVOKABLE void edit(QObject* _data);
/// @returns transaction item for a give index
Q_INVOKABLE QObject* getItem(int _index);
/// @returns a list of functions for current contract
Q_INVOKABLE QList<QString> getFunctions();
/// @returns function parameters along with parameter values if set. @see TransactionParameterItem
Q_INVOKABLE QVariantList getParameters(int _id, QString const& _functionId);
signals:
void transactionAdded();
@ -105,8 +154,10 @@ signals:
private:
std::vector<Transaction> m_transactions;
QTextDocument* m_document;
};
}
}

2
mix/TransactionListView.cpp

@ -32,7 +32,7 @@ using namespace dev::mix;
TransactionListView::TransactionListView(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::RightTab)
{
m_editor = _doc;
m_model.reset(new TransactionListModel(this));
m_model.reset(new TransactionListModel(this, _doc));
m_appEngine->rootContext()->setContextProperty("transactionListModel", m_model.get());
}

2
mix/TransactionListView.h

@ -30,6 +30,8 @@ namespace mix
class TransactionListModel;
/// Transactions list control
/// @todo This should be moved into state as a sequence
class TransactionListView: public Extension
{
Q_OBJECT

8
mix/qml/BasicContent.qml

@ -7,13 +7,13 @@ Rectangle {
height: parent.height
color: "lightgray"
Text {
font.pointSize: 7
font.pointSize: 9
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 3
anchors.leftMargin: 3
height: 9
font.family: "Sego UI light"
font.family: "Monospace"
objectName: "status"
id: status
}
@ -23,8 +23,8 @@ Rectangle {
anchors.leftMargin: 10
anchors.top: status.bottom
anchors.topMargin: 3
font.pointSize: 7
font.family: "Sego UI light"
font.pointSize: 9
font.family: "Monospace"
height: parent.height * 0.8
width: parent.width - 20
wrapMode: Text.Wrap

4
mix/qml/MainContent.qml

@ -32,8 +32,8 @@ Rectangle {
TextArea {
id: codeEditor
height: parent.height
font.family: "Verdana"
font.pointSize: 9
font.family: "Monospace"
font.pointSize: 12
width: parent.width
anchors.centerIn: parent
tabChangesFocus: false

72
mix/qml/TransactionDialog.qml

@ -13,13 +13,44 @@ Dialog {
property alias focus : titleField.focus
property alias transactionTitle : titleField.text
property int transactionId
property int transactionParams;
function reset(id, model) {
var item = model.getItem(id);
transactionId = id;
property int transactionIndex
property alias transactionParams : paramsModel;
property alias gas : gasField.text;
property alias gasPrice : gasPriceField.text;
property alias transactionValue : valueField.text;
property alias functionId : functionComboBox.currentText;
property var model;
function reset(index, m) {
model = m;
var item = model.getItem(index);
transactionIndex = index;
transactionTitle = item.title;
gas = item.gas;
gasPrice = item.gasPrice;
transactionValue = item.value;
var functionId = item.functionId;
functionsModel.clear();
var functionIndex = -1;
var functions = model.getFunctions();
for (var f = 0; f < functions.length; f++) {
functionsModel.append({ text: functions[f] });
if (functions[f] === item.functionId)
functionIndex = f;
}
functionComboBox.currentIndex = functionIndex;
}
function loadParameters() {
if (!paramsModel)
return;
paramsModel.clear();
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var parameters = model.getParameters(transactionIndex, functionsModel.get(functionComboBox.currentIndex).text);
for (var p = 0; p < parameters.length; p++) {
paramsModel.append({ name: parameters[p].name, type: parameters[p].type, value: parameters[p].value });
}
}
}
GridLayout {
@ -41,11 +72,20 @@ Dialog {
Label {
text: qsTr("Function")
}
TextField {
id: functionField
ComboBox {
id: functionComboBox
Layout.fillWidth: true
currentIndex: -1
textRole: "text"
editable: false
model: ListModel {
id: functionsModel
}
onCurrentIndexChanged: {
loadParameters();
}
}
Label {
text: qsTr("Value")
}
@ -97,14 +137,9 @@ Dialog {
return editableDelegate;
}
}
}
ListModel {
id: paramsModel
Component.onCompleted: {
for (var i=0 ; i < 3 ; ++i)
paramsModel.append({"name":"Param " + i , "Type": "int", "value": i})
}
}
Component {
@ -127,14 +162,11 @@ Dialog {
anchors.margins: 4
Connections {
target: loaderEditor.item
onAccepted: {
//if (typeof styleData.value === 'number')
// paramsModel.setProperty(styleData.row, styleData.role, Number(parseFloat(loaderEditor.item.text).toFixed(0)))
//else
// paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text)
onTextChanged: {
paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text);
}
}
sourceComponent: styleData.selected ? editor : null
sourceComponent: (styleData.selected /*&& styleData.role === "value"*/) ? editor : null
Component {
id: editor
TextInput {

2
mix/qml/TransactionList.qml

@ -65,7 +65,7 @@ Rectangle {
text: qsTr("Edit");
Layout.fillHeight: true
onClicked: {
transactionDialog.reset(transactionId, transactionListModel);
transactionDialog.reset(index, transactionListModel);
transactionDialog.open();
transactionDialog.focus = true;
}

Loading…
Cancel
Save