Browse Source

Manage parameters in constructor #820

cl-refactor
yann300 10 years ago
parent
commit
0f7459490b
  1. 28
      mix/ClientModel.cpp
  2. 9
      mix/ClientModel.h
  3. 1
      mix/QContractDefinition.cpp
  4. 4
      mix/QContractDefinition.h
  5. 2
      mix/qml.qrc
  6. 1
      mix/qml/ProjectModel.qml
  7. 19
      mix/qml/StateDialog.qml
  8. 16
      mix/qml/StateList.qml
  9. 58
      mix/qml/TransactionDialog.qml
  10. 8
      mix/qml/js/QEtherHelper.js
  11. 13
      mix/qml/js/TransactionHelper.js
  12. 29
      mix/qml/main.qml

28
mix/ClientModel.cpp

@ -67,11 +67,10 @@ void ClientModel::debugState(QVariantMap _state)
QVariantList transactions = _state.value("transactions").toList(); QVariantList transactions = _state.value("transactions").toList();
std::vector<TransactionSettings> transactionSequence; std::vector<TransactionSettings> transactionSequence;
TransactionSettings constructorTr;
for (auto const& t: transactions) for (auto const& t: transactions)
{ {
QVariantMap transaction = t.toMap(); QVariantMap transaction = t.toMap();
QString functionId = transaction.value("functionId").toString(); QString functionId = transaction.value("functionId").toString();
u256 gas = (qvariant_cast<QEther*>(transaction.value("gas")))->toU256Wei(); u256 gas = (qvariant_cast<QEther*>(transaction.value("gas")))->toU256Wei();
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei(); u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
@ -80,14 +79,20 @@ void ClientModel::debugState(QVariantMap _state)
TransactionSettings transactionSettings(functionId, value, gas, gasPrice); TransactionSettings transactionSettings(functionId, value, gas, gasPrice);
for (auto p = params.cbegin(); p != params.cend(); ++p) for (auto p = params.cbegin(); p != params.cend(); ++p)
transactionSettings.parameterValues.insert(std::make_pair(p.key(), (qvariant_cast<QEther*>(p.value()))->toU256Wei())); {
QBigInt* param = qvariant_cast<QBigInt*>(p.value());
transactionSettings.parameterValues.insert(std::make_pair(p.key(), boost::get<dev::u256>(param->internalValue())));
}
if (transaction.value("executeConstructor").toBool())
constructorTr = transactionSettings;
else
transactionSequence.push_back(transactionSettings); transactionSequence.push_back(transactionSettings);
} }
executeSequence(transactionSequence, balance); executeSequence(transactionSequence, balance, constructorTr);
} }
void ClientModel::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance) void ClientModel::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance, TransactionSettings const& ctrTransaction)
{ {
if (m_running) if (m_running)
throw (std::logic_error("debugging already running")); throw (std::logic_error("debugging already running"));
@ -137,7 +142,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
//run contract creation first //run contract creation first
m_client->resetState(_balance); m_client->resetState(_balance);
ExecutionResult debuggingContent = deployContract(contractCode); ExecutionResult debuggingContent = deployContract(contractCode, ctrTransaction);
Address address = debuggingContent.contractAddress; Address address = debuggingContent.contractAddress;
for (unsigned i = 0; i < _sequence.size(); ++i) for (unsigned i = 0; i < _sequence.size(); ++i)
debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i)); debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i));
@ -189,13 +194,18 @@ void ClientModel::showDebugError(QString const& _error)
m_context->displayMessageDialog(tr("Debugger"), _error); m_context->displayMessageDialog(tr("Debugger"), _error);
} }
ExecutionResult ClientModel::deployContract(bytes const& _code) ExecutionResult ClientModel::deployContract(bytes const& _code, TransactionSettings const& ctrTransaction)
{ {
Address contractAddress;
if (!ctrTransaction.isEmpty())
contractAddress = m_client->transact(m_client->userAccount().secret(), ctrTransaction.value, _code, ctrTransaction.gas, ctrTransaction.gasPrice);
else
{
u256 gasPrice = 10000000000000; u256 gasPrice = 10000000000000;
u256 gas = 125000; u256 gas = 125000;
u256 amount = 100; u256 amount = 100;
contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice);
Address contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice); }
ExecutionResult r = m_client->lastExecutionResult(); ExecutionResult r = m_client->lastExecutionResult();
r.contractAddress = contractAddress; r.contractAddress = contractAddress;
return r; return r;

9
mix/ClientModel.h

@ -42,6 +42,7 @@ class AppContext;
/// Backend transaction config class /// Backend transaction config class
struct TransactionSettings struct TransactionSettings
{ {
TransactionSettings() {}
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
@ -55,6 +56,10 @@ struct TransactionSettings
u256 gasPrice; u256 gasPrice;
/// Mapping from contract function parameter name to value /// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues; std::map<QString, u256> parameterValues;
public:
/// @returns true if the functionId has not be set
bool isEmpty() const { return functionId.isNull() || functionId.isEmpty(); }
}; };
@ -100,8 +105,8 @@ signals:
void dataAvailable(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); void dataAvailable(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData());
private: private:
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance); void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance, TransactionSettings const& ctrTransaction = TransactionSettings());
ExecutionResult deployContract(bytes const& _code); ExecutionResult deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
ExecutionResult callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); ExecutionResult callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
AppContext* m_context; AppContext* m_context;

1
mix/QContractDefinition.cpp

@ -33,6 +33,7 @@ using namespace dev::mix;
QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract) QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract)
{ {
m_constructor = new QFunctionDefinition(_contract->getConstructor(), -1);
auto interfaceFunctions = _contract->getInterfaceFunctions(); auto interfaceFunctions = _contract->getInterfaceFunctions();
unsigned i = 0; unsigned i = 0;
for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it, ++i) for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it, ++i)

4
mix/QContractDefinition.h

@ -36,15 +36,19 @@ class QContractDefinition: public QBasicNodeDefinition
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QQmlListProperty<dev::mix::QFunctionDefinition> functions READ functions CONSTANT) Q_PROPERTY(QQmlListProperty<dev::mix::QFunctionDefinition> functions READ functions CONSTANT)
Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT)
public: public:
QContractDefinition() {} QContractDefinition() {}
QContractDefinition(solidity::ContractDefinition const* _contract); QContractDefinition(solidity::ContractDefinition const* _contract);
/// Get all the functions of the contract. /// Get all the functions of the contract.
QQmlListProperty<QFunctionDefinition> functions() const { return QQmlListProperty<QFunctionDefinition>(const_cast<QContractDefinition*>(this), const_cast<QContractDefinition*>(this)->m_functions); } QQmlListProperty<QFunctionDefinition> functions() const { return QQmlListProperty<QFunctionDefinition>(const_cast<QContractDefinition*>(this), const_cast<QContractDefinition*>(this)->m_functions); }
/// Get the constructor of the contract.
QFunctionDefinition* constructor() const { return m_constructor; }
QList<QFunctionDefinition*> const& functionsList() const { return m_functions; } QList<QFunctionDefinition*> const& functionsList() const { return m_functions; }
private: private:
QList<QFunctionDefinition*> m_functions; QList<QFunctionDefinition*> m_functions;
QFunctionDefinition* m_constructor;
}; };
} }

2
mix/qml.qrc

@ -43,5 +43,7 @@
<file>qml/Ether.qml</file> <file>qml/Ether.qml</file>
<file>qml/EtherValue.qml</file> <file>qml/EtherValue.qml</file>
<file>qml/BigIntValue.qml</file> <file>qml/BigIntValue.qml</file>
<file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file>
</qresource> </qresource>
</RCC> </RCC>

1
mix/qml/ProjectModel.qml

@ -4,7 +4,6 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls 1.0 import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
import "js/ProjectModel.js" as ProjectModelCode import "js/ProjectModel.js" as ProjectModelCode
Item { Item {

19
mix/qml/StateDialog.qml

@ -3,6 +3,8 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import org.ethereum.qml.QEther 1.0 import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
Window { Window {
id: modalStateDialog id: modalStateDialog
@ -118,27 +120,12 @@ Window {
transactionDialog.open(index, transactionsModel.get(index)); transactionDialog.open(index, transactionsModel.get(index));
} }
function ether(_value, _unit)
{
var etherComponent = Qt.createComponent("qrc:/qml/EtherValue.qml");
var ether = etherComponent.createObject(modalStateDialog);
ether.setValue(_value);
ether.setUnit(_unit);
return ether;
}
function addTransaction() { function addTransaction() {
// Set next id here to work around Qt bug // Set next id here to work around Qt bug
// https://bugreports.qt-project.org/browse/QTBUG-41327 // https://bugreports.qt-project.org/browse/QTBUG-41327
// Second call to signal handler would just edit the item that was just created, no harm done // Second call to signal handler would just edit the item that was just created, no harm done
var item = { var item = TransactionHelper.defaultTransaction();
value: ether("0", QEther.Wei),
functionId: "",
gas: ether("125000", QEther.Wei),
gasPrice: ether("100000", QEther.Wei)
};
transactionDialog.open(transactionsModel.count, item); transactionDialog.open(transactionsModel.count, item);
} }

16
mix/qml/StateList.qml

@ -4,6 +4,7 @@ import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.ethereum.qml.QEther 1.0 import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
Rectangle { Rectangle {
color: "#ededed" color: "#ededed"
@ -67,15 +68,22 @@ Rectangle {
id: stateListModel id: stateListModel
function addState() { function addState() {
var etherComponent = Qt.createComponent("qrc:/qml/EtherValue.qml"); var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var ether = etherComponent.createObject(stateListContainer);
ether.setValue("100000000000000000000000000");
ether.setUnit(QEther.Wei);
var item = { var item = {
title: "", title: "",
balance: ether, balance: ether,
transactions: [] transactions: []
}; };
var ctorTr = {
value: QEtherHelper.createEther("100", QEther.Wei),
functionId: qsTr("Constructor"),
gas: QEtherHelper.createEther("125000", QEther.Wei),
gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei),
executeConstructor: true
};
item.transactions.push(ctorTr);
stateDialog.open(stateListModel.count, item); stateDialog.open(stateListModel.count, item);
} }

58
mix/qml/TransactionDialog.qml

@ -3,6 +3,7 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import org.ethereum.qml.QEther 1.0 import org.ethereum.qml.QEther 1.0
import "js/TransactionHelper.js" as TransactionHelper
Window { Window {
id: modalTransactionDialog id: modalTransactionDialog
@ -18,15 +19,29 @@ Window {
property alias transactionValue: valueField.value; property alias transactionValue: valueField.value;
property alias functionId: functionComboBox.currentText; property alias functionId: functionComboBox.currentText;
property var itemParams; property var itemParams;
property bool isConstructorTransaction;
property bool useTransactionDefaultValue: false
signal accepted; signal accepted;
function open(index, item) { function open(index, item) {
valueLabel.visible = !useTransactionDefaultValue;
valueField.visible = !useTransactionDefaultValue;
gasLabel.visible = !useTransactionDefaultValue;
gasFieldRect.visible = !useTransactionDefaultValue;
gasPriceLabel.visible = !useTransactionDefaultValue;
gasPriceRect.visible = !useTransactionDefaultValue;
transactionIndex = index; transactionIndex = index;
gasField.value = item.gas; gasField.value = item.gas;
gasPriceField.value = item.gasPrice; gasPriceField.value = item.gasPrice;
valueField.value = item.value; valueField.value = item.value;
var functionId = item.functionId; var functionId = item.functionId;
isConstructorTransaction = item.executeConstructor;
functionLabel.visible = !item.executeConstructor;
functionComboBox.visible = !item.executeConstructor;
console.log(item.executeConstructor);
itemParams = item.parameters !== undefined ? item.parameters : {}; itemParams = item.parameters !== undefined ? item.parameters : {};
functionsModel.clear(); functionsModel.clear();
var functionIndex = -1; var functionIndex = -1;
@ -41,7 +56,18 @@ Window {
functionIndex = 0; //@todo suggest unused funtion functionIndex = 0; //@todo suggest unused funtion
functionComboBox.currentIndex = functionIndex; functionComboBox.currentIndex = functionIndex;
paramsModel.clear();
if (!item.executeConstructor)
loadParameters(); loadParameters();
else
{
console.log("load ctro paramters");
var parameters = codeModel.code.contract.constructor.parameters;
for (var p = 0; p < parameters.length; p++) {
var pname = parameters[p].name;
paramsModel.append({ name: pname, type: parameters[p].type, value: itemParams[pname] !== undefined ? itemParams[pname].value() : "" });
}
}
visible = true; visible = true;
valueField.focus = true; valueField.focus = true;
} }
@ -49,7 +75,6 @@ Window {
function loadParameters() { function loadParameters() {
if (!paramsModel) if (!paramsModel)
return; return;
paramsModel.clear();
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; var func = codeModel.code.contract.functions[functionComboBox.currentIndex];
var parameters = func.parameters; var parameters = func.parameters;
@ -67,17 +92,37 @@ Window {
function getItem() function getItem()
{ {
var item = { var item;
if (!useTransactionDefaultValue)
{
item = {
functionId: transactionDialog.functionId, functionId: transactionDialog.functionId,
gas: transactionDialog.gas, gas: transactionDialog.gas,
gasPrice: transactionDialog.gasPrice, gasPrice: transactionDialog.gasPrice,
value: transactionDialog.transactionValue, value: transactionDialog.transactionValue,
parameters: {} parameters: {},
executeConstructor: isConstructorTransaction
};
}
else
{
item = TransactionHelper.defaultTransaction();
item.functionId = transactionDialog.functionId;
item.executeConstructor = isConstructorTransaction;
} }
if (isConstructorTransaction)
item.functionId = qsTr("Constructor");
for (var p = 0; p < transactionDialog.transactionParams.count; p++) { for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p); var parameter = transactionDialog.transactionParams.get(p);
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml"); var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml");
var param = intComponent.createObject(modalTransactionDialog); var param = intComponent.createObject(modalTransactionDialog);
console.log(param);
console.log(JSON.stringify(param));
console.log(item);
console.log(JSON.stringify(item));
param.setValue(parameter.value); param.setValue(parameter.value);
item.parameters[parameter.name] = param; item.parameters[parameter.name] = param;
} }
@ -93,6 +138,7 @@ Window {
columnSpacing: 10 columnSpacing: 10
Label { Label {
id: functionLabel;
text: qsTr("Function") text: qsTr("Function")
} }
ComboBox { ComboBox {
@ -110,10 +156,12 @@ Window {
} }
Label { Label {
id: valueLabel
text: qsTr("Value") text: qsTr("Value")
} }
Rectangle Rectangle
{ {
id: valueFieldRect
Layout.fillWidth: true Layout.fillWidth: true
Ether { Ether {
id: valueField id: valueField
@ -123,10 +171,12 @@ Window {
} }
Label { Label {
id: gasLabel
text: qsTr("Gas") text: qsTr("Gas")
} }
Rectangle Rectangle
{ {
id: gasFieldRect
Layout.fillWidth: true Layout.fillWidth: true
Ether { Ether {
id: gasField id: gasField
@ -136,10 +186,12 @@ Window {
} }
Label { Label {
id: gasPriceLabel
text: qsTr("Gas price") text: qsTr("Gas price")
} }
Rectangle Rectangle
{ {
id: gasPriceRect
Layout.fillWidth: true Layout.fillWidth: true
Ether { Ether {
id: gasPriceField id: gasPriceField

8
mix/qml/js/QEtherHelper.js

@ -0,0 +1,8 @@
function createEther(_value, _unit, _parent)
{
var etherComponent = Qt.createComponent("qrc:/qml/EtherValue.qml");
var ether = etherComponent.createObject();
ether.setValue(_value);
ether.setUnit(_unit);
return ether;
}

13
mix/qml/js/TransactionHelper.js

@ -0,0 +1,13 @@
Qt.include("QEtherHelper.js")
function defaultTransaction()
{
return {
value: createEther("0", QEther.Wei),
functionId: "",
gas: createEther("125000", QEther.Wei),
gasPrice: createEther("100000", QEther.Wei),
executeConstructor: false,
parameters: {}
};
}

29
mix/qml/main.qml

@ -5,6 +5,9 @@ import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import CodeEditorExtensionManager 1.0 import CodeEditorExtensionManager 1.0
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
ApplicationWindow { ApplicationWindow {
id: mainApplication id: mainApplication
@ -75,12 +78,38 @@ ApplicationWindow {
text: "&Run" text: "&Run"
shortcut: "F5" shortcut: "F5"
onTriggered: { onTriggered: {
if (codeModel.code.contract.constructor.parameters.length === 0)
{
mainContent.ensureRightView(); mainContent.ensureRightView();
clientModel.debugDeployment(); clientModel.debugDeployment();
} }
else
{
var item = TransactionHelper.defaultTransaction();
item.executeConstructor = true;
transactionDialog.open(0, item);
}
}
enabled: codeModel.hasContract && !clientModel.running; enabled: codeModel.hasContract && !clientModel.running;
} }
TransactionDialog {
id: transactionDialog
onAccepted: {
mainContent.ensureRightView();
var item = transactionDialog.getItem();
var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var state = {
title: "",
balance: ether,
transactions: [item]
};
clientModel.debugState(state);
}
useTransactionDefaultValue: true
}
Action { Action {
id: debugResetStateAction id: debugResetStateAction
text: "Reset &State" text: "Reset &State"

Loading…
Cancel
Save