Browse Source

Manage parameters in constructor #820

cl-refactor
yann300 10 years ago
parent
commit
0f7459490b
  1. 36
      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. 68
      mix/qml/TransactionDialog.qml
  10. 8
      mix/qml/js/QEtherHelper.js
  11. 13
      mix/qml/js/TransactionHelper.js
  12. 33
      mix/qml/main.qml

36
mix/ClientModel.cpp

@ -67,11 +67,10 @@ void ClientModel::debugState(QVariantMap _state)
QVariantList transactions = _state.value("transactions").toList();
std::vector<TransactionSettings> transactionSequence;
TransactionSettings constructorTr;
for (auto const& t: transactions)
{
QVariantMap transaction = t.toMap();
QString functionId = transaction.value("functionId").toString();
u256 gas = (qvariant_cast<QEther*>(transaction.value("gas")))->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);
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())));
}
transactionSequence.push_back(transactionSettings);
if (transaction.value("executeConstructor").toBool())
constructorTr = transactionSettings;
else
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)
throw (std::logic_error("debugging already running"));
@ -137,7 +142,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
//run contract creation first
m_client->resetState(_balance);
ExecutionResult debuggingContent = deployContract(contractCode);
ExecutionResult debuggingContent = deployContract(contractCode, ctrTransaction);
Address address = debuggingContent.contractAddress;
for (unsigned i = 0; i < _sequence.size(); ++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);
}
ExecutionResult ClientModel::deployContract(bytes const& _code)
ExecutionResult ClientModel::deployContract(bytes const& _code, TransactionSettings const& ctrTransaction)
{
u256 gasPrice = 10000000000000;
u256 gas = 125000;
u256 amount = 100;
Address contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice);
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 gas = 125000;
u256 amount = 100;
contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice);
}
ExecutionResult r = m_client->lastExecutionResult();
r.contractAddress = contractAddress;
return r;

9
mix/ClientModel.h

@ -42,6 +42,7 @@ class AppContext;
/// Backend transaction config class
struct TransactionSettings
{
TransactionSettings() {}
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
@ -55,6 +56,10 @@ struct TransactionSettings
u256 gasPrice;
/// Mapping from contract function parameter name to value
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());
private:
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
ExecutionResult deployContract(bytes const& _code);
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance, TransactionSettings const& ctrTransaction = TransactionSettings());
ExecutionResult deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
ExecutionResult callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
AppContext* m_context;

1
mix/QContractDefinition.cpp

@ -33,6 +33,7 @@ using namespace dev::mix;
QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_contract)
{
m_constructor = new QFunctionDefinition(_contract->getConstructor(), -1);
auto interfaceFunctions = _contract->getInterfaceFunctions();
unsigned i = 0;
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_PROPERTY(QQmlListProperty<dev::mix::QFunctionDefinition> functions READ functions CONSTANT)
Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT)
public:
QContractDefinition() {}
QContractDefinition(solidity::ContractDefinition const* _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); }
/// Get the constructor of the contract.
QFunctionDefinition* constructor() const { return m_constructor; }
QList<QFunctionDefinition*> const& functionsList() const { return m_functions; }
private:
QList<QFunctionDefinition*> m_functions;
QFunctionDefinition* m_constructor;
};
}

2
mix/qml.qrc

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

1
mix/qml/ProjectModel.qml

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

19
mix/qml/StateDialog.qml

@ -3,6 +3,8 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
Window {
id: modalStateDialog
@ -118,27 +120,12 @@ Window {
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() {
// Set next id here to work around Qt bug
// 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
var item = {
value: ether("0", QEther.Wei),
functionId: "",
gas: ether("125000", QEther.Wei),
gasPrice: ether("100000", QEther.Wei)
};
var item = TransactionHelper.defaultTransaction();
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.Layouts 1.1
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
Rectangle {
color: "#ededed"
@ -67,15 +68,22 @@ Rectangle {
id: stateListModel
function addState() {
var etherComponent = Qt.createComponent("qrc:/qml/EtherValue.qml");
var ether = etherComponent.createObject(stateListContainer);
ether.setValue("100000000000000000000000000");
ether.setUnit(QEther.Wei);
var ether = QEtherHelper.createEther("100000000000000000000000000", QEther.Wei);
var item = {
title: "",
balance: ether,
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);
}

68
mix/qml/TransactionDialog.qml

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

33
mix/qml/main.qml

@ -5,6 +5,9 @@ import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import CodeEditorExtensionManager 1.0
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
ApplicationWindow {
id: mainApplication
@ -75,12 +78,38 @@ ApplicationWindow {
text: "&Run"
shortcut: "F5"
onTriggered: {
mainContent.ensureRightView();
clientModel.debugDeployment();
if (codeModel.code.contract.constructor.parameters.length === 0)
{
mainContent.ensureRightView();
clientModel.debugDeployment();
}
else
{
var item = TransactionHelper.defaultTransaction();
item.executeConstructor = true;
transactionDialog.open(0, item);
}
}
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 {
id: debugResetStateAction
text: "Reset &State"

Loading…
Cancel
Save