From 870e58e1fb630ef9752811fd2ea41090e16a1a50 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 8 Jul 2015 17:05:20 +0200 Subject: [PATCH 01/13] ScenarioLoader.qml ui changes --- mix/ClientModel.cpp | 1 - mix/CodeModel.h | 5 + mix/qml/Application.qml | 2 +- mix/qml/BlockChain.qml | 111 +++++++++++++-- mix/qml/ScenarioButton.qml | 8 +- mix/qml/ScenarioLoader.qml | 276 ++++++++++++++++++++----------------- mix/qml/StateListModel.qml | 5 +- mix/qml/Watchers.qml | 4 +- 8 files changed, 265 insertions(+), 147 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index eae3f8834..42fc4cfc3 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -351,7 +351,6 @@ void ClientModel::executeSequence(vector const& _sequence) if (!transaction.isFunctionCall) { callAddress(Address(address.toStdString()), bytes(), transaction); - onNewTransaction(); continue; } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index e51eabf51..73835d807 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "SolidityType.h" #include "QBigInt.h" @@ -246,8 +247,12 @@ public: void gasEstimation(solidity::CompilerStack const& _cs); /// Gas cost by doc id Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const; + /// Gas cost by @arg contractName @arg functionName Q_INVOKABLE QVariantList gasCostBy(QString const& _contractName, QString const& _functionName) const; + /// Set optimize code Q_INVOKABLE void setOptimizeCode(bool _value); + /// sha3 + Q_INVOKABLE QString sha3(QString _source) { return QString::fromStdString(dev::sha3(_source.toStdString()).hex()); } int txGas() { return static_cast(dev::eth::c_txGas); } int callStipend() { return static_cast(dev::eth::c_callStipend); } diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index 61a2e09b1..bdb0896e5 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -202,7 +202,7 @@ ApplicationWindow { text: qsTr("Deploy") shortcut: "F5" onTriggered: mainContent.startQuickDebugging() - enabled: codeModel.hasContract && !clientModel.running + enabled: codeModel.hasContract && !clientModel.running && projectModel.stateListModel.defaultStateName() !== "" } Action { diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index ccc027444..b6b5e3403 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -20,7 +20,7 @@ ColumnLayout { spacing: 0 property int previousWidth property variant debugTrRequested: [] - signal chainChanged + signal chainChanged(var blockIndex, var txIndex, var item) signal chainReloaded signal txSelected(var blockIndex, var txIndex) signal rebuilding @@ -30,15 +30,46 @@ ColumnLayout { { target: codeModel onContractRenamed: { - rebuild.startBlinking() + rebuild.needRebuild("ContractRenamed") } onNewContractCompiled: { - rebuild.startBlinking() + rebuild.needRebuild("NewContractCompiled") + } + onCompilationComplete: { + for (var c in rebuild.contractsHex) + { + if (codeModel.contracts[c] === undefined || codeModel.contracts[c].codeHex !== rebuild.contractsHex[c]) + { + if (!rebuild.containsRebuildCause("CodeChanged")) + { + rebuild.needRebuild("CodeChanged") + } + return + } + } + rebuild.notNeedRebuild("CodeChanged") } } + onChainChanged: { - rebuild.startBlinking() + if (rebuild.txSha3[blockIndex][txIndex] !== codeModel.sha3(JSON.stringify(model.blocks[blockIndex].transactions[txIndex]))) + { + rebuild.txChanged.push(rebuild.txSha3[blockIndex][txIndex]) + rebuild.needRebuild("txChanged") + } + else { + for (var k in rebuild.txChanged) + { + if (rebuild.txChanged[k] === rebuild.txSha3[blockIndex][txIndex]) + { + rebuild.txChanged.splice(k, 1) + break + } + } + if (rebuild.txChanged.length === 0) + rebuild.notNeedRebuild("txChanged") + } } onWidthChanged: @@ -174,7 +205,8 @@ ColumnLayout { Connections { target: block - onTxSelected: { + onTxSelected: + { blockChainPanel.txSelected(index, txIndex) } } @@ -274,8 +306,7 @@ ColumnLayout { Rectangle { Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - + Layout.preferredHeight: 30 ScenarioButton { id: rebuild text: qsTr("Rebuild") @@ -283,6 +314,43 @@ ColumnLayout { height: 30 roundLeft: true roundRight: true + property variant contractsHex: ({}) + property variant txSha3: ({}) + property variant txChanged: [] + property var blinkReasons: [] + + function needRebuild(reason) + { + rebuild.startBlinking() + blinkReasons.push(reason) + } + + function containsRebuildCause(reason) + { + for (var c in blinkReasons) + { + if (blinkReasons[c] === reason) + { + return true + } + } + } + + + function notNeedRebuild(reason) + { + for (var c in blinkReasons) + { + if (blinkReasons[c] === reason) + { + blinkReasons.splice(c, 1) + break + } + } + if (blinkReasons.length === 0) + rebuild.stopBlinking() + } + onClicked: { if (ensureNotFuturetime.running) @@ -335,8 +403,34 @@ ColumnLayout { blockModel.append(model.blocks[j]) ensureNotFuturetime.start() + takeCodeSnapshot() + takeTxSnaphot() + blinkReasons = [] clientModel.setupScenario(model); } + + function takeCodeSnapshot() + { + contractsHex = {} + for (var c in codeModel.contracts) + contractsHex[c] = codeModel.contracts[c].codeHex + } + + function takeTxSnaphot() + { + txSha3 = {} + txChanged = [] + for (var j = 0; j < model.blocks.length; j++) + { + for (var k = 0; k < model.blocks[j].transactions.length; k++) + { + if (txSha3[j] === undefined) + txSha3[j] = {} + txSha3[j][k] = codeModel.sha3(JSON.stringify(model.blocks[j].transactions[k])) + } + } + } + buttonShortcut: "" sourceImg: "qrc:/qml/img/recycleicon@2x.png" } @@ -548,9 +642,8 @@ ColumnLayout { else { model.blocks[blockIndex].transactions[transactionIndex] = item blockModel.setTransaction(blockIndex, transactionIndex, item) - chainChanged() + chainChanged(blockIndex, transactionIndex, item) } - } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml index d4beaefaa..4c60682ca 100644 --- a/mix/qml/ScenarioButton.qml +++ b/mix/qml/ScenarioButton.qml @@ -30,8 +30,8 @@ Rectangle { id: left width: 10 height: parent.height - anchors.left: parent.left - anchors.leftMargin: -8 + anchors.left: contentRectangle.left + anchors.leftMargin: -4 radius: 15 } @@ -111,8 +111,8 @@ Rectangle { id: right width: 10 height: parent.height - anchors.left: contentRectangle.right - anchors.leftMargin: -8 + anchors.right: contentRectangle.right + anchors.rightMargin: -4 radius: 15 } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 58247b213..a54eb48bf 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -6,6 +6,7 @@ import QtQuick.Dialogs 1.2 import QtQuick.Window 2.0 import QtQuick.Dialogs 1.1 import Qt.labs.settings 1.0 +import org.ethereum.qml.InverseMouseArea 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." @@ -18,6 +19,7 @@ ColumnLayout signal duplicated(variant scenario) signal loaded(variant scenario) signal renamed(variant scenario) + signal deleted() spacing: 0 function init() { @@ -29,146 +31,92 @@ ColumnLayout editStatus.visible = true } - Rectangle + RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: 30 - color: "transparent" - Rectangle + Layout.preferredWidth: 560 + anchors.horizontalCenter: parent.horizontalCenter + Layout.preferredHeight: 60 + spacing: 0 + anchors.top: parent.top + anchors.topMargin: 10 + + Row { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - color: "transparent" - Label - { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - id: scenarioName - font.bold: true - } + Layout.preferredWidth: 100 * 5 + 30 + Layout.preferredHeight: 50 + spacing: 25 - TextInput + Rectangle { - id: scenarioNameEdit - visible: false - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - Keys.onEnterPressed: - { - save() - } - - function edit() - { - editIconRect.anchors.left = scenarioNameEdit.right - editStatus.parent.anchors.left = scenarioNameEdit.right - scenarioNameEdit.forceActiveFocus() - } - - function save() - { - editIconRect.anchors.left = scenarioName.right - editStatus.parent.anchors.left = scenarioName.right - scenarioName.text = scenarioNameEdit.text - scenarioName.visible = true - scenarioNameEdit.visible = false - projectModel.stateListModel.getState(scenarioList.currentIndex).title = scenarioName.text - projectModel.saveProjectFile() - saved(state) - scenarioList.model.get(scenarioList.currentIndex).title = scenarioName.text - scenarioList.currentIndex = scenarioList.currentIndex - renamed(projectModel.stateListModel.getState(scenarioList.currentIndex)) - } - } + color: "white" + width: 251 + 30 + height: 30 - Connections - { - target: blockChainSelector - onLoaded: + Rectangle { - scenarioName.text = scenario.title - scenarioNameEdit.text = scenario.title - } - } - - Rectangle - { - anchors.left: scenarioName.right - anchors.top: scenarioName.top - anchors.leftMargin: 2 - Layout.preferredWidth: 20 - Text { - id: editStatus - text: "*" - visible: false + id: left + width: 10 + height: parent.height + anchors.left: parent.left + anchors.leftMargin: -5 + radius: 15 } - } - Rectangle - { - id: editIconRect - anchors.top: scenarioName.top - anchors.topMargin: 6 - anchors.left: scenarioName.right - anchors.leftMargin: 20 Image { source: "qrc:/qml/img/edittransaction.png" - width: 30 + height: parent.height - 10 fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 4 + id: editImg MouseArea { anchors.fill: parent onClicked: { - scenarioName.visible = !scenarioName.visible - scenarioNameEdit.visible = !scenarioNameEdit.visible - if (!scenarioNameEdit.visible) - scenarioNameEdit.save() - else - scenarioNameEdit.edit() + scenarioNameEdit.toggleEdit() } } } - } - } - } - RowLayout - { - Layout.preferredWidth: 560 - anchors.horizontalCenter: parent.horizontalCenter - Layout.preferredHeight: 50 - spacing: 0 - - Row - { - Layout.preferredWidth: 100 * 5 - Layout.preferredHeight: 50 - spacing: 15 - - Rectangle - { - color: "transparent" - width: 251 - height: 30 - Rectangle + Label { - width: 10 + anchors.left: editImg.right + text: "X" height: parent.height - anchors.right: scenarioList.left - anchors.rightMargin: -8 - radius: 15 + color: "#cccccc" + id: deleteImg + anchors.top: parent.top + anchors.topMargin: 6 + visible: projectModel.stateListModel.count > 1 + MouseArea + { + anchors.fill: parent + onClicked: + { + if (projectModel.stateListModel.count > 1) + { + projectModel.stateListModel.deleteState(scenarioList.currentIndex) + scenarioList.currentIndex = 0 + deleted() + } + } + } } ComboBox { id: scenarioList + anchors.left: deleteImg.right + anchors.leftMargin: 2 model: projectModel.stateListModel + anchors.top: parent.top textRole: "title" height: parent.height width: 150 + signal updateView() + onCurrentIndexChanged: { restoreScenario.restore() @@ -177,15 +125,18 @@ ColumnLayout function load() { var state = projectModel.stateListModel.getState(currentIndex) - loaded(state) + if (state) + loaded(state) } style: ComboBoxStyle { + id: style background: Rectangle { color: "white" anchors.fill: parent } label: Rectangle { + property alias label: comboLabel anchors.fill: parent color: "white" Label { @@ -194,20 +145,33 @@ ColumnLayout elide: Text.ElideRight width: parent.width anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: { - if (projectModel.stateListModel.getState(scenarioList.currentIndex)) - return projectModel.stateListModel.getState(scenarioList.currentIndex).title - else - return "" + anchors.left: parent.left + Component.onCompleted: + { + comboLabel.updateLabel() + } + + function updateLabel() + { + comboLabel.text = "" + if (scenarioList.currentIndex < projectModel.stateListModel.count) + comboLabel.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title } + Connections { target: blockChainSelector onLoaded: { - comboLabel.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title + if (projectModel.stateListModel.count > 0) + comboLabel.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title + else + return "" } onRenamed: { comboLabel.text = scenario.title + scenarioNameEdit.text = scenario.title + } + onDeleted: { + comboLabel.updateLabel() } } } @@ -215,9 +179,74 @@ ColumnLayout } } + TextField + { + id: scenarioNameEdit + anchors.left: deleteImg.right + anchors.leftMargin: 2 + height: parent.height + z: 5 + visible: false + width: 150 + Keys.onEnterPressed: + { + toggleEdit() + } + + Keys.onReturnPressed: + { + toggleEdit() + } + + function toggleEdit() + { + scenarioList.visible = !scenarioList.visible + scenarioNameEdit.visible = !scenarioNameEdit.visible + if (!scenarioNameEdit.visible) + scenarioNameEdit.save() + else + { + scenarioNameEdit.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title + scenarioNameEdit.forceActiveFocus() + outsideClick.active = true + } + } + + function save() + { + outsideClick.active = false + projectModel.stateListModel.getState(scenarioList.currentIndex).title = scenarioNameEdit.text + projectModel.saveProjectFile() + saved(state) + scenarioList.model.get(scenarioList.currentIndex).title = scenarioNameEdit.text + scenarioList.currentIndex = scenarioList.currentIndex + renamed(projectModel.stateListModel.getState(scenarioList.currentIndex)) + } + + style: TextFieldStyle { + background: Rectangle { + radius: 2 + implicitWidth: 100 + implicitHeight: 30 + color: "white" + border.color: "#cccccc" + border.width: 1 + } + } + + InverseMouseArea { + id: outsideClick + anchors.fill: parent + active: false + onClickedOutside: { + scenarioNameEdit.toggleEdit() + } + } + } + Rectangle { - width: 1 + width: 1 height: parent.height anchors.right: addScenario.left color: "#ededed" @@ -236,7 +265,6 @@ ColumnLayout projectModel.stateListModel.appendState(item) projectModel.stateListModel.save() scenarioList.currentIndex = projectModel.stateListModel.count - 1 - scenarioNameEdit.edit() } text: qsTr("New..") roundRight: true @@ -251,15 +279,6 @@ ColumnLayout height: 30 color: "transparent" - Rectangle - { - width: 10 - height: parent.height - anchors.right: restoreScenario.left - anchors.rightMargin: -4 - radius: 15 - } - ScenarioButton { id: restoreScenario width: 100 @@ -275,7 +294,6 @@ ColumnLayout var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) if (state) { - editStatus.visible = false restored(state) loaded(state) } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d3bf1c860..e7b092463 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -403,7 +403,10 @@ Item { function defaultStateName() { - return stateList[defaultStateIndex].title; + if (stateList.length > 0) + return stateList[defaultStateIndex].title; + else + return "" } function reloadStateFromFromProject(index) diff --git a/mix/qml/Watchers.qml b/mix/qml/Watchers.qml index 9625d9424..654670d6c 100644 --- a/mix/qml/Watchers.qml +++ b/mix/qml/Watchers.qml @@ -83,7 +83,7 @@ Rectangle { Label { id: fromLabel text: qsTr("from") - visible: from.text !== "" + visible: false color: "#EAB920" } Label { @@ -97,7 +97,7 @@ Rectangle { Label { id: toLabel text: qsTr("to") - visible: from.text !== "" + visible: false color: "#EAB920" } Label { From ae07c6a11a51d1175e55cb0fac22c840ea81408f Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 13 Jul 2015 16:39:05 +0200 Subject: [PATCH 02/13] deploy dialog --- mix/ClientModel.cpp | 73 ++-- mix/ClientModel.h | 8 +- mix/MixClient.cpp | 35 +- mix/MixClient.h | 2 +- mix/qml.qrc | 5 + mix/qml/Application.qml | 5 + mix/qml/CodeEditorView.qml | 13 + mix/qml/DeployContractStep.qml | 352 ++++++++++++++++++ mix/qml/DeploymentDialog.qml | 584 ++++-------------------------- mix/qml/DeploymentDialogSteps.qml | 133 +++++++ mix/qml/DeploymentWorker.qml | 176 +++++++++ mix/qml/Ether.qml | 7 +- mix/qml/PackagingStep.qml | 192 ++++++++++ mix/qml/ProjectModel.qml | 4 +- mix/qml/RegisteringStep.qml | 230 ++++++++++++ mix/qml/TransactionDialog.qml | 23 +- mix/qml/js/NetworkDeployment.js | 149 ++++---- mix/qml/js/ProjectModel.js | 8 +- mix/qml/js/TransactionHelper.js | 7 + 19 files changed, 1361 insertions(+), 645 deletions(-) create mode 100644 mix/qml/DeployContractStep.qml create mode 100644 mix/qml/DeploymentDialogSteps.qml create mode 100644 mix/qml/DeploymentWorker.qml create mode 100644 mix/qml/PackagingStep.qml create mode 100644 mix/qml/RegisteringStep.qml diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 9b4eeab14..7cc080d99 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -81,13 +81,7 @@ ClientModel::ClientModel(): qRegisterMetaType("QInstruction"); qRegisterMetaType("QCode"); qRegisterMetaType("QCallData"); - qRegisterMetaType("RecordLogEntry*"); - - m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); - - m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); - m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); - connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); + qRegisterMetaType("RecordLogEntry*"); } ClientModel::~ClientModel() @@ -95,6 +89,19 @@ ClientModel::~ClientModel() m_runFuture.waitForFinished(); } +void ClientModel::init(QString _dbpath) +{ + m_dbpath = _dbpath; + if (m_dbpath.isEmpty()) + m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); + else + m_client.reset(new MixClient(m_dbpath.toStdString())); + + m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); + m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); + connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); +} + QString ClientModel::apiCall(QString const& _message) { try @@ -295,36 +302,40 @@ void ClientModel::finalizeBlock() } } +TransactionSettings ClientModel::transaction(QVariant _tr) +{ + QVariantMap transaction = _tr.toMap(); + QString contractId = transaction.value("contractId").toString(); + QString functionId = transaction.value("functionId").toString(); + bool gasAuto = transaction.value("gasAuto").toBool(); + u256 gas = 0; + if (transaction.value("gas").data()) + gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); + else + gasAuto = true; + + u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); + u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); + QString sender = transaction.value("sender").toString(); + bool isContractCreation = transaction.value("isContractCreation").toBool(); + bool isFunctionCall = transaction.value("isFunctionCall").toBool(); + if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later + contractId = m_codeModel->contracts().keys()[0]; + Secret f = Secret(sender.toStdString()); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); + transactionSettings.parameterValues = transaction.value("parameters").toMap(); + if (contractId == functionId || functionId == "Constructor") + transactionSettings.functionId.clear(); + return transactionSettings; +} + void ClientModel::processNextTransactions() { WriteGuard(x_queueTransactions); vector transactionSequence; for (auto const& t: m_queueTransactions.front()) { - QVariantMap transaction = t.toMap(); - QString contractId = transaction.value("contractId").toString(); - QString functionId = transaction.value("functionId").toString(); - bool gasAuto = transaction.value("gasAuto").toBool(); - u256 gas = 0; - if (transaction.value("gas").data()) - gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); - else - gasAuto = true; - - u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); - u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); - QString sender = transaction.value("sender").toString(); - bool isContractCreation = transaction.value("isContractCreation").toBool(); - bool isFunctionCall = transaction.value("isFunctionCall").toBool(); - if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later - contractId = m_codeModel->contracts().keys()[0]; - Secret f = Secret(sender.toStdString()); - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); - transactionSettings.parameterValues = transaction.value("parameters").toMap(); - - if (contractId == functionId || functionId == "Constructor") - transactionSettings.functionId.clear(); - + TransactionSettings transactionSettings = transaction(t); transactionSequence.push_back(transactionSettings); } executeSequence(transactionSequence); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index ca8c36b79..4a367f9ba 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -171,7 +171,7 @@ public: Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) /// @returns deployed contracts gas costs Q_PROPERTY(QVariantList gasCosts READ gasCosts NOTIFY gasCostsChanged) - // @returns the last block + /// @returns the last block Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT) /// ethereum.js RPC request entry point /// @param _message RPC request in Json format @@ -191,6 +191,10 @@ public: Q_INVOKABLE void addAccount(QString const& _secret); /// Return the address associated with the current secret Q_INVOKABLE QString resolveAddress(QString const& _secret); + /// Compute required gas for a list of transactions @arg _tr + QBigInt computeRequiredGas(QVariantList _tr); + /// init eth client + Q_INVOKABLE void init(QString _dbpath); public slots: /// Setup scenario, run transaction sequence, show debugger for the last transaction @@ -266,6 +270,7 @@ private: void finalizeBlock(); void stopExecution(); void setupExecutionChain(); + TransactionSettings transaction(QVariant _tr); std::atomic m_running; std::atomic m_mining; @@ -284,6 +289,7 @@ private: CodeModel* m_codeModel = nullptr; QList m_queueTransactions; mutable boost::shared_mutex x_queueTransactions; + QString m_dbpath; }; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index c73763076..8e3b24cd9 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -79,7 +79,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -124,22 +123,16 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre return ret; } -void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) +ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, LastHashes _lastHashes, bool _call) { - Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; - // do debugging run first - LastHashes lastHashes(256); - lastHashes[0] = bc().numberHash(bc().number()); - for (unsigned i = 1; i < 256; ++i) - lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); - State execState = _state; - execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation + execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation eth::ExecutionResult er; - Executive execution(execState, lastHashes, 0); + Executive execution(execState, _lastHashes, 0); execution.setResultRecipient(er); - execution.initialize(t); + execution.initialize(_t); execution.execute(); + std::vector machineStates; std::vector levels; std::vector codes; @@ -235,7 +228,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c } ExecutionResult d; - d.inputParameters = t.data(); + d.inputParameters = _t.data(); d.result = er; d.machineStates = machineStates; d.executionCode = std::move(codes); @@ -249,12 +242,26 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (!_call) d.transactionIndex = m_state.pending().size(); d.executonIndex = m_executions.size(); + return d; +} + + +void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) +{ + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; + // do debugging run first + LastHashes lastHashes(256); + lastHashes[0] = bc().numberHash(bc().number()); + for (unsigned i = 1; i < 256; ++i) + lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); + + ExecutionResult d = debugTransaction(t, _state, lastHashes, _call); // execute on a state if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er = _state.execute(lastHashes, t); + eth::ExecutionResult er = _state.execute(lastHashes, _t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..75f45efbf 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -61,7 +61,7 @@ public: virtual std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); } std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto); dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); - + ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::LastHashes _lastHashes, bool _call); void setAddress(Address _us) override; void startMining() override; void stopMining() override; diff --git a/mix/qml.qrc b/mix/qml.qrc index 34295b022..c1901c220 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -71,5 +71,10 @@ qml/ScenarioButton.qml qml/Watchers.qml qml/KeyValuePanel.qml + qml/DeployContractStep.qml + qml/RegisteringStep.qml + qml/DeploymentDialogSteps.qml + qml/PackagingStep.qml + qml/DeploymentWorker.qml diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index bdb0896e5..8ee70942d 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -42,6 +42,11 @@ ApplicationWindow { ClientModel { id: clientModel codeModel: codeModel + Component.onCompleted: + { + console.log("tmp") + init("/tmp") + } } ProjectModel { diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 51950fec7..774a3b11f 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -24,6 +24,19 @@ Item { return ""; } + function getContracts() + { + var ctr = [] + for (var i = 0; i < openDocCount; i++) + { + if (editorListModel.get(i).isContract) + { + ctr.push(editors.itemAt(i).item) + } + } + return ctr; + } + function isDocumentOpen(documentId) { for (var i = 0; i < openDocCount; i++) if (editorListModel.get(i).documentId === documentId && diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml new file mode 100644 index 000000000..4d675a639 --- /dev/null +++ b/mix/qml/DeployContractStep.qml @@ -0,0 +1,352 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import org.ethereum.qml.QEther 1.0 + +Rectangle { + property variant paramsModel: [] + property variant worker + color: "#E3E3E3E3" + anchors.fill: parent + id: root + + function show() + { + visible = true + contractList.currentIndex = 0 + contractList.change() + accountsModel.clear() + for (var k in worker.accounts) + { + accountsModel.append(worker.accounts[k]) + } + if (worker.accounts.length > 0) + worker.currentAccount = worker.accounts[0].id + } + + RowLayout + { + anchors.fill: parent + anchors.margins: 10 + ColumnLayout + { + anchors.top: parent.top + Layout.preferredWidth: parent.width * 0.40 - 20 + Layout.fillHeight: true + id: scenarioList + + Label + { + Layout.fillWidth: true + text: qsTr("Pick Scenario to deploy") + } + + ComboBox + { + id: contractList + Layout.preferredWidth: parent.width - 20 + model: projectModel.stateListModel + textRole: "title" + onCurrentIndexChanged: + { + change() + } + + function change() + { + trListModel.clear() + if (currentIndex > -1) + { + for (var k = 0; k < projectModel.stateListModel.get(currentIndex).blocks.count; k++) + { + for (var j = 0; j < projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.count; j++) + { + trListModel.append(projectModel.stateListModel.get(currentIndex).blocks.get(k).transactions.get(j)); + } + } + for (var k = 0; k < trListModel.count; k++) + { + trList.itemAt(k).init() + } + ctrDeployCtrLabel.calculateContractDeployGas(); + } + } + } + + Rectangle + { + Layout.fillHeight: true + Layout.preferredWidth: parent.width - 20 + id: trContainer + color: "white" + border.color: "#cccccc" + border.width: 1 + ScrollView + { + anchors.fill: parent + ColumnLayout + { + spacing: 0 + ListModel + { + id: trListModel + } + + Repeater + { + id: trList + model: trListModel + ColumnLayout + { + Layout.fillWidth: true + spacing: 5 + Layout.preferredHeight: + { + if (index > -1) + return 20 + trListModel.get(index)["parameters"].count * 20 + else + return 20 + } + + function init() + { + paramList.clear() + if (trListModel.get(index).parameters) + { + for (var k in trListModel.get(index).parameters) + { + paramList.append({ "name": k, "value": trListModel.get(index).parameters[k] }) + } + } + } + + Label + { + id: trLabel + Layout.preferredHeight: 20 + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 5 + anchors.leftMargin: 10 + text: + { + if (index > -1) + return trListModel.get(index).label + else + return "" + } + } + + ListModel + { + id: paramList + } + + Repeater + { + Layout.preferredHeight: + { + if (index > -1) + return trListModel.get(index)["parameters"].count * 20 + else + return 0 + } + model: paramList + Label + { + Layout.preferredHeight: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + text: name + "=" + value + font.italic: true + } + } + } + } + } + } + } + } + + + ColumnLayout + { + anchors.top: parent.top + Layout.preferredHeight: parent.height - 25 + ColumnLayout + { + anchors.top: parent.top + Layout.preferredWidth: parent.width * 0.60 + Layout.fillHeight: true + id: deploymentOption + + Label + { + anchors.left: parent.left + anchors.leftMargin: 105 + text: qsTr("Deployment options") + } + + ListModel + { + id: accountsModel + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + width: 100 + Label + { + text: qsTr("Account") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + ComboBox + { + id: accountsList + textRole: "id" + model: accountsModel + Layout.preferredWidth: 235 + onCurrentTextChanged: + { + worker.currentAccount = currentText + } + } + } + + RowLayout + { + Layout.fillWidth: true + Rectangle + { + width: 100 + Label + { + text: qsTr("Gas Price") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Ether + { + id: gasPriceInput + displayUnitSelection: true + displayFormattedValue: false + edit: true + } + + Connections + { + target: gasPriceInput + onValueChanged: + { + ctrDeployCtrLabel.calculateContractDeployGas() + } + onAmountChanged: + { + ctrDeployCtrLabel.setCost() + } + onUnitChanged: + { + ctrDeployCtrLabel.setCost() + } + } + + Connections + { + target: worker + id: gasPriceLoad + property bool loaded: false + onGasPriceLoaded: + { + gasPriceInput.value = QEtherHelper.createEther(worker.gasPriceInt.value(), QEther.Wei) + gasPriceLoad.loaded = true + ctrDeployCtrLabel.calculateContractDeployGas() + } + } + } + + RowLayout + { + id: ctrDeployCtrLabel + Layout.fillWidth: true + property int cost + function calculateContractDeployGas() + { + if (!root.visible) + return; + var sce = projectModel.stateListModel.getState(contractList.currentIndex) + worker.estimateGas(sce, function(gas) { + if (gasPriceLoad.loaded) + { + cost = 0 + for (var k in gas) + { + cost += gas[k] + } + setCost() + } + }); + } + + function setCost() + { + var ether = QEtherHelper.createBigInt(cost); + var gasTotal = ether.multiply(gasPriceInput.value); + gasToUseInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); + } + + Rectangle + { + width: 100 + Label + { + text: qsTr("Cost Estimate") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Ether + { + id: gasToUseInput + displayUnitSelection: false + displayFormattedValue: true + edit: false + Layout.preferredWidth: 350 + } + } + + + } + + Rectangle + { + Layout.preferredWidth: parent.width + Layout.alignment: Qt.BottomEdge + Button + { + anchors.right: parent.right + text: qsTr("Deploy Contracts") + onClicked: + { + projectModel.deployedScenarioIndex = contractList.currentIndex + NetworkDeploymentCode.deployContracts(); + } + } + } + } + } + +} + diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 81092ec76..ad946cd3e 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -14,22 +14,14 @@ import "." Dialog { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 735 + width: 800 height: 450 visible: false - property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. - property int ownedRegistrarSetSubRegistrarGas: 50000 - property int ownedRegistrarSetContentHashGas: 50000 - property int urlHintSuggestUrlGas: 70000 - property alias applicationUrlEth: applicationUrlEth.text - property alias applicationUrlHttp: applicationUrlHttp.text - property alias localPackageUrl: localPackageUrl.text - property string packageHash - property string packageBase64 - property string eth: registrarAddr.text - property string currentAccount - property string gasPrice - property variant paramsModel: [] + + property alias deployStep: deployStep + property alias packageStep: packageStep + property alias registerStep: registerStep + property alias worker: worker function close() { @@ -38,552 +30,126 @@ Dialog { function open() { + deployStep.visible = false + packageStep.visible = false + registerStep.visible = false + steps.init() + worker.renewCtx() visible = true; - var requests = [{ - //accounts - jsonrpc: "2.0", - method: "eth_accounts", - params: null, - id: 0 - }]; - - TransactionHelper.rpcCall(requests, function(arg1, arg2) - { - modelAccounts.clear(); - var ids = JSON.parse(arg2)[0].result; - requests = []; - for (var k in ids) - { - modelAccounts.append({ "id": ids[k] }) - requests.push({ - //accounts - jsonrpc: "2.0", - method: "eth_getBalance", - params: [ids[k], 'latest'], - id: k - }); - } - - if (ids.length > 0) - currentAccount = modelAccounts.get(0).id; - - TransactionHelper.rpcCall(requests, function (request, response){ - var balanceRet = JSON.parse(response); - for (var k in balanceRet) - { - var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); - comboAccounts.balances.push(ether.format()); - comboAccounts.weiBalances.push(balanceRet[k].result); - } - balance.text = comboAccounts.balances[0]; - }); - }); - - if (clientModel.gasCosts.length === 0) - { - errorDialog.text = qsTr("Please run the state one time before deploying in order to calculate gas requirement."); - errorDialog.open(); - } - else - { - NetworkDeploymentCode.gasPrice(function(price) { - gasPrice = price; - gasPriceInt.setValue(gasPrice); - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - }); - } } - function stopForInputError(inError) + DeploymentWorker { - errorDialog.text = ""; - if (inError.length > 0) - { - errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n") - for (var k in inError) - errorDialog.text += inError[k] + "\n"; - errorDialog.open(); - return true; - } - return false; - } - - function pad(h) - { - // TODO move this to QHashType class - while (h.length < 64) - { - h = '0' + h; - } - return h; - } - - function waitForTrCountToIncrement(callBack) - { - poolLog.callBack = callBack; - poolLog.k = -1; - poolLog.elapsed = 0; - poolLog.start(); - } - - BigIntValue - { - id: gasPriceInt - } - - Timer - { - id: poolLog - property var callBack - property int k: -1 - property int elapsed - interval: 500 - running: false - repeat: true - onTriggered: { - elapsed += interval; - var requests = []; - var jsonRpcRequestId = 0; - requests.push({ - jsonrpc: "2.0", - method: "eth_getTransactionCount", - params: [ currentAccount, "pending" ], - id: jsonRpcRequestId++ - }); - TransactionHelper.rpcCall(requests, function (httpRequest, response){ - response = response.replace(/,0+/, ''); // ==> result:27,00000000 - var count = JSON.parse(response)[0].result - console.log("count " + count); - if (k < parseInt(count) && k > 0) - { - stop(); - callBack(1); - } - else if (elapsed > 25000) - { - stop(); - callBack(-1); - } - else - k = parseInt(JSON.parse(response)[0].result); - }) - } - } - - SourceSansProRegular - { - id: lightFont + id: worker } contentItem: Rectangle { color: appStyle.generic.layout.backgroundColor anchors.fill: parent - Column + ColumnLayout { spacing: 5 anchors.fill: parent anchors.margins: 10 - ColumnLayout + + RowLayout { - id: containerDeploy - Layout.fillWidth: true - Layout.preferredHeight: 500 - RowLayout + id: explanation + Layout.preferredWidth: parent.width - 50 + Layout.preferredHeight: 50 + Label { - Rectangle - { - Layout.preferredWidth: 357 - DefaultLabel - { - text: qsTr("Deployment") - font.family: lightFont.name - font.underline: true - anchors.centerIn: parent - } - } - - Button - { - action: displayHelpAction - iconSource: "qrc:/qml/img/help.png" - } - - Action { - id: displayHelpAction - tooltip: qsTr("Help") - onTriggered: { - Qt.openUrlExternally("https://github.com/ethereum/wiki/wiki/Mix:-The-DApp-IDE#deployment-to-network") - } - } - - Button - { - action: openFolderAction - iconSource: "qrc:/qml/img/openedfolder.png" - } - - Action { - id: openFolderAction - enabled: deploymentDialog.packageBase64 !== "" - tooltip: qsTr("Open Package Folder") - onTriggered: { - fileIo.openFileBrowser(projectModel.deploymentDir); - } - } - - Button - { - action: b64Action - iconSource: "qrc:/qml/img/b64.png" - } - - Action { - id: b64Action - enabled: deploymentDialog.packageBase64 !== "" - tooltip: qsTr("Copy Base64 conversion to ClipBoard") - onTriggered: { - clipboard.text = deploymentDialog.packageBase64; - } - } - - Button - { - action: exitAction - iconSource: "qrc:/qml/img/exit.png" - } - - Action { - id: exitAction - tooltip: qsTr("Exit") - onTriggered: { - close() - } - } + anchors.centerIn: parent + text: qsTr("Putting your dapp live is a multi step process. You can read more about it on the 'guide to uploading'.") } + } - GridLayout + RowLayout + { + ColumnLayout { - columns: 2 - width: parent.width - - DefaultLabel + Layout.preferredHeight: parent.height - 50 + Layout.preferredWidth: 200 + DeploymentDialogSteps { - text: qsTr("State:") + id: steps } + } - Rectangle + Connections + { + target: steps + property variant selected + onSelected: { - width: 300 - color: "transparent" - height: 25 - id: paramsRect - ComboBox + if (selected) + selected.visible = false + switch (step) { - id: statesList - textRole: "title" - model: projectModel.stateListModel - onCurrentIndexChanged : { - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - } - } - } - - DefaultLabel - { - text: qsTr("Root Registrar address:") - visible: true //still use it for now in dev env. - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: registrarAddr - text: "c6d9d2cd449a754c494264e1809c50e34d64562b" - visible: true - } - - DefaultLabel - { - text: qsTr("Account used to deploy:") - } - - Rectangle - { - width: 300 - height: 25 - color: "transparent" - ComboBox { - id: comboAccounts - property var balances: [] - property var weiBalances: [] - onCurrentIndexChanged : { - if (modelAccounts.count > 0) - { - currentAccount = modelAccounts.get(currentIndex).id; - balance.text = balances[currentIndex]; - balanceInt.setValue(weiBalances[currentIndex]); - ctrDeployCtrLabel.calculateContractDeployGas(); - ctrRegisterLabel.calculateRegisterGas(); - } - } - model: ListModel { - id: modelAccounts - } + case "deploy": + { + selected = deployStep + break; } - - DefaultLabel + case "package": { - anchors.verticalCenter: parent.verticalCenter - anchors.left: comboAccounts.right - anchors.leftMargin: 20 - id: balance; + selected = packageStep + break; } - - BigIntValue + case "register": { - id: balanceInt + selected = registerStep + break; } + } + selected.show() } } - DefaultLabel + ColumnLayout { - text: qsTr("Amount of gas to use for contract deployment: ") - id: ctrDeployCtrLabel - function calculateContractDeployGas() + Layout.preferredHeight: parent.height - 50 + Layout.preferredWidth: parent.width - 200 + DeployContractStep { - var ether = QEtherHelper.createBigInt(NetworkDeploymentCode.gasUsed()); - var gasTotal = ether.multiply(gasPriceInt); - gasToUseInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); - gasToUseDeployInput.update(); + id: deployStep + visible: false + worker: worker } - } - Ether { - id: gasToUseInput - displayUnitSelection: false - displayFormattedValue: true - Layout.preferredWidth: 350 - } - - DefaultLabel - { - text: qsTr("Amount of gas to use for dapp registration: ") - id: ctrRegisterLabel - function calculateRegisterGas() + PackagingStep { - if (!modalDeploymentDialog.visible) - return; - appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/'); - NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost) - { - var ether = QEtherHelper.createBigInt(pathCreationCost); - var gasTotal = ether.multiply(gasPriceInt); - gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); - gasToUseDeployInput.update(); - }); + id: packageStep + visible: false + worker: worker } - } - - Ether { - id: gasToUseDeployInput - displayUnitSelection: false - displayFormattedValue: true - Layout.preferredWidth: 350 - } - DefaultLabel - { - text: qsTr("Ethereum Application URL: ") - } - - Rectangle - { - Layout.fillWidth: true - height: 25 - color: "transparent" - DefaultTextField + RegisteringStep { - width: 200 - id: applicationUrlEth - onTextChanged: { - ctrRegisterLabel.calculateRegisterGas(); - } - } - - DefaultLabel - { - id: appUrlFormatted - anchors.verticalCenter: parent.verticalCenter; - anchors.left: applicationUrlEth.right - font.italic: true - font.pointSize: appStyle.absoluteSize(-1) + id: registerStep + visible: false + worker: worker } } } - RowLayout - { - Layout.fillWidth: true - Rectangle - { - Layout.preferredWidth: 357 - color: "transparent" - } - - Button - { - id: deployButton - action: runAction - iconSource: "qrc:/qml/img/run.png" - } - - Action { - id: runAction - tooltip: qsTr("Deploy contract(s) and Package resources files.") - onTriggered: { - var inError = []; - var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); - for (var k in ethUrl) - { - if (ethUrl[k].length > 32) - inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); - } - if (!stopForInputError(inError)) - { - projectModel.deployedState = statesList.currentText; - if (contractRedeploy.checked) - deployWarningDialog.open(); - else - NetworkDeploymentCode.startDeployProject(false); - } - } - } - - CheckBox - { - anchors.left: deployButton.right - id: contractRedeploy - enabled: Object.keys(projectModel.deploymentAddresses).length > 0 - checked: Object.keys(projectModel.deploymentAddresses).length == 0 - text: qsTr("Deploy Contract(s)") - anchors.verticalCenter: parent.verticalCenter - } - } - Rectangle { - width: parent.width - height: 1 - color: "#5891d3" - } - - ColumnLayout - { - id: containerRegister Layout.fillWidth: true - Layout.preferredHeight: 500 - RowLayout - { - Layout.preferredHeight: 25 - Rectangle - { - Layout.preferredWidth: 356 - DefaultLabel - { - text: qsTr("Registration") - font.family: lightFont.name - font.underline: true - anchors.centerIn: parent - } - } - } - - GridLayout - { - columns: 2 - Layout.fillWidth: true - - DefaultLabel - { - Layout.preferredWidth: 355 - text: qsTr("Local package URL") - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: localPackageUrl - readOnly: true - } - - DefaultLabel - { - Layout.preferredWidth: 355 - text: qsTr("Web Application Resources URL: ") - } - - DefaultTextField - { - Layout.preferredWidth: 350 - id: applicationUrlHttp - enabled: rowRegister.isOkToRegister() - } - } - - RowLayout + Layout.preferredHeight: 30 + color: "transparent" + Button { - id: rowRegister - Layout.fillWidth: true - - Rectangle + text: qsTr("Cancel") + anchors.right: parent.right + anchors.rightMargin: 10 + onClicked: { - Layout.preferredWidth: 357 - color: "transparent" - } - - function isOkToRegister() - { - return Object.keys(projectModel.deploymentAddresses).length > 0 && deploymentDialog.packageHash !== ""; - } - - Button { - action: registerAction - iconSource: "qrc:/qml/img/note.png" - } - - BigIntValue - { - id: registerUrlHintGas - Component.onCompleted: - { - setValue(modalDeploymentDialog.urlHintSuggestUrlGas); - } - } - - Action { - id: registerAction - enabled: rowRegister.isOkToRegister() - tooltip: qsTr("Register hosted Web Application.") - onTriggered: { - if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") - deployDialog.open(); - return; - } - var inError = []; - if (applicationUrlHttp.text.length > 32) - inError.push(qsTr(applicationUrlHttp.text)); - if (!stopForInputError(inError)) - NetworkDeploymentCode.registerToUrlHint(); - } + modalDeploymentDialog.close() } } } + } } diff --git a/mix/qml/DeploymentDialogSteps.qml b/mix/qml/DeploymentDialogSteps.qml new file mode 100644 index 000000000..4ba4d0382 --- /dev/null +++ b/mix/qml/DeploymentDialogSteps.qml @@ -0,0 +1,133 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 + +Rectangle { + anchors.fill: parent + color: "white" + property variant sel + signal selected(string step) + + function init() + { + menu.itemAt(0).select() + } + + function itemClicked(step) + { + selected(step) + } + + border.color: "#cccccc" + border.width: 1 + + Column + { + anchors.fill: parent + anchors.margins: 1 + Repeater + { + id: menu + model: [ + { + step: 1, + type:"deploy", + label: qsTr("Deploy contracts") + }, + { + step: 2, + type:"package", + label: qsTr("Package files") + }, + { + step: 3, + type:"register", + label: qsTr("Register Dapp") + } + ] + + Rectangle + { + height: 50 + width: parent.width + color: "white" + id: itemContainer + + function select() + { + if (sel !== undefined) + { + menu.itemAt(sel).unselect() + } + labelContainer.state = "selected" + sel = index + itemClicked(menu.model[index].type) + } + + function unselect() + { + labelContainer.state = "" + } + + Rectangle { + width: 40 + height: 40 + color: "transparent" + border.color: "#cccccc" + border.width: 2 + radius: width*0.5 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + id: labelContainer + Label + { + color: "#cccccc" + id: label + anchors.centerIn: parent + text: menu.model[index].step + } + states: [ + State { + name: "selected" + PropertyChanges { target: label; color: "white" } + PropertyChanges { target: labelContainer.border; color: "white" } + PropertyChanges { target: detail; color: "white" } + PropertyChanges { target: itemContainer; color: "#3395FE" } + } + ] + } + + Rectangle + { + anchors.verticalCenter: parent.verticalCenter + anchors.left: label.parent.right + width: parent.width - 40 + height: 40 + color: "transparent" + Label + { + id: detail + color: "black" + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + text: menu.model[index].label + } + } + + MouseArea + { + anchors.fill: parent + onClicked: + { + itemContainer.select() + } + } + } + } + + } +} + diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml new file mode 100644 index 000000000..054d5a90c --- /dev/null +++ b/mix/qml/DeploymentWorker.qml @@ -0,0 +1,176 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import org.ethereum.qml.QEther 1.0 +import org.ethereum.qml.CodeModel 1.0 +import org.ethereum.qml.ClientModel 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import "." + +Item +{ + property string currentAccount + property string gasPrice + property alias gasPriceInt: gasPriceInt + property variant balances: ({}) + property variant accounts: [] + signal gasPriceLoaded() + + function renewCtx() + { + var requests = [{ + //accounts + jsonrpc: "2.0", + method: "eth_accounts", + params: null, + id: 0 + }]; + + TransactionHelper.rpcCall(requests, function(arg1, arg2) + { + accounts = [] + var ids = JSON.parse(arg2)[0].result; + requests = []; + for (var k in ids) + { + requests.push({ + //accounts + jsonrpc: "2.0", + method: "eth_getBalance", + params: [ids[k], 'latest'], + id: k + }); + accounts.push({ "id": ids[k] }) + } + + TransactionHelper.rpcCall(requests, function (request, response){ + var balanceRet = JSON.parse(response); + for (var k in balanceRet) + { + var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); + balances[accounts[k]] = ether + } + }, function(){}); + }, function(){}); + + NetworkDeploymentCode.gasPrice(function(price) { + gasPrice = price; + gasPriceInt.setValue(price); + console.log("fjdsfkjds hfkdsf " + price) + gasPriceLoaded() + }, function(){}); + } + + function stopForInputError(inError) + { + errorDialog.text = ""; + if (inError.length > 0) + { + errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n") + for (var k in inError) + errorDialog.text += inError[k] + "\n"; + errorDialog.open(); + return true; + } + return false; + } + + function waitForTrCountToIncrement(callBack) + { + poolLog.callBack = callBack; + poolLog.k = -1; + poolLog.elapsed = 0; + poolLog.start(); + } + + Component.onCompleted: + { + renewCtx() + } + + BigIntValue + { + id: gasPriceInt + } + + function estimateGas(scenario, callback) + { + if (!clientModelGasEstimation.running) + { + var ctr = projectModel.codeEditor.getContracts() + for (var k in ctr) + { + codeModelGasEstimation.registerCodeChange(ctr[k].document.documentId, ctr[k].getText()); + } + gasEstimationConnect.callback = callback + clientModelGasEstimation.setupScenario(scenario) + } + } + + Connections + { + id: gasEstimationConnect + target: clientModelGasEstimation + property var callback + onRunComplete: { + callback(clientModelGasEstimation.gasCosts) + } + } + + CodeModel { + id: codeModelGasEstimation + } + + ClientModel { + id: clientModelGasEstimation + codeModel: codeModelGasEstimation + Component.onCompleted: + { + init("/tmp/bcgas/") + } + } + + Timer + { + id: poolLog + property var callBack + property int k: -1 + property int elapsed + interval: 500 + running: false + repeat: true + onTriggered: { + elapsed += interval; + var requests = []; + var jsonRpcRequestId = 0; + requests.push({ + jsonrpc: "2.0", + method: "eth_getTransactionCount", + params: [ currentAccount, "pending" ], + id: jsonRpcRequestId++ + }); + TransactionHelper.rpcCall(requests, function (httpRequest, response){ + response = response.replace(/,0+/, ''); // ==> result:27,00000000 + var count = JSON.parse(response)[0].result + if (k < parseInt(count) && k > 0) + { + stop(); + callBack(1); + } + else if (elapsed > 25000) + { + stop(); + callBack(-1); + } + else + k = parseInt(JSON.parse(response)[0].result); + }) + } + } +} + diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml index 29323642a..593a54a3a 100644 --- a/mix/qml/Ether.qml +++ b/mix/qml/Ether.qml @@ -18,6 +18,8 @@ RowLayout { property bool displayUnitSelection onValueChanged: update() Component.onCompleted: update() + signal amountChanged + signal unitChanged function update() @@ -37,16 +39,17 @@ RowLayout { DefaultTextField { - implicitWidth: 200 onTextChanged: { if (value !== undefined) { value.setValue(text) formattedValue.text = value.format(); + amountChanged() } } readOnly: !edit + visible: edit id: etherValueEdit; } @@ -54,13 +57,13 @@ RowLayout { { id: units visible: displayUnitSelection; - implicitWidth: 145 onCurrentTextChanged: { if (value) { value.setUnit(currentText); formattedValue.text = value.format(); + unitChanged() } } diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml new file mode 100644 index 000000000..24453a24b --- /dev/null +++ b/mix/qml/PackagingStep.qml @@ -0,0 +1,192 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.1 +import Qt.labs.settings 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper + +Rectangle { + property variant paramsModel: [] + property variant worker + color: "#E3E3E3E3" + anchors.fill: parent + + property string packageHash + property string packageBase64 + property alias localPackageUrl: localPackageUrl.text + property string deploymentId + property string packageDir + + Settings { + property alias localUrl: localPackageUrl.text + } + + + function show() + { + visible = true + } + + FileDialog { + id: ressourcesFolder + visible: false + title: qsTr("Please choose a path") + selectFolder: true + property variant target + onAccepted: { + var u = ressourcesFolder.fileUrl.toString(); + if (u.indexOf("file://") == 0) + u = u.substring(7, u.length) + if (Qt.platform.os == "windows" && u.indexOf("/") == 0) + u = u.substring(1, u.length); + target.text = u; + } + } + + ColumnLayout + { + anchors.top: parent.top + anchors.topMargin: 10 + width: parent.width + + id: col + spacing: 20 + + Label + { + anchors.top: parent.top + Layout.fillWidth: true + anchors.left: parent.left + anchors.leftMargin: 10 + text: qsTr("Upload and update your Dapp assets") + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Save Package to") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: packageFolder + visible: true + Layout.preferredWidth: 150 + text: projectPath + "package/" + } + + Button + { + text: qsTr("select") + onClicked: { + ressourcesFolder.target = packageFolder + ressourcesFolder.open() + } + } + } + + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + color: "transparent" + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Generate Package") + onClicked: + { + NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses) + } + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Local package URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: localPackageUrl + Layout.preferredWidth: 235 + readOnly: true + } + } + + Label + { + Layout.preferredWidth: 300 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("You have to upload the package to a remote folder, or use a service like pastebin") + wrapMode: Text.WordWrap + clip: true + } + + Rectangle + { + color: "transparent" + Layout.fillWidth: true + Layout.preferredHeight: 20 + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Copy Base64") + onClicked: + { + clipboard.text = deploymentDialog.packageStep.packageBase64; + } + } + } + + Rectangle + { + color: "transparent" + Layout.fillWidth: true + Layout.preferredHeight: 20 + Button + { + Layout.preferredWidth: 200 + anchors.horizontalCenter: parent.horizontalCenter + text: qsTr("Open pastebin") + onClicked: + { + Qt.openUrlExternally("http://pastebin.com/"); + } + } + } + } +} + + + + + + + + + diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 0bf7c0fb2..9c9734289 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -40,7 +40,7 @@ Item { property string projectPath: "" property string projectTitle: "" property string currentDocumentId: "" - property var deploymentAddresses: [] + property var deploymentAddresses: ({}) property string deploymentDir property var listModel: projectListModel property var stateListModel: projectStateListModel.model @@ -48,7 +48,7 @@ Item { property CodeEditorView codeEditor: null property var unsavedFiles: [] property alias newProjectDialog: newProjectDialog - property string deployedState + property int deployedScenarioIndex //interface function saveAll() { ProjectModelCode.saveAll(); } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml new file mode 100644 index 000000000..79ea17d0d --- /dev/null +++ b/mix/qml/RegisteringStep.qml @@ -0,0 +1,230 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import org.ethereum.qml.QEther 1.0 +import Qt.labs.settings 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "js/NetworkDeployment.js" as NetworkDeploymentCode +import "js/QEtherHelper.js" as QEtherHelper +import "." + +Rectangle { + property variant worker + property alias applicationUrlEth: applicationUrlEth.text + property alias applicationUrlHttp: applicationUrlHttp.text + property string eth: registrarAddr.text + property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. + property int ownedRegistrarSetSubRegistrarGas: 50000 + property int ownedRegistrarSetContentHashGas: 50000 + property int urlHintSuggestUrlGas: 70000 + + color: "#E3E3E3E3" + anchors.fill: parent + + function show() + { + ctrRegisterLabel.calculateRegisterGas() + visible = true + } + + Settings + { + id: settings + property alias ethUrl: applicationUrlEth.text + property string httpUrl: applicationUrlHttp.text + } + + ColumnLayout + { + anchors.top: parent.top + width: parent.width + anchors.topMargin: 10 + id: col + spacing: 20 + Label + { + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: 10 + Layout.fillWidth: true + text: qsTr("Register your Dapp on the Name registrar Contract") + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Root Registrar address") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: registrarAddr + text: "bb9af5b8f19fb2bc1765ca36e697fa30e3386b71" //"c6d9d2cd449a754c494264e1809c50e34d64562b" + visible: true + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Web Application Resources URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + DefaultTextField + { + id: applicationUrlHttp + enabled: rowRegister.isOkToRegister() + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Gas to use for dapp registration") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + id: ctrRegisterLabel + function calculateRegisterGas() + { + if (!modalDeploymentDialog.visible) + return; + appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/'); + NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost) + { + var ether = QEtherHelper.createBigInt(pathCreationCost); + var gasTotal = ether.multiply(worker.gasPriceInt); + gasToUseDeployInput.value = QEtherHelper.createEther(gasTotal.value(), QEther.Wei, parent); + gasToUseDeployInput.update(); + }); + } + } + } + + Ether + { + id: gasToUseDeployInput + displayUnitSelection: true + displayFormattedValue: true + edit: true + Layout.preferredWidth: 235 + } + } + + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label + { + text: qsTr("Ethereum Application URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Rectangle + { + height: 25 + color: "transparent" + Layout.preferredWidth: 235 + DefaultTextField + { + width: 235 + id: applicationUrlEth + onTextChanged: { + ctrRegisterLabel.calculateRegisterGas(); + } + } + + DefaultLabel + { + id: appUrlFormatted + anchors.verticalCenter: parent.verticalCenter; + anchors.top: applicationUrlEth.bottom + anchors.topMargin: 10 + font.italic: true + font.pointSize: appStyle.absoluteSize(-1) + } + } + } + + + } + + RowLayout + { + anchors.bottom: parent.bottom + width: parent.width + anchors.bottomMargin: 8 + Button + { + anchors.right: parent.right + anchors.rightMargin: 10 + text: qsTr("Register Dapp") + width: 30 + onClicked: + { + var inError = []; + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); + for (var k in ethUrl) + { + if (ethUrl[k].length > 32) + inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + } + if (!worker.stopForInputError(inError)) + { + NetworkDeploymentCode.registerDapp(function(){ + applicationUrlEth.text = ethUrl + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") + deployDialog.open(); + return; + } + var inError = []; + if (applicationUrlHttp.text.length > 32) + inError.push(qsTr(applicationUrlHttp.text)); + if (!worker.stopForInputError(inError)) + { + /*registerToUrlHint(function(){ + settings.httpUrl = applicationUrlHttp.text + })*/ + } + }) + } + } + } + } +} + diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 4edc601de..9960afca7 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -125,9 +125,9 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[contractFromToken(contractCreationComboBox.currentValue())]; + var contract = codeModel.contracts[TransactionHelper.contractFromToken(contractCreationComboBox.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex + 1]; + var func = contract.contract.functions[functionComboBox.currentIndex /*+ 1*/]; if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) @@ -188,7 +188,7 @@ Dialog { if (!item.isContractCreation) { item.contractId = recipientsAccount.currentValue(); - item.label = contractFromToken(item.contractId) + "." + item.functionId + "()"; + item.label = TransactionHelper.contractFromToken(item.contractId) + "." + item.functionId + "()"; if (recipientsAccount.current().type === "address") { item.functionId = ""; @@ -205,14 +205,7 @@ Dialog { item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; - } - - function contractFromToken(token) - { - if (token.indexOf('<') === 0) - return token.replace("<", "").replace(">", "").split(" - ")[0]; - return token; - } + } function load(isContractCreation, isFunctionCall, functionId, contractId) { @@ -236,7 +229,7 @@ Dialog { { labelRecipient.text = qsTr("Recipient Contract") functionRect.show() - loadFunctions(contractFromToken(recipientsAccount.currentValue())) + loadFunctions(TransactionHelper.contractFromToken(recipientsAccount.currentValue())) loadParameters(); paramScroll.updateView() } @@ -416,7 +409,7 @@ Dialog { onIndexChanged: { if (rbbuttonList.current.objectName === "trTypeExecute") - loadFunctions(contractFromToken(currentValue())) + loadFunctions(TransactionHelper.contractFromToken(currentValue())) } } @@ -587,7 +580,7 @@ Dialog { target: functionComboBox onCurrentIndexChanged: { - estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + estimatedGas.displayGas(TransactionHelper.contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) } } @@ -604,7 +597,7 @@ Dialog { function updateView() { if (rbbuttonList.current.objectName === "trTypeExecute") - estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + estimatedGas.displayGas(TransactionHelper.contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) else if (rbbuttonList.current.objectName === "trTypeCreate") { var contractName = contractCreationComboBox.currentValue() diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 94d83460f..24be9eb3e 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -32,38 +32,30 @@ function deployProject(force) { deploymentDialog.open(); } -function startDeployProject(erasePrevious) -{ - var date = new Date(); - var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - if (!erasePrevious) - { - finalizeDeployment(deploymentId, projectModel.deploymentAddresses); - return; - } - +function deployContracts() +{ var jsonRpcUrl = "http://127.0.0.1:8080"; - console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); + console.log("Deploying to " + jsonRpcUrl); deploymentStarted(); var ctrAddresses = {}; - var state = retrieveState(projectModel.deployedState); - console.log(JSON.stringify(state)); + var state = retrieveState(projectModel.deployedScenarioIndex); if (!state) { - var txt = qsTr("Unable to find state " + projectModel.deployedState); + var txt = qsTr("Unable to find this scenario"); deploymentError(txt); console.log(txt); return; } - executeTr(0, state, ctrAddresses, function (){ - finalizeDeployment(deploymentId, ctrAddresses); + executeTr(0, 0, state, ctrAddresses, function(){ + projectModel.deploymentAddresses = ctrAddresses; + deploymentStepChanged(qsTr("Scenario deployed. Please wait for verifications")) }); } function checkPathCreationCost(callBack) { - var dappUrl = formatAppUrl(deploymentDialog.applicationUrlEth); + var dappUrl = formatAppUrl(deploymentDialog.registerStep.applicationUrlEth); checkEthPath(dappUrl, true, function(success, cause) { if (!success) { @@ -85,7 +77,7 @@ function checkPathCreationCost(callBack) else { deploymentStepChanged(qsTr("Your Dapp can be registered here.")); - callBack((dappUrl.length - 1) * (deploymentDialog.ownedRegistrarDeployGas + deploymentDialog.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.ownedRegistrarSetContentHashGas); + callBack((dappUrl.length - 1) * (deploymentDialog.registerStep.ownedRegistrarDeployGas + deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas) + deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); } }); } @@ -97,19 +89,13 @@ function gasUsed() for (var g in gasCosts) { gas += gasCosts[g]; - console.log(" gasCost " + gasCosts[g]); } return gas; } -function retrieveState(state) +function retrieveState(stateIndex) { - for (var k = 0; k < projectModel.stateListModel.count; k++) - { - if (projectModel.stateListModel.get(k).title === state) - return projectModel.stateListModel.get(k); - } - return null; + return projectModel.stateListModel.get(stateIndex); } function replaceParamToken(paramsDef, params, ctrAddresses) @@ -134,6 +120,7 @@ function replaceParamToken(paramsDef, params, ctrAddresses) function getFunction(ctrName, functionId) { + ctrName = contractFromToken(ctrName) if (codeModel.contracts[ctrName] === undefined) return null; if (ctrName === functionId) @@ -148,20 +135,21 @@ function getFunction(ctrName, functionId) } } -function executeTr(trIndex, state, ctrAddresses, callBack) +function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) { - var tr = state.transactions.get(trIndex); + var tr = state.blocks.get(blockIndex).transactions.get(trIndex); var func = getFunction(tr.contractId, tr.functionId); + console.log(func + " " + tr.contractId + " " + tr.functionId + " ") if (!func) - executeTrNextStep(trIndex, state, ctrAddresses, callBack); + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack); else { var gasCost = clientModel.toHex(clientModel.gasCosts[trIndex]); - var rpcParams = { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost }; + var rpcParams = { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost }; var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses); - var encodedParams = clientModel.encodeParams(params, tr.contractId, tr.functionId); + var encodedParams = clientModel.encodeParams(params, contractFromToken(tr.contractId), tr.functionId); - if (state.contractId === state.functionId) + if (tr.contractId === tr.functionId) rpcParams.code = codeModel.contracts[tr.contractId].codeHex + encodedParams.join(""); else rpcParams.data = func.hash + encodedParams.join(""); @@ -182,23 +170,34 @@ function executeTr(trIndex, state, ctrAddresses, callBack) ctrAddresses[tr.contractId] = JSON.parse(response)[0].result ctrAddresses[tr.contractId + " - " + trIndex] = JSON.parse(response)[0].result //get right ctr address if deploy more than one contract of same type. } - deploymentDialog.waitForTrCountToIncrement(function(status) { + deploymentDialog.worker.waitForTrCountToIncrement(function(status) { + console.log("deploy contract?" + status) if (status === -1) trCountIncrementTimeOut(); else - executeTrNextStep(trIndex, state, ctrAddresses, callBack) + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) }); }); } } -function executeTrNextStep(trIndex, state, ctrAddresses, callBack) +function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) { trIndex++; - if (trIndex < state.transactions.count) - executeTr(trIndex, state, ctrAddresses, callBack); + if (trIndex < state.blocks.get(blockIndex).transactions.count) + executeTr(blockIndex, trIndex, state, ctrAddresses, callBack); else - callBack(); + { + blockIndex++ + if (blockIndex < state.blocks.count) + { + executeTr(blockIndex, 0, state, ctrAddresses, callBack); + } + else + { + callBack(); + } + } } function gasPrice(callBack, error) @@ -216,7 +215,12 @@ function gasPrice(callBack, error) }); } -function finalizeDeployment(deploymentId, addresses) { +function packageDapp(addresses) +{ + var date = new Date(); + var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); + deploymentDialog.packageStep.deploymentId = deploymentId + deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; projectModel.deploymentDir = deploymentDir; @@ -259,21 +263,32 @@ function finalizeDeployment(deploymentId, addresses) { deploymentAddresses = addresses; saveProject(); - var packageRet = fileIo.makePackage(deploymentDir); - deploymentDialog.packageHash = packageRet[0]; - deploymentDialog.packageBase64 = packageRet[1]; - deploymentDialog.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + if (deploymentDialog.packageStep.packageDir !== "") + deploymentDir = deploymentDialog.packageStep.packageDir + else + { + deploymentDir = projectPath + "package/" + fileIo.makeDir(deploymentDir); + } - var applicationUrlEth = deploymentDialog.applicationUrlEth; + var packageRet = fileIo.makePackage(deploymentDir); + deploymentDialog.packageStep.packageHash = packageRet[0]; + deploymentDialog.packageStep.packageBase64 = packageRet[1]; + deploymentDialog.packageStep.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + deploymentComplete() +} +function registerDapp(callback) +{ + var applicationUrlEth = deploymentDialog.registerStep.applicationUrlEth; applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); checkEthPath(applicationUrlEth, false, function (success) { if (!success) return; deploymentComplete(); - deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment."); - deployResourcesDialog.open(); + if (callback) + callback() }); } @@ -283,8 +298,8 @@ function checkEthPath(dappUrl, checkOnly, callBack) { // convenient for dev purpose, should not be possible in normal env. if (!checkOnly) - reserve(deploymentDialog.eth, function() { - registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar. + reserve(deploymentDialog.registerStep.eth, function() { + registerContentHash(deploymentDialog.registerStep.eth, callBack); // we directly create a dapp under the root registrar. }); else callBack(true); @@ -298,7 +313,7 @@ function checkEthPath(dappUrl, checkOnly, callBack) //subRegistrar() jsonrpc: "2.0", method: "eth_call", - params: [ { "gas": "0xffff", "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0xe1fa8e84" + str }, "pending" ], + params: [ { "gas": "0xffff", "from": deploymentDialog.worker.currentAccount, "to": '0x' + deploymentDialog.registerStep.eth, "data": "0xe1fa8e84" + str }, "pending" ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -327,12 +342,12 @@ function isOwner(addr, callBack) //getOwner() jsonrpc: "2.0", method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0xb387ef92" }, "pending" ], + params: [ { "from": deploymentDialog.worker.currentAccount, "to": '0x' + addr, "data": "0xb387ef92" }, "pending" ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { var res = JSON.parse(response); - callBack(normalizeAddress(deploymentDialog.currentAccount) === normalizeAddress(res[0].result)); + callBack(normalizeAddress(deploymentDialog.worker.currentAccount) === normalizeAddress(res[0].result)); }); } @@ -374,7 +389,7 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) //register() jsonrpc: "2.0", method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x5a3a05bd" + str }, "pending" ], + params: [ { "from": deploymentDialog.worker.currentAccount, "to": '0x' + addr, "data": "0x5a3a05bd" + str }, "pending" ], id: jsonRpcRequestId++ }); @@ -406,11 +421,11 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) deploymentStepChanged(txt); //current registrar is owned => ownedregistrar creation and continue. requests = []; - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarDeployGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarDeployGas); requests.push({ jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "code": "0x600080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331781556105cd90819061003990396000f3007c010000000000000000000000000000000000000000000000000000000060003504630198489281146100b257806321f8a721146100e45780632dff6941146100ee5780633b3b57de1461010e5780635a3a05bd1461013e5780635fd4b08a146101715780637dd564111461017d57806389a69c0e14610187578063b387ef92146101bb578063b5c645bd146101f4578063be99a98014610270578063c3d014d6146102a8578063d93e7573146102dc57005b73ffffffffffffffffffffffffffffffffffffffff600435166000908152600160205260409020548060005260206000f35b6000808052602081f35b600435600090815260026020819052604090912001548060005260206000f35b600435600090815260026020908152604082205473ffffffffffffffffffffffffffffffffffffffff1680835291f35b600435600090815260026020908152604082206001015473ffffffffffffffffffffffffffffffffffffffff1680835291f35b60008060005260206000f35b6000808052602081f35b60005461030c9060043590602435903373ffffffffffffffffffffffffffffffffffffffff908116911614610569576105c9565b60005473ffffffffffffffffffffffffffffffffffffffff168073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b600435600090815260026020819052604090912080546001820154919092015473ffffffffffffffffffffffffffffffffffffffff9283169291909116908273ffffffffffffffffffffffffffffffffffffffff166000528173ffffffffffffffffffffffffffffffffffffffff166020528060405260606000f35b600054610312906004359060243590604435903373ffffffffffffffffffffffffffffffffffffffff90811691161461045457610523565b6000546103189060043590602435903373ffffffffffffffffffffffffffffffffffffffff90811691161461052857610565565b60005461031e90600435903373ffffffffffffffffffffffffffffffffffffffff90811691161461032457610451565b60006000f35b60006000f35b60006000f35b60006000f35b60008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091529020548114610361576103e1565b6000818152600260205260408082205473ffffffffffffffffffffffffffffffffffffffff169183917ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85459190a360008181526002602090815260408083205473ffffffffffffffffffffffffffffffffffffffff16835260019091528120555b600081815260026020819052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590910182905582917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b50565b600083815260026020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001683179055806104bb57827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc60006040a2610522565b73ffffffffffffffffffffffffffffffffffffffff8216837ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a854560006040a373ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208390555b5b505050565b600082815260026020819052604080832090910183905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b5050565b60008281526002602052604080822060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905583917fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc91a25b505056" } ], id: jsonRpcRequestId++ }); @@ -420,19 +435,19 @@ function continueRegistration(dappUrl, addr, callBack, checkOnly) var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); deploymentStepChanged(txt); console.log(txt); - deploymentDialog.waitForTrCountToIncrement(function(status) { + deploymentDialog.worker.waitForTrCountToIncrement(function(status) { if (status === -1) { trCountIncrementTimeOut(); return; } var crLevel = clientModel.encodeStringParam(dappUrl[0]); - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetSubRegistrarGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetSubRegistrarGas); requests.push({ //setRegister() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + deploymentDialog.pad(newCtrAddress) } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + addr, "data": "0x89a69c0e" + crLevel + newCtrAddress } ], id: jsonRpcRequestId++ }); @@ -465,7 +480,7 @@ function reserve(registrar, callBack) //reserve() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0xfffff", "to": '0x' + registrar, "data": "0x432ced04" + paramTitle } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -481,12 +496,12 @@ function registerContentHash(registrar, callBack) console.log(txt); var requests = []; var paramTitle = clientModel.encodeStringParam(projectModel.projectTitle); - var gasCost = clientModel.toHex(deploymentDialog.ownedRegistrarSetContentHashGas); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); requests.push({ //setContent() jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageHash } ], + params: [ { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "to": '0x' + registrar, "data": "0xc3d014d6" + paramTitle + deploymentDialog.packageStep.packageHash } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -494,24 +509,26 @@ function registerContentHash(registrar, callBack) }); } -function registerToUrlHint() +function registerToUrlHint(callback) { - deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); + deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.registerStep.applicationUrlHttp) + ") ..."); urlHintAddress(function(urlHint){ var requests = []; - var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.applicationUrlHttp); - var gasCost = clientModel.toHex(deploymentDialog.urlHintSuggestUrlGas); + var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.registerStep.applicationUrlHttp); + var gasCost = clientModel.toHex(deploymentDialog.registerStep.urlHintSuggestUrlGas); requests.push({ //urlHint => suggestUrl jsonrpc: "2.0", method: "eth_sendTransaction", - params: [ { "to": '0x' + urlHint, "from": deploymentDialog.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageHash + paramUrlHttp } ], + params: [ { "to": '0x' + urlHint, "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost, "data": "0x584e86ad" + deploymentDialog.packageStep.packageHash + paramUrlHttp } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { deploymentComplete(); + if (callback) + callback() }); }); } @@ -524,7 +541,7 @@ function urlHintAddress(callBack) //registrar: get UrlHint addr jsonrpc: "2.0", method: "eth_call", - params: [ { "to": '0x' + deploymentDialog.eth, "from": deploymentDialog.currentAccount, "data": "0x3b3b57de" + urlHint }, "pending" ], + params: [ { "to": '0x' + deploymentDialog.registerStep.eth, "from": deploymentDialog.worker.currentAccount, "data": "0x3b3b57de" + urlHint }, "pending" ], id: jsonRpcRequestId++ }); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index b3afabd3d..a3f6372e0 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -107,13 +107,13 @@ function loadProject(path) { if (projectData.deploymentDir) projectModel.deploymentDir = projectData.deploymentDir if (projectData.packageHash) - deploymentDialog.packageHash = projectData.packageHash + deploymentDialog.packageStep.packageHash = projectData.packageHash if (projectData.packageBase64) - deploymentDialog.packageBase64 = projectData.packageBase64 + deploymentDialog.packageStep.packageBase64 = projectData.packageBase64 if (projectData.applicationUrlEth) - deploymentDialog.applicationUrlEth = projectData.applicationUrlEth + deploymentDialog.registerStep.applicationUrlEth = projectData.applicationUrlEth if (projectData.applicationUrlHttp) - deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp + deploymentDialog.registerStep.applicationUrlHttp = projectData.applicationUrlHttp if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index ea91a40d7..33dadab9d 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -45,3 +45,10 @@ function rpcCall(requests, callBack, error) httpRequest.send(rpcRequest); } +function contractFromToken(token) +{ + if (token.indexOf('<') === 0) + return token.replace("<", "").replace(">", "").split(" - ")[0]; + return token; +} + From 631f12e6c4da96cc5f2379e638da68a24d75768e Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Jul 2015 15:26:51 +0200 Subject: [PATCH 03/13] deploy dialog UX changes --- mix/qml/DeployContractStep.qml | 76 +++++++++++++++++++++++++++++-- mix/qml/DeploymentDialog.qml | 2 +- mix/qml/DeploymentWorker.qml | 1 - mix/qml/PackagingStep.qml | 31 +++++++++---- mix/qml/RegisteringStep.qml | 80 +++++++++++++++++---------------- mix/qml/TransactionDialog.qml | 14 +++++- mix/qml/js/NetworkDeployment.js | 32 ++++++++----- mix/qml/js/ProjectModel.js | 15 ++++--- 8 files changed, 180 insertions(+), 71 deletions(-) diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 4d675a639..3f796d590 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 import QtQuick.Layouts 1.0 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.3 +import Qt.labs.settings 1.0 import "js/TransactionHelper.js" as TransactionHelper import "js/NetworkDeployment.js" as NetworkDeploymentCode import "js/QEtherHelper.js" as QEtherHelper @@ -10,10 +11,13 @@ import org.ethereum.qml.QEther 1.0 Rectangle { property variant paramsModel: [] property variant worker + property variant gas: [] color: "#E3E3E3E3" anchors.fill: parent id: root + property int labelWidth: 150 + function show() { visible = true @@ -26,6 +30,7 @@ Rectangle { } if (worker.accounts.length > 0) worker.currentAccount = worker.accounts[0].id + deployedAddresses.refresh() } RowLayout @@ -201,7 +206,7 @@ Rectangle { Layout.fillWidth: true Rectangle { - width: 100 + width: labelWidth Label { text: qsTr("Account") @@ -228,7 +233,7 @@ Rectangle { Layout.fillWidth: true Rectangle { - width: 100 + width: labelWidth Label { text: qsTr("Gas Price") @@ -289,6 +294,7 @@ Rectangle { worker.estimateGas(sce, function(gas) { if (gasPriceLoad.loaded) { + root.gas = gas cost = 0 for (var k in gas) { @@ -308,7 +314,7 @@ Rectangle { Rectangle { - width: 100 + width: labelWidth Label { text: qsTr("Cost Estimate") @@ -327,7 +333,66 @@ Rectangle { } } + RowLayout + { + id: deployedRow + Layout.fillWidth: true + Rectangle + { + width: labelWidth + Label + { + id: labelAddresses + text: qsTr("Deployed Addresses") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + ColumnLayout + { + + ListModel + { + id: deployedAddrModel + } + Repeater + { + id: deployedAddresses + model: deployedAddrModel + function refresh() + { + deployedAddrModel.clear() + deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0 + for (var k in projectModel.deploymentAddresses) + { + deployedAddrModel.append({ id: k, value: projectModel.deploymentAddresses[k]}) + } + } + + Rectangle + { + Layout.preferredHeight: 20 + Layout.preferredWidth: 235 + color: "transparent" + Label + { + id: labelContract + width: 110 + elide: Text.ElideRight + text: index > -1 ? deployedAddrModel.get(index).id : "" + } + + TextField + { + anchors.left: labelContract.right + text: index > - 1 ? deployedAddrModel.get(index).value : "" + } + } + } + } + } } Rectangle @@ -341,7 +406,10 @@ Rectangle { onClicked: { projectModel.deployedScenarioIndex = contractList.currentIndex - NetworkDeploymentCode.deployContracts(); + NetworkDeploymentCode.deployContracts(root.gas, function(addresses) + { + deployedAddresses.refresh() + }); } } } diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index ad946cd3e..f2fdc32a2 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -14,7 +14,7 @@ import "." Dialog { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 800 + width: 850 height: 450 visible: false diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 054d5a90c..ea6af5dab 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -61,7 +61,6 @@ Item NetworkDeploymentCode.gasPrice(function(price) { gasPrice = price; gasPriceInt.setValue(price); - console.log("fjdsfkjds hfkdsf " + price) gasPriceLoaded() }, function(){}); } diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml index 24453a24b..bd76b1d9e 100644 --- a/mix/qml/PackagingStep.qml +++ b/mix/qml/PackagingStep.qml @@ -13,18 +13,14 @@ Rectangle { property variant worker color: "#E3E3E3E3" anchors.fill: parent - + id: root property string packageHash property string packageBase64 property alias localPackageUrl: localPackageUrl.text + property alias lastDeployDate: lastDeployLabel.text property string deploymentId property string packageDir - Settings { - property alias localUrl: localPackageUrl.text - } - - function show() { visible = true @@ -100,16 +96,35 @@ Rectangle { Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 20 + Layout.preferredHeight: 40 color: "transparent" Button { + id: generatePackageBtn Layout.preferredWidth: 200 anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Generate Package") onClicked: { - NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses) + NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses); + } + } + + RowLayout + { + anchors.top: generatePackageBtn.bottom + anchors.topMargin: 10 + visible: root.lastDeployDate !== "" + anchors.horizontalCenter: parent.horizontalCenter + Label + { + id: lastPackage + text: qsTr("Last Package") + } + + Label + { + id: lastDeployLabel } } } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index 79ea17d0d..08dfa8c14 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -11,8 +11,8 @@ import "." Rectangle { property variant worker - property alias applicationUrlEth: applicationUrlEth.text - property alias applicationUrlHttp: applicationUrlHttp.text + property string applicationUrlEth + property string applicationUrlHttp property string eth: registrarAddr.text property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. property int ownedRegistrarSetSubRegistrarGas: 50000 @@ -25,16 +25,11 @@ Rectangle { function show() { ctrRegisterLabel.calculateRegisterGas() + applicationUrlEthCtrl.text = applicationUrlEth + applicationUrlHttp.text = applicationUrlHttp visible = true } - Settings - { - id: settings - property alias ethUrl: applicationUrlEth.text - property string httpUrl: applicationUrlHttp.text - } - ColumnLayout { anchors.top: parent.top @@ -69,7 +64,7 @@ Rectangle { DefaultTextField { id: registrarAddr - text: "bb9af5b8f19fb2bc1765ca36e697fa30e3386b71" //"c6d9d2cd449a754c494264e1809c50e34d64562b" + text: "31e316dace244c1efb93c565eb1974ff8efbdefe" //"c6d9d2cd449a754c494264e1809c50e34d64562b" visible: true Layout.preferredWidth: 235 } @@ -92,8 +87,7 @@ Rectangle { DefaultTextField { - id: applicationUrlHttp - enabled: rowRegister.isOkToRegister() + id: applicationUrlHttpCtrl Layout.preferredWidth: 235 } } @@ -160,7 +154,7 @@ Rectangle { DefaultTextField { width: 235 - id: applicationUrlEth + id: applicationUrlEthCtrl onTextChanged: { ctrRegisterLabel.calculateRegisterGas(); } @@ -194,34 +188,44 @@ Rectangle { width: 30 onClicked: { - var inError = []; - var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); - for (var k in ethUrl) + if (applicationUrlEthCtrl.text !== applicationUrlEth) { - if (ethUrl[k].length > 32) - inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + var inError = []; + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); + for (var k in ethUrl) + { + if (ethUrl[k].length > 32) + inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + } + if (!worker.stopForInputError(inError)) + { + NetworkDeploymentCode.registerDapp(function(){ + }) + } } - if (!worker.stopForInputError(inError)) + + + if (applicationUrlHttpCtrl.text !== applicationUrlHttp) { - NetworkDeploymentCode.registerDapp(function(){ - applicationUrlEth.text = ethUrl - if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") - deployDialog.open(); - return; - } - var inError = []; - if (applicationUrlHttp.text.length > 32) - inError.push(qsTr(applicationUrlHttp.text)); - if (!worker.stopForInputError(inError)) - { - /*registerToUrlHint(function(){ - settings.httpUrl = applicationUrlHttp.text - })*/ - } - }) + if (!(ethUrl.length === 1 && ethUrl[0] === projectModel.projectTitle)) + { + applicationUrlEth.text = ethUrl.join('/') + } + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") + deployDialog.open(); + return; + } + var inError = []; + if (applicationUrlHttp.text.length > 32) + inError.push(qsTr(applicationUrlHttp.text)); + if (!worker.stopForInputError(inError)) + { + registerToUrlHint(function(){ + }) + } } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 9960afca7..e47bd9ed2 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -127,7 +127,7 @@ Dialog { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { var contract = codeModel.contracts[TransactionHelper.contractFromToken(contractCreationComboBox.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex /*+ 1*/]; + var func = getFunction(functionComboBox.currentText, contract); if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) @@ -138,6 +138,18 @@ Dialog { initTypeLoader(); } + function getFunction(name, contract) + { + for (var k in contract.contract.functions) + { + if (contract.contract.functions[k].name === name) + { + return contract.contract.functions[k] + } + } + return null + } + function initTypeLoader() { paramScroll.value = {} diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 24be9eb3e..e159108bf 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -32,8 +32,9 @@ function deployProject(force) { deploymentDialog.open(); } -function deployContracts() +function deployContracts(gas, callback) { + deploymentGas = gas; var jsonRpcUrl = "http://127.0.0.1:8080"; console.log("Deploying to " + jsonRpcUrl); deploymentStarted(); @@ -50,6 +51,8 @@ function deployContracts() executeTr(0, 0, state, ctrAddresses, function(){ projectModel.deploymentAddresses = ctrAddresses; deploymentStepChanged(qsTr("Scenario deployed. Please wait for verifications")) + if (callback) + callback(ctrAddresses) }); } @@ -135,16 +138,18 @@ function getFunction(ctrName, functionId) } } +var deploymentGas +var trRealIndex = -1 function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) { + trRealIndex++; var tr = state.blocks.get(blockIndex).transactions.get(trIndex); var func = getFunction(tr.contractId, tr.functionId); - console.log(func + " " + tr.contractId + " " + tr.functionId + " ") if (!func) executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack); else { - var gasCost = clientModel.toHex(clientModel.gasCosts[trIndex]); + var gasCost = clientModel.toHex(deploymentGas[trRealIndex]); var rpcParams = { "from": deploymentDialog.worker.currentAccount, "gas": "0x" + gasCost }; var params = replaceParamToken(func.parameters, tr.parameters, ctrAddresses); var encodedParams = clientModel.encodeParams(params, contractFromToken(tr.contractId), tr.functionId); @@ -223,6 +228,15 @@ function packageDapp(addresses) deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; + + if (deploymentDialog.packageStep.packageDir !== "") + deploymentDir = deploymentDialog.packageStep.packageDir + else + { + deploymentDir = projectPath + "package/" + fileIo.makeDir(deploymentDir); + } + projectModel.deploymentDir = deploymentDir; fileIo.makeDir(deploymentDir); for (var i = 0; i < projectListModel.count; i++) { @@ -263,24 +277,18 @@ function packageDapp(addresses) deploymentAddresses = addresses; saveProject(); - if (deploymentDialog.packageStep.packageDir !== "") - deploymentDir = deploymentDialog.packageStep.packageDir - else - { - deploymentDir = projectPath + "package/" - fileIo.makeDir(deploymentDir); - } - var packageRet = fileIo.makePackage(deploymentDir); deploymentDialog.packageStep.packageHash = packageRet[0]; deploymentDialog.packageStep.packageBase64 = packageRet[1]; deploymentDialog.packageStep.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + deploymentDialog.packageStep.lastDeployDate = date deploymentComplete() } function registerDapp(callback) { var applicationUrlEth = deploymentDialog.registerStep.applicationUrlEth; + projectModel.deploymentEthUrl = applicationUrlEth applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); checkEthPath(applicationUrlEth, false, function (success) { @@ -512,7 +520,7 @@ function registerContentHash(registrar, callBack) function registerToUrlHint(callback) { deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.registerStep.applicationUrlHttp) + ") ..."); - + projectModel.deploymentHttpUrl = deploymentDialog.registerStep.applicationUrlHttp urlHintAddress(function(urlHint){ var requests = []; var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.registerStep.applicationUrlHttp); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index a3f6372e0..a203ef8fd 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -74,11 +74,12 @@ function saveProjectFile() files: [], title: projectTitle, deploymentAddresses: deploymentAddresses, - applicationUrlEth: deploymentDialog.applicationUrlEth, - applicationUrlHttp: deploymentDialog.applicationUrlHttp, - packageHash: deploymentDialog.packageHash, - packageBase64: deploymentDialog.packageBase64, - deploymentDir: projectModel.deploymentDir + applicationUrlEth: deploymentDialog.registerStep.applicationUrlEth, + applicationUrlHttp: deploymentDialog.registerStep.applicationUrlHttp, + packageHash: deploymentDialog.packageStep.packageHash, + packageBase64: deploymentDialog.packageStep.packageBase64, + deploymentDir: deploymentDialog.packageStep.packageDir, + lastPackageDate: deploymentDialog.packageStep.lastDeployDate }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push({ @@ -114,11 +115,13 @@ function loadProject(path) { deploymentDialog.registerStep.applicationUrlEth = projectData.applicationUrlEth if (projectData.applicationUrlHttp) deploymentDialog.registerStep.applicationUrlHttp = projectData.applicationUrlHttp + if (projectData.lastPackageDate) + deploymentDialog.packageStep.lastDeployDate = projectData.lastPackageDate if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; } - deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; + deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : {}; projectTitle = projectData.title; projectPath = path; if (!projectData.files) From ab635946efd5cde30102acd09ae4dcc2ae333856 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 15 Jul 2015 11:36:22 +0200 Subject: [PATCH 04/13] deploydialog ui changes (on register) --- mix/ClientModel.cpp | 20 +++++- mix/MixClient.cpp | 2 +- mix/QBigInt.h | 1 + mix/qml/DeployContractStep.qml | 2 +- mix/qml/DeploymentDialog.qml | 2 +- mix/qml/PackagingStep.qml | 1 - mix/qml/ProjectModel.qml | 4 +- mix/qml/RegisteringStep.qml | 109 +++++++++++++++++--------------- mix/qml/js/NetworkDeployment.js | 47 +++++++++----- mix/qml/js/ProjectModel.js | 8 +-- 10 files changed, 115 insertions(+), 81 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 7cc080d99..c6cc05722 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -447,7 +447,6 @@ void ClientModel::executeTr(QVariantMap _tr) } } - std::pair ClientModel::resolvePair(QString const& _contractId) { std::pair ret = std::make_pair(_contractId, 0); @@ -684,12 +683,27 @@ void ClientModel::debugRecord(unsigned _index) Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) { - return m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto); + eth::TransactionSkeleton ts; + ts.creation = true; + ts.value = _ctrTransaction.value; + ts.data = _code; + ts.gas = _ctrTransaction.gas; + ts.gasPrice = _ctrTransaction.gasPrice; + ts.from = toAddress(_ctrTransaction.sender); + return m_client->submitTransaction(ts, _ctrTransaction.sender, _ctrTransaction.gasAuto).second; } void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { - m_client->submitTransaction(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice, _tr.gasAuto); + eth::TransactionSkeleton ts; + ts.creation = false; + ts.value = _tr.value; + ts.to = _contract; + ts.data = _data; + ts.gas = _tr.gas; + ts.gasPrice = _tr.gasPrice; + ts.from = toAddress(_tr.sender); + m_client->submitTransaction(ts, _tr.sender, _tr.gasAuto); } RecordLogEntry* ClientModel::lastBlock() const diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 41c7e542d..72cc194ff 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -261,7 +261,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - eth::ExecutionResult er = _state.execute(lastHashes, _t); + eth::ExecutionResult er = _state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; diff --git a/mix/QBigInt.h b/mix/QBigInt.h index ccf487d2a..700c817e5 100644 --- a/mix/QBigInt.h +++ b/mix/QBigInt.h @@ -85,6 +85,7 @@ public: /// Set the value of the BigInteger used. Will use u256 type. Invokable from QML. Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); } Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); } + void setBigInt(u256 const& _value) { m_internalValue = _value; } /// Subtract by @a _value. Invokable from QML. Q_INVOKABLE QBigInt* subtract(QBigInt* const& _value) const; /// Add @a _value to the current big integer. Invokable from QML. diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 3f796d590..143b686ab 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -246,7 +246,7 @@ Rectangle { { id: gasPriceInput displayUnitSelection: true - displayFormattedValue: false + displayFormattedValue: true edit: true } diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index f2fdc32a2..0fde7c0fd 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -14,7 +14,7 @@ import "." Dialog { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 850 + width: 1000 height: 450 visible: false diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml index bd76b1d9e..ba3b16773 100644 --- a/mix/qml/PackagingStep.qml +++ b/mix/qml/PackagingStep.qml @@ -101,7 +101,6 @@ Rectangle { Button { id: generatePackageBtn - Layout.preferredWidth: 200 anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Generate Package") onClicked: diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 9c9734289..62173418e 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -49,6 +49,8 @@ Item { property var unsavedFiles: [] property alias newProjectDialog: newProjectDialog property int deployedScenarioIndex + property string applicationUrlEth + property string applicationUrlHttp //interface function saveAll() { ProjectModelCode.saveAll(); } @@ -72,7 +74,7 @@ Item { function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function deployProject() { NetworkDeploymentCode.deployProject(false); } - function registerToUrlHint() { NetworkDeploymentCode.registerToUrlHint(); } + function registerToUrlHint(url, callback) { NetworkDeploymentCode.registerToUrlHint(url, callback); } function formatAppUrl() { NetworkDeploymentCode.formatAppUrl(url); } Connections { diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index 08dfa8c14..db54839ad 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -11,8 +11,6 @@ import "." Rectangle { property variant worker - property string applicationUrlEth - property string applicationUrlHttp property string eth: registrarAddr.text property int ownedRegistrarDeployGas: 1179075 // TODO: Use sol library to calculate gas requirement for each tr. property int ownedRegistrarSetSubRegistrarGas: 50000 @@ -25,8 +23,8 @@ Rectangle { function show() { ctrRegisterLabel.calculateRegisterGas() - applicationUrlEthCtrl.text = applicationUrlEth - applicationUrlHttp.text = applicationUrlHttp + applicationUrlEthCtrl.text = projectModel.applicationUrlEth + applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp visible = true } @@ -68,7 +66,7 @@ Rectangle { visible: true Layout.preferredWidth: 235 } - } + } RowLayout { @@ -79,7 +77,7 @@ Rectangle { Layout.preferredWidth: col.width / 2 Label { - text: qsTr("Web Application Resources URL") + text: qsTr("Htpp URL") anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter } @@ -109,8 +107,8 @@ Rectangle { { if (!modalDeploymentDialog.visible) return; - appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text).join('/'); - NetworkDeploymentCode.checkPathCreationCost(function(pathCreationCost) + appUrlFormatted.text = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text).join('/'); + NetworkDeploymentCode.checkPathCreationCost(applicationUrlEthCtrl.text, function(pathCreationCost) { var ether = QEtherHelper.createBigInt(pathCreationCost); var gasTotal = ether.multiply(worker.gasPriceInt); @@ -140,7 +138,7 @@ Rectangle { Layout.preferredWidth: col.width / 2 Label { - text: qsTr("Ethereum Application URL") + text: qsTr("Ethereum URL") anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter } @@ -159,20 +157,34 @@ Rectangle { ctrRegisterLabel.calculateRegisterGas(); } } + } + } - DefaultLabel + RowLayout + { + Layout.fillWidth: true + Layout.preferredHeight: 20 + Rectangle + { + Layout.preferredWidth: col.width / 2 + Label { - id: appUrlFormatted - anchors.verticalCenter: parent.verticalCenter; - anchors.top: applicationUrlEth.bottom - anchors.topMargin: 10 - font.italic: true - font.pointSize: appStyle.absoluteSize(-1) + text: qsTr("Formatted Ethereum URL") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter } } - } - + DefaultLabel + { + id: appUrlFormatted + anchors.verticalCenter: parent.verticalCenter; + anchors.top: applicationUrlEthCtrl.bottom + anchors.topMargin: 10 + font.italic: true + font.pointSize: appStyle.absoluteSize(-1) + } + } } RowLayout @@ -188,44 +200,37 @@ Rectangle { width: 30 onClicked: { - if (applicationUrlEthCtrl.text !== applicationUrlEth) + var inError = []; + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text); + for (var k in ethUrl) { - var inError = []; - var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); - for (var k in ethUrl) - { - if (ethUrl[k].length > 32) - inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); - } - if (!worker.stopForInputError(inError)) - { - NetworkDeploymentCode.registerDapp(function(){ - }) - } + if (ethUrl[k].length > 32) + inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + } + if (!worker.stopForInputError(inError)) + { + NetworkDeploymentCode.registerDapp(ethUrl, function(){ + projectModel.applicationUrlEth = applicationUrlEthCtrl.text + projectModel.saveProject() + }) } - - if (applicationUrlHttpCtrl.text !== applicationUrlHttp) + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") { - if (!(ethUrl.length === 1 && ethUrl[0] === projectModel.projectTitle)) - { - applicationUrlEth.text = ethUrl.join('/') - } - if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") - deployDialog.open(); - return; - } - var inError = []; - if (applicationUrlHttp.text.length > 32) - inError.push(qsTr(applicationUrlHttp.text)); - if (!worker.stopForInputError(inError)) - { - registerToUrlHint(function(){ - }) - } + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") + deployDialog.open(); + return; + } + inError = []; + if (applicationUrlHttpCtrl.text.length > 32) + inError.push(qsTr(applicationUrlHttpCtrl.text)); + if (!worker.stopForInputError(inError)) + { + registerToUrlHint(applicationUrlHttpCtrl.text, function(){ + projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text + projectModel.saveProject() + }) } } } diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index e159108bf..6410b37e9 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -56,9 +56,9 @@ function deployContracts(gas, callback) }); } -function checkPathCreationCost(callBack) +function checkPathCreationCost(ethUrl, callBack) { - var dappUrl = formatAppUrl(deploymentDialog.registerStep.applicationUrlEth); + var dappUrl = formatAppUrl(ethUrl); checkEthPath(dappUrl, true, function(success, cause) { if (!success) { @@ -170,22 +170,37 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) var txt = qsTr(tr.contractId + "." + tr.functionId + "() ...") deploymentStepChanged(txt); console.log(txt); - if (tr.contractId === tr.functionId) - { - ctrAddresses[tr.contractId] = JSON.parse(response)[0].result - ctrAddresses[tr.contractId + " - " + trIndex] = JSON.parse(response)[0].result //get right ctr address if deploy more than one contract of same type. - } deploymentDialog.worker.waitForTrCountToIncrement(function(status) { - console.log("deploy contract?" + status) if (status === -1) trCountIncrementTimeOut(); else + { + if (tr.contractId === tr.functionId) + { + retrieveContractAddress(JSON.parse(response)[0].result, function(addr){ + ctrAddresses[tr.contractId + " - " + trIndex] = addr //get right ctr address if deploy more than one contract of same type. + }) + } executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) + } }); }); } } +function retrieveContractAddress(trHash, callback) +{ + var requests = [{ + jsonrpc: "2.0", + method: "eth_getTransactionReceipt", + params: [ trHash ], + id: jsonRpcRequestId + }]; + rpcCall(requests, function (httpCall, response){ + callback(JSON.parse(response)[0].contractAddress) + }) +} + function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) { trIndex++; @@ -285,13 +300,10 @@ function packageDapp(addresses) deploymentComplete() } -function registerDapp(callback) +function registerDapp(url, callback) { - var applicationUrlEth = deploymentDialog.registerStep.applicationUrlEth; - projectModel.deploymentEthUrl = applicationUrlEth - applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); - checkEthPath(applicationUrlEth, false, function (success) { + checkEthPath(url, false, function (success) { if (!success) return; deploymentComplete(); @@ -517,13 +529,12 @@ function registerContentHash(registrar, callBack) }); } -function registerToUrlHint(callback) +function registerToUrlHint(url, callback) { - deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.registerStep.applicationUrlHttp) + ") ..."); - projectModel.deploymentHttpUrl = deploymentDialog.registerStep.applicationUrlHttp + deploymentStepChanged(qsTr("Registering application Resources...")) urlHintAddress(function(urlHint){ var requests = []; - var paramUrlHttp = clientModel.encodeStringParam(deploymentDialog.registerStep.applicationUrlHttp); + var paramUrlHttp = clientModel.encodeStringParam(url) var gasCost = clientModel.toHex(deploymentDialog.registerStep.urlHintSuggestUrlGas); requests.push({ //urlHint => suggestUrl @@ -570,6 +581,8 @@ function normalizeAddress(addr) function formatAppUrl(url) { + if (!url) + return [projectModel.projectTitle]; if (url.toLowerCase().lastIndexOf("/") === url.length - 1) url = url.substring(0, url.length - 1); if (url.toLowerCase().indexOf("eth://") === 0) diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index a203ef8fd..f4959191e 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -74,8 +74,8 @@ function saveProjectFile() files: [], title: projectTitle, deploymentAddresses: deploymentAddresses, - applicationUrlEth: deploymentDialog.registerStep.applicationUrlEth, - applicationUrlHttp: deploymentDialog.registerStep.applicationUrlHttp, + applicationUrlEth: projectModel.applicationUrlEth, + applicationUrlHttp: projectModel.applicationUrlHttp, packageHash: deploymentDialog.packageStep.packageHash, packageBase64: deploymentDialog.packageStep.packageBase64, deploymentDir: deploymentDialog.packageStep.packageDir, @@ -112,9 +112,9 @@ function loadProject(path) { if (projectData.packageBase64) deploymentDialog.packageStep.packageBase64 = projectData.packageBase64 if (projectData.applicationUrlEth) - deploymentDialog.registerStep.applicationUrlEth = projectData.applicationUrlEth + projectModel.applicationUrlEth = projectData.applicationUrlEth if (projectData.applicationUrlHttp) - deploymentDialog.registerStep.applicationUrlHttp = projectData.applicationUrlHttp + projectModel.applicationUrlHttp = projectData.applicationUrlHttp if (projectData.lastPackageDate) deploymentDialog.packageStep.lastDeployDate = projectData.lastPackageDate if (!projectData.title) { From 5f69f8972570417de265fe76f3883ba5ccc90526 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 15 Jul 2015 15:22:33 +0200 Subject: [PATCH 05/13] deploydialog --- mix/FileIo.cpp | 7 ++++--- mix/qml/DeployContractStep.qml | 5 ++++- mix/qml/DeploymentWorker.qml | 26 ++++++++++++-------------- mix/qml/RegisteringStep.qml | 2 +- mix/qml/js/NetworkDeployment.js | 17 +++++++++-------- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 96a1ff446..328b111d5 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -72,8 +72,9 @@ QString FileIo::pathFromUrl(QString const& _url) void FileIo::makeDir(QString const& _url) { QDir dirPath(pathFromUrl(_url)); - if (!dirPath.exists()) - dirPath.mkpath(dirPath.path()); + if (dirPath.exists()) + dirPath.removeRecursively(); + dirPath.mkpath(dirPath.path()); } QString FileIo::readFile(QString const& _url) @@ -186,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) QUrl url(_deploymentFolder + "package.dapp"); QFile compressed(url.path()); QByteArray qFileBytes((char*)dapp.data(), static_cast(dapp.size())); - if (compressed.open(QIODevice::WriteOnly)) + if (compressed.open(QIODevice::WriteOnly | QIODevice::Truncate)) { compressed.write(qFileBytes); compressed.flush(); diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 143b686ab..0d93630bf 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -367,7 +367,8 @@ Rectangle { deployedRow.visible = Object.keys(projectModel.deploymentAddresses).length > 0 for (var k in projectModel.deploymentAddresses) { - deployedAddrModel.append({ id: k, value: projectModel.deploymentAddresses[k]}) + if (k.indexOf("-") !== -1) // this is an contract instance. ctr without - are the last deployed (to support old project) + deployedAddrModel.append({ id: k, value: projectModel.deploymentAddresses[k]}) } } @@ -408,6 +409,8 @@ Rectangle { projectModel.deployedScenarioIndex = contractList.currentIndex NetworkDeploymentCode.deployContracts(root.gas, function(addresses) { + projectModel.deploymentAddresses = addresses + projectModel.saveProject() deployedAddresses.refresh() }); } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index ea6af5dab..06c0e6f2e 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -79,10 +79,10 @@ Item return false; } - function waitForTrCountToIncrement(callBack) + function waitForTrReceipt(hash, callback) { - poolLog.callBack = callBack; - poolLog.k = -1; + poolLog.callBack = callback; + poolLog.hash = hash poolLog.elapsed = 0; poolLog.start(); } @@ -138,8 +138,8 @@ Item { id: poolLog property var callBack - property int k: -1 property int elapsed + property string hash interval: 500 running: false repeat: true @@ -149,25 +149,23 @@ Item var jsonRpcRequestId = 0; requests.push({ jsonrpc: "2.0", - method: "eth_getTransactionCount", - params: [ currentAccount, "pending" ], + method: "eth_getTransactionReceipt", + params: [ hash ], id: jsonRpcRequestId++ }); TransactionHelper.rpcCall(requests, function (httpRequest, response){ - response = response.replace(/,0+/, ''); // ==> result:27,00000000 - var count = JSON.parse(response)[0].result - if (k < parseInt(count) && k > 0) + console.log(response) + var receipt = JSON.parse(response)[0].result + if (receipt) { stop(); - callBack(1); + callBack(1, receipt); } - else if (elapsed > 25000) + else if (elapsed > 250000) { stop(); - callBack(-1); + callBack(-1, null); } - else - k = parseInt(JSON.parse(response)[0].result); }) } } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index db54839ad..34e627028 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -62,7 +62,7 @@ Rectangle { DefaultTextField { id: registrarAddr - text: "31e316dace244c1efb93c565eb1974ff8efbdefe" //"c6d9d2cd449a754c494264e1809c50e34d64562b" + text: "be5aac309199b4e0740ff52d4b28dc948cf44bea" //"c6d9d2cd449a754c494264e1809c50e34d64562b" visible: true Layout.preferredWidth: 235 } diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 6410b37e9..d194cd26c 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -144,6 +144,8 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) { trRealIndex++; var tr = state.blocks.get(blockIndex).transactions.get(trIndex); + if (!tr) + callBack() var func = getFunction(tr.contractId, tr.functionId); if (!func) executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack); @@ -170,20 +172,20 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) var txt = qsTr(tr.contractId + "." + tr.functionId + "() ...") deploymentStepChanged(txt); console.log(txt); - deploymentDialog.worker.waitForTrCountToIncrement(function(status) { + + deploymentDialog.worker.waitForTrReceipt(JSON.parse(response)[0].result, function(status, receipt){ if (status === -1) trCountIncrementTimeOut(); else { if (tr.contractId === tr.functionId) { - retrieveContractAddress(JSON.parse(response)[0].result, function(addr){ - ctrAddresses[tr.contractId + " - " + trIndex] = addr //get right ctr address if deploy more than one contract of same type. - }) + ctrAddresses[tr.contractId] = receipt.contractAddress + ctrAddresses[tr.contractId + " - " + trIndex] = receipt.contractAddress //get right ctr address if deploy more than one contract of same type. } executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) } - }); + }) }); } } @@ -247,10 +249,7 @@ function packageDapp(addresses) if (deploymentDialog.packageStep.packageDir !== "") deploymentDir = deploymentDialog.packageStep.packageDir else - { deploymentDir = projectPath + "package/" - fileIo.makeDir(deploymentDir); - } projectModel.deploymentDir = deploymentDir; fileIo.makeDir(deploymentDir); @@ -514,6 +513,7 @@ function registerContentHash(registrar, callBack) var txt = qsTr("Finalizing Dapp registration ..."); deploymentStepChanged(txt); console.log(txt); + console.log("register url " + deploymentDialog.packageStep.packageHash + " " + projectModel.projectTitle) var requests = []; var paramTitle = clientModel.encodeStringParam(projectModel.projectTitle); var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); @@ -531,6 +531,7 @@ function registerContentHash(registrar, callBack) function registerToUrlHint(url, callback) { + console.log("register url " + deploymentDialog.packageStep.packageHash + " " + url) deploymentStepChanged(qsTr("Registering application Resources...")) urlHintAddress(function(urlHint){ var requests = []; From f400140ce4ede6bee43400bc9bbce9fe897a060d Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 15 Jul 2015 15:24:26 +0200 Subject: [PATCH 06/13] rollback registrat addr --- mix/qml/RegisteringStep.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index 34e627028..e6399421e 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -62,7 +62,7 @@ Rectangle { DefaultTextField { id: registrarAddr - text: "be5aac309199b4e0740ff52d4b28dc948cf44bea" //"c6d9d2cd449a754c494264e1809c50e34d64562b" + text: "c6d9d2cd449a754c494264e1809c50e34d64562b" visible: true Layout.preferredWidth: 235 } From 6561e8c706c2569ef12a31bca12f3c121b1ecc59 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 15 Jul 2015 18:06:03 +0200 Subject: [PATCH 07/13] bug fix last package url block number for verification --- mix/qml/Application.qml | 1 - mix/qml/DeployContractStep.qml | 50 +++++++++++++++++++++++++++++++--- mix/qml/DeploymentWorker.qml | 17 +++++++++++- mix/qml/PackagingStep.qml | 1 + mix/qml/ProjectModel.qml | 1 + mix/qml/RegisteringStep.qml | 1 - mix/qml/ScenarioExecution.qml | 1 - mix/qml/ScenarioLoader.qml | 2 +- mix/qml/js/ProjectModel.js | 8 +++++- 9 files changed, 72 insertions(+), 10 deletions(-) diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index 8ee70942d..5ae12b816 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -44,7 +44,6 @@ ApplicationWindow { codeModel: codeModel Component.onCompleted: { - console.log("tmp") init("/tmp") } } diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 0d93630bf..ddb8529a4 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -30,6 +30,15 @@ Rectangle { } if (worker.accounts.length > 0) worker.currentAccount = worker.accounts[0].id + + if (projectModel.deployBlockNumber) + { + worker.blockNumber(function (bn) + { + verificationLabel.text = bn - projectModel.deployBlockNumber + }); + } + deployedAddresses.refresh() } @@ -58,7 +67,8 @@ Rectangle { textRole: "title" onCurrentIndexChanged: { - change() + if (root.visible) + change() } function change() @@ -188,6 +198,7 @@ Rectangle { Layout.preferredWidth: parent.width * 0.60 Layout.fillHeight: true id: deploymentOption + spacing: 8 Label { @@ -343,7 +354,7 @@ Rectangle { Label { id: labelAddresses - text: qsTr("Deployed Addresses") + text: qsTr("Deployed Contracts") anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter } @@ -351,7 +362,8 @@ Rectangle { ColumnLayout { - + anchors.top: parent.top + anchors.topMargin: 1 ListModel { id: deployedAddrModel @@ -380,13 +392,15 @@ Rectangle { Label { id: labelContract - width: 110 + width: 112 elide: Text.ElideRight text: index > -1 ? deployedAddrModel.get(index).id : "" } TextField { + width: 123 + anchors.verticalCenter: parent.verticalCenter anchors.left: labelContract.right text: index > - 1 ? deployedAddrModel.get(index).value : "" } @@ -394,6 +408,28 @@ Rectangle { } } } + + RowLayout + { + id: verificationRow + Layout.fillWidth: true + visible: Object.keys(projectModel.deploymentAddresses).length > 0 + Rectangle + { + width: labelWidth + Label + { + text: qsTr("Verifications") + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Label + { + id: verificationLabel + } + } } Rectangle @@ -409,6 +445,12 @@ Rectangle { projectModel.deployedScenarioIndex = contractList.currentIndex NetworkDeploymentCode.deployContracts(root.gas, function(addresses) { + worker.blockNumber(function (nb) + { + projectModel.deployBlockNumber = nb + verificationLabel.text = "0" + projectModel.saveProject() + }) projectModel.deploymentAddresses = addresses projectModel.saveProject() deployedAddresses.refresh() diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 06c0e6f2e..7493e4b23 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -87,6 +87,21 @@ Item poolLog.start(); } + function blockNumber(callback) + { + var requests = []; + requests.push({ + jsonrpc: "2.0", + method: "eth_blockNumber", + params: [], + id: 0 + }); + TransactionHelper.rpcCall(requests, function (httpRequest, response){ + var b = JSON.parse(response)[0].result; + callback(parseInt(b, 16)) + }); + } + Component.onCompleted: { renewCtx() @@ -168,6 +183,6 @@ Item } }) } - } + } } diff --git a/mix/qml/PackagingStep.qml b/mix/qml/PackagingStep.qml index ba3b16773..424732869 100644 --- a/mix/qml/PackagingStep.qml +++ b/mix/qml/PackagingStep.qml @@ -106,6 +106,7 @@ Rectangle { onClicked: { NetworkDeploymentCode.packageDapp(projectModel.deploymentAddresses); + projectModel.saveProject() } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 62173418e..96cf2f72a 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -51,6 +51,7 @@ Item { property int deployedScenarioIndex property string applicationUrlEth property string applicationUrlHttp + property string deployBlockNumber //interface function saveAll() { ProjectModelCode.saveAll(); } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index e6399421e..d8ebf3b34 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -179,7 +179,6 @@ Rectangle { { id: appUrlFormatted anchors.verticalCenter: parent.verticalCenter; - anchors.top: applicationUrlEthCtrl.bottom anchors.topMargin: 10 font.italic: true font.pointSize: appStyle.absoluteSize(-1) diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 687c8e99f..00c09f4cf 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -32,7 +32,6 @@ Rectangle { { id: columnExe Layout.preferredWidth: parent.width - width: parent.width - 40 anchors.left: parent.left anchors.leftMargin: 15 ColumnLayout diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index a54eb48bf..0de779135 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -154,7 +154,7 @@ ColumnLayout function updateLabel() { comboLabel.text = "" - if (scenarioList.currentIndex < projectModel.stateListModel.count) + if (scenarioList.currentIndex > - 1 && scenarioList.currentIndex < projectModel.stateListModel.count) comboLabel.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index f4959191e..2230fa290 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -79,7 +79,9 @@ function saveProjectFile() packageHash: deploymentDialog.packageStep.packageHash, packageBase64: deploymentDialog.packageStep.packageBase64, deploymentDir: deploymentDialog.packageStep.packageDir, - lastPackageDate: deploymentDialog.packageStep.lastDeployDate + lastPackageDate: deploymentDialog.packageStep.lastDeployDate, + deployBlockNumber: projectModel.deployBlockNumber, + localPackageUrl: deploymentDialog.packageStep.localPackageUrl }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push({ @@ -117,6 +119,10 @@ function loadProject(path) { projectModel.applicationUrlHttp = projectData.applicationUrlHttp if (projectData.lastPackageDate) deploymentDialog.packageStep.lastDeployDate = projectData.lastPackageDate + if (projectData.deployBlockNumber) + projectModel.deployBlockNumber = projectData.deployBlockNumber + if (projectData.localPackageUrl) + deploymentDialog.packageStep.localPackageUrl = projectData.localPackageUrl if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; From fe0608970554d3eb56400b761ed0ceb5060de31d Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 16 Jul 2015 11:41:21 +0200 Subject: [PATCH 08/13] more advanced verification system logs display account balance --- mix/qml/DeployContractStep.qml | 35 ++++++++++++++--- mix/qml/DeploymentDialogSteps.qml | 20 ++++++++++ mix/qml/DeploymentWorker.qml | 62 ++++++++++++++++++++++++++++--- mix/qml/ProjectModel.qml | 5 +++ mix/qml/RegisteringStep.qml | 61 ++++++++++++++++++++++++++++-- mix/qml/StatusPane.qml | 7 ---- mix/qml/js/NetworkDeployment.js | 25 ++++++++----- mix/qml/js/ProjectModel.js | 18 ++++++++- 8 files changed, 199 insertions(+), 34 deletions(-) diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index ddb8529a4..678132582 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -28,18 +28,32 @@ Rectangle { { accountsModel.append(worker.accounts[k]) } + if (worker.accounts.length > 0) worker.currentAccount = worker.accounts[0].id if (projectModel.deployBlockNumber) { - worker.blockNumber(function (bn) + worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost) { - verificationLabel.text = bn - projectModel.deployBlockNumber + root.updateVerification(bn, trLost) }); } - deployedAddresses.refresh() + worker.renewCtx() + } + + function updateVerification(blockNumber, trLost) + { + verificationLabel.text = blockNumber - projectModel.deployBlockNumber + if (trLost.length > 0) + { + verificationLabel.text += "\n" + qsTr("Transactions lost") + "\n" + for (var k in trLost) + { + verificationLabel.text += trLost[k] + "\n" + } + } } RowLayout @@ -235,8 +249,15 @@ Rectangle { onCurrentTextChanged: { worker.currentAccount = currentText + accountBalance.text = worker.balance(currentText).format() + console.log(worker.balance(currentText).format()) } } + + Label + { + id: accountBalance + } } RowLayout @@ -428,6 +449,7 @@ Rectangle { Label { id: verificationLabel + maximumLineCount: 20 } } } @@ -443,13 +465,14 @@ Rectangle { onClicked: { projectModel.deployedScenarioIndex = contractList.currentIndex - NetworkDeploymentCode.deployContracts(root.gas, function(addresses) + NetworkDeploymentCode.deployContracts(root.gas, function(addresses, trHashes) { - worker.blockNumber(function (nb) + projectModel.deploymentTrHashes = trHashes + worker.verifyHashes(trHashes, function (nb, trLost) { projectModel.deployBlockNumber = nb - verificationLabel.text = "0" projectModel.saveProject() + root.updateVerification(nb, trLost) }) projectModel.deploymentAddresses = addresses projectModel.saveProject() diff --git a/mix/qml/DeploymentDialogSteps.qml b/mix/qml/DeploymentDialogSteps.qml index 4ba4d0382..062bb5fd0 100644 --- a/mix/qml/DeploymentDialogSteps.qml +++ b/mix/qml/DeploymentDialogSteps.qml @@ -29,6 +29,7 @@ Rectangle { Repeater { id: menu + height: 150 model: [ { step: 1, @@ -128,6 +129,25 @@ Rectangle { } } + Connections { + target:projectModel + onDeploymentStarted: log.text = log.text + qsTr("Running deployment...") + "\n" + onDeploymentError: log.text = log.text + error + "\n" + onDeploymentComplete: log.text = log.text + qsTr("Deployment complete") + "\n" + onDeploymentStepChanged: log.text = log.text + message + "\n" + } + + ScrollView + { + width: parent.width + height: parent.height - menu.height + TextField + { + anchors.fill: parent + maximumLength: 100000 + id: log + } + } } } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 7493e4b23..c875a662a 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -23,6 +23,8 @@ Item function renewCtx() { + accounts = [] + balances = {} var requests = [{ //accounts jsonrpc: "2.0", @@ -33,7 +35,7 @@ Item TransactionHelper.rpcCall(requests, function(arg1, arg2) { - accounts = [] + var ids = JSON.parse(arg2)[0].result; requests = []; for (var k in ids) @@ -53,7 +55,9 @@ Item for (var k in balanceRet) { var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); - balances[accounts[k]] = ether + console.log(accounts[k].id) + console.log(ether.format()) + balances[accounts[k].id] = ether } }, function(){}); }, function(){}); @@ -65,6 +69,16 @@ Item }, function(){}); } + function balance(account) + { + for (var k in accounts) + { + if (accounts[k].id === account) + return balances[account] + } + return null + } + function stopForInputError(inError) { errorDialog.text = ""; @@ -87,18 +101,54 @@ Item poolLog.start(); } - function blockNumber(callback) + function verifyHash(tr, hash, callBack) { + var h = {} + h[tr] = hash + verifyHashes(h, function (bn, trLost) + { + callBack(bn, trLost) + }); + } + + function verifyHashes(trHashes, callback) + { + //trHashes : { "trLabel": 'hash' } var requests = []; + var req = 0 requests.push({ jsonrpc: "2.0", method: "eth_blockNumber", params: [], - id: 0 + id: req }); + var label = {} + for (var k in trHashes) + { + req++ + label[req] = k + requests.push({ + jsonrpc: "2.0", + method: "eth_getTransactionReceipt", + params: [trHashes[k]], + id: req + }); + } + TransactionHelper.rpcCall(requests, function (httpRequest, response){ - var b = JSON.parse(response)[0].result; - callback(parseInt(b, 16)) + console.log(response) + + var ret = JSON.parse(response) + var b = ret[0].result; + var trLost = [] + for (var k in ret) + { + if (ret[k].result === null) + { + trLost.push(label[ret[k].id]) + } + } + callback(parseInt(b, 16), trLost) }); } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 96cf2f72a..586bb1f17 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -52,6 +52,11 @@ Item { property string applicationUrlEth property string applicationUrlHttp property string deployBlockNumber + property string deploymentTrHashes + property string registerContentHashTrHash + property string registerUrlTrHash + property string registerContentHashBlockNumber + property string registerUrlBlockNumber //interface function saveAll() { ProjectModelCode.saveAll(); } diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index d8ebf3b34..9486d8a64 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -16,7 +16,7 @@ Rectangle { property int ownedRegistrarSetSubRegistrarGas: 50000 property int ownedRegistrarSetContentHashGas: 50000 property int urlHintSuggestUrlGas: 70000 - + id: root color: "#E3E3E3E3" anchors.fill: parent @@ -26,6 +26,35 @@ Rectangle { applicationUrlEthCtrl.text = projectModel.applicationUrlEth applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp visible = true + + if (projectModel.registerContentHashTrHash) + { + worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) + { + updateVerification(bn, trLost, verificationEthUrl) + }); + } + + if (projectModel.registerUrlTrHash) + { + worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) + { + updateVerification(bn, trLost, verificationUrl) + }); + } + } + + function updateVerification(originbn, trLost, ctrl) + { + if (trLost.length === 0) + { + ctrl.text = bn - originbn + ctrl.text += qsTr(" verifications") + } + else + { + ctrl.text = tr + qsTr(" invalidated") + } } ColumnLayout @@ -87,6 +116,13 @@ Rectangle { { id: applicationUrlHttpCtrl Layout.preferredWidth: 235 + + Label + { + id: verificationUrl + anchors.top: applicationUrlHttpCtrl.bottom + anchors.topMargin: 10 + } } } @@ -141,7 +177,7 @@ Rectangle { text: qsTr("Ethereum URL") anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - } + } } Rectangle @@ -183,14 +219,19 @@ Rectangle { font.italic: true font.pointSize: appStyle.absoluteSize(-1) } + + Label + { + id: verificationEthUrl + } } } RowLayout { anchors.bottom: parent.bottom - width: parent.width - anchors.bottomMargin: 8 + width: parent.width + Button { anchors.right: parent.right @@ -211,6 +252,12 @@ Rectangle { NetworkDeploymentCode.registerDapp(ethUrl, function(){ projectModel.applicationUrlEth = applicationUrlEthCtrl.text projectModel.saveProject() + worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) + { + projectModel.registerContentHashBlockNumber = bn + projectModel.saveProject() + root.updateVerification(bn, trLost, verificationEthUrl) + }); }) } @@ -229,6 +276,12 @@ Rectangle { registerToUrlHint(applicationUrlHttpCtrl.text, function(){ projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text projectModel.saveProject() + worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) + { + projectModel.registerUrlBlockNumber = bn + projectModel.saveProject() + root.updateVerification(bn, trLost, verificationUrl) + }); }) } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 1c1453002..a8750fc7c 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -110,13 +110,6 @@ Rectangle { } } - Connections { - target:projectModel - onDeploymentStarted: infoMessage(qsTr("Running deployment..."), "Deployment"); - onDeploymentError: errorMessage(error, "Deployment"); - onDeploymentComplete: infoMessage(qsTr("Deployment complete"), "Deployment"); - onDeploymentStepChanged: infoMessage(message, "Deployment"); - } Connections { target: codeModel onCompilationComplete: diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index d194cd26c..d9527c550 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -48,11 +48,12 @@ function deployContracts(gas, callback) console.log(txt); return; } - executeTr(0, 0, state, ctrAddresses, function(){ + var trHashes = {} + executeTr(0, 0, state, ctrAddresses, trHashes, function(){ projectModel.deploymentAddresses = ctrAddresses; deploymentStepChanged(qsTr("Scenario deployed. Please wait for verifications")) if (callback) - callback(ctrAddresses) + callback(ctrAddresses, trHashes) }); } @@ -140,7 +141,7 @@ function getFunction(ctrName, functionId) var deploymentGas var trRealIndex = -1 -function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) +function executeTr(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack) { trRealIndex++; var tr = state.blocks.get(blockIndex).transactions.get(trIndex); @@ -148,7 +149,7 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) callBack() var func = getFunction(tr.contractId, tr.functionId); if (!func) - executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack); + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack); else { var gasCost = clientModel.toHex(deploymentGas[trRealIndex]); @@ -172,8 +173,9 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) var txt = qsTr(tr.contractId + "." + tr.functionId + "() ...") deploymentStepChanged(txt); console.log(txt); - - deploymentDialog.worker.waitForTrReceipt(JSON.parse(response)[0].result, function(status, receipt){ + var hash = JSON.parse(response)[0].result + trHashes[tr.contractId + "." + tr.functionId + "()"] = hash + deploymentDialog.worker.waitForTrReceipt(hash, function(status, receipt){ if (status === -1) trCountIncrementTimeOut(); else @@ -183,7 +185,7 @@ function executeTr(blockIndex, trIndex, state, ctrAddresses, callBack) ctrAddresses[tr.contractId] = receipt.contractAddress ctrAddresses[tr.contractId + " - " + trIndex] = receipt.contractAddress //get right ctr address if deploy more than one contract of same type. } - executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) + executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack) } }) }); @@ -203,17 +205,17 @@ function retrieveContractAddress(trHash, callback) }) } -function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, callBack) +function executeTrNextStep(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack) { trIndex++; if (trIndex < state.blocks.get(blockIndex).transactions.count) - executeTr(blockIndex, trIndex, state, ctrAddresses, callBack); + executeTr(blockIndex, trIndex, state, ctrAddresses, trHashes, callBack); else { blockIndex++ if (blockIndex < state.blocks.count) { - executeTr(blockIndex, 0, state, ctrAddresses, callBack); + executeTr(blockIndex, 0, state, ctrAddresses, trHashes, callBack); } else { @@ -514,6 +516,7 @@ function registerContentHash(registrar, callBack) deploymentStepChanged(txt); console.log(txt); console.log("register url " + deploymentDialog.packageStep.packageHash + " " + projectModel.projectTitle) + projectModel.registerContentHashTrHash = "" var requests = []; var paramTitle = clientModel.encodeStringParam(projectModel.projectTitle); var gasCost = clientModel.toHex(deploymentDialog.registerStep.ownedRegistrarSetContentHashGas); @@ -525,6 +528,7 @@ function registerContentHash(registrar, callBack) id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { + projectModel.registerContentHashTrHash = JSON.parse(response)[0].result callBack(true); }); } @@ -546,6 +550,7 @@ function registerToUrlHint(url, callback) }); rpcCall(requests, function (httpRequest, response) { + projectModel.registerUrlTrHash = JSON.parse(response)[0].result deploymentComplete(); if (callback) callback() diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 2230fa290..a91237ec7 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -81,7 +81,12 @@ function saveProjectFile() deploymentDir: deploymentDialog.packageStep.packageDir, lastPackageDate: deploymentDialog.packageStep.lastDeployDate, deployBlockNumber: projectModel.deployBlockNumber, - localPackageUrl: deploymentDialog.packageStep.localPackageUrl + localPackageUrl: deploymentDialog.packageStep.localPackageUrl, + deploymentTrHashes: projectModel.deploymentTrHashes, + registerContentHashTrHash: projectModel.registerContentHashTrHash, + registerUrlTrHash: projectModel.registerUrlTrHash, + registerContentHashBlockNumber: projectModel.registerContentHashBlockNumber, + registerUrlBlockNumber: projectModel.registerUrlBlockNumber }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push({ @@ -123,6 +128,16 @@ function loadProject(path) { projectModel.deployBlockNumber = projectData.deployBlockNumber if (projectData.localPackageUrl) deploymentDialog.packageStep.localPackageUrl = projectData.localPackageUrl + if (projectData.deploymentTrHashes) + projectModel.deploymentTrHashes = projectData.deploymentTrHashes + if (projectData.registerUrlTrHash) + projectModel.registerUrlTrHash = projectData.registerUrlHash + if (projectData.registerContentHashTrHash) + projectModel.registerContentHashTrHash = projectData.registerContentHashTrHash + if (projectData.registerContentHashBlockNumber) + projectModel.registerContentHashBlockNumber = projectData.registerContentHashBlockNumber + if (projectData.registerUrlBlockNumber) + projectModel.registerUrlBlockNumber = projectData.registerUrlBlockNumber if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; @@ -369,3 +384,4 @@ function generateFileName(name, extension) { } while (fileIo.fileExists(filePath)); return fileName } + From 9f0a10b5182d4f7789c6f2ca1f84a3a6584a6866 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 16 Jul 2015 14:44:47 +0200 Subject: [PATCH 09/13] use tr hash for verification clear deploy action --- mix/FileIo.cpp | 7 ++ mix/FileIo.h | 2 + mix/qml/DeployContractStep.qml | 2 +- mix/qml/DeploymentDialogSteps.qml | 72 +++++++++++++++--- mix/qml/DeploymentWorker.qml | 6 +- mix/qml/ProjectModel.qml | 27 ++++++- mix/qml/RegisteringStep.qml | 119 +++++++++++++++++------------- mix/qml/js/ProjectModel.js | 6 +- 8 files changed, 168 insertions(+), 73 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 328b111d5..0a583f2a0 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -77,6 +77,13 @@ void FileIo::makeDir(QString const& _url) dirPath.mkpath(dirPath.path()); } +void FileIo::deleteDir(QString const& _url) +{ + QDir dirPath(pathFromUrl(_url)); + if (dirPath.exists()) + dirPath.removeRecursively(); +} + QString FileIo::readFile(QString const& _url) { QFile file(pathFromUrl(_url)); diff --git a/mix/FileIo.h b/mix/FileIo.h index 90a143120..eb5bc6cad 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -68,6 +68,8 @@ public: Q_INVOKABLE void stopWatching(QString const& _path); /// Delete a file Q_INVOKABLE void deleteFile(QString const& _path); + /// delete a directory + Q_INVOKABLE void deleteDir(QString const& _url); private: QString getHomePath() const; diff --git a/mix/qml/DeployContractStep.qml b/mix/qml/DeployContractStep.qml index 678132582..10f879ab7 100644 --- a/mix/qml/DeployContractStep.qml +++ b/mix/qml/DeployContractStep.qml @@ -32,7 +32,7 @@ Rectangle { if (worker.accounts.length > 0) worker.currentAccount = worker.accounts[0].id - if (projectModel.deployBlockNumber) + if (projectModel.deployBlockNumber !== -1) { worker.verifyHashes(projectModel.deploymentTrHashes, function (bn, trLost) { diff --git a/mix/qml/DeploymentDialogSteps.qml b/mix/qml/DeploymentDialogSteps.qml index 062bb5fd0..68abe2a46 100644 --- a/mix/qml/DeploymentDialogSteps.qml +++ b/mix/qml/DeploymentDialogSteps.qml @@ -9,6 +9,11 @@ Rectangle { property variant sel signal selected(string step) + function refreshCurrent() + { + menu.itemAt(sel).select() + } + function init() { menu.itemAt(0).select() @@ -22,14 +27,13 @@ Rectangle { border.color: "#cccccc" border.width: 1 - Column + ColumnLayout { anchors.fill: parent anchors.margins: 1 Repeater { id: menu - height: 150 model: [ { step: 1, @@ -50,8 +54,8 @@ Rectangle { Rectangle { - height: 50 - width: parent.width + Layout.preferredHeight: 50 + Layout.fillWidth: true color: "white" id: itemContainer @@ -130,21 +134,69 @@ Rectangle { } Connections { - target:projectModel + target: projectModel onDeploymentStarted: log.text = log.text + qsTr("Running deployment...") + "\n" onDeploymentError: log.text = log.text + error + "\n" onDeploymentComplete: log.text = log.text + qsTr("Deployment complete") + "\n" onDeploymentStepChanged: log.text = log.text + message + "\n" } + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: "#cccccc" + } + + RowLayout + { + anchors.horizontalCenter: parent.horizontalCenter + Layout.preferredHeight: 20 + anchors.left: parent.left + anchors.leftMargin: 2 + Button + { + Layout.preferredHeight: 22 + Layout.preferredWidth: 22 + action: clearAction + iconSource: "qrc:/qml/img/cleariconactive.png" + } + + Action { + id: clearAction + enabled: log.text !== "" + tooltip: qsTr("Clear") + onTriggered: { + log.text = "" + } + } + + Button + { + Layout.preferredHeight: 22 + text: qsTr("Clear Deployment") + action: clearDeployAction + } + + Action { + id: clearDeployAction + onTriggered: { + fileIo.deleteDir(projectModel.deploymentDir) + projectModel.cleanDeploymentStatus() + } + } + } + ScrollView { - width: parent.width - height: parent.height - menu.height - TextField + Layout.fillHeight: true + Layout.fillWidth: true + Text { - anchors.fill: parent - maximumLength: 100000 + anchors.left: parent.left + anchors.leftMargin: 2 + font.pointSize: 9 + font.italic: true id: log } } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index c875a662a..07b473822 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -55,8 +55,6 @@ Item for (var k in balanceRet) { var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei); - console.log(accounts[k].id) - console.log(ether.format()) balances[accounts[k].id] = ether } }, function(){}); @@ -144,9 +142,7 @@ Item for (var k in ret) { if (ret[k].result === null) - { - trLost.push(label[ret[k].id]) - } + trLost.push(label[ret[k]]) } callback(parseInt(b, 16), trLost) }); diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 586bb1f17..5ec833da6 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -52,11 +52,11 @@ Item { property string applicationUrlEth property string applicationUrlHttp property string deployBlockNumber - property string deploymentTrHashes + property var deploymentTrHashes property string registerContentHashTrHash property string registerUrlTrHash - property string registerContentHashBlockNumber - property string registerUrlBlockNumber + property int registerContentHashBlockNumber: -1 + property int registerUrlBlockNumber: -1 //interface function saveAll() { ProjectModelCode.saveAll(); } @@ -83,6 +83,27 @@ Item { function registerToUrlHint(url, callback) { NetworkDeploymentCode.registerToUrlHint(url, callback); } function formatAppUrl() { NetworkDeploymentCode.formatAppUrl(url); } + function cleanDeploymentStatus() + { + deployedScenarioIndex = 0 + applicationUrlEth = "" + applicationUrlHttp = "" + deployBlockNumber = "" + deploymentTrHashes = {} + registerContentHashTrHash = "" + registerUrlTrHash = "" + registerContentHashBlockNumber = -1 + registerUrlBlockNumber = -1 + deploymentAddresses = {} + deploymentDir = "" + deploymentDialog.packageStep.packageHash = "" + deploymentDialog.packageStep.packageBase64 = "" + deploymentDialog.packageStep.packageDir = "" + deploymentDialog.packageStep.lastDeployDate = "" + deploymentDialog.packageStep.localPackageUrl = "" + saveProject() + } + Connections { target: mainApplication onLoaded: { diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index 9486d8a64..caae97325 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -27,24 +27,24 @@ Rectangle { applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp visible = true - if (projectModel.registerContentHashTrHash) + if (projectModel.registerContentHashTrHash !== "") { worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) { - updateVerification(bn, trLost, verificationEthUrl) + updateVerification(projectModel.registerContentHashBlockNumber, bn, trLost, verificationEthUrl) }); } - if (projectModel.registerUrlTrHash) + if (projectModel.registerUrlTrHash !== "") { worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) { - updateVerification(bn, trLost, verificationUrl) + updateVerification(projectModel.registerUrlBlockNumber, bn, trLost, verificationUrl) }); } } - function updateVerification(originbn, trLost, ctrl) + function updateVerification(originbn, bn, trLost, ctrl) { if (trLost.length === 0) { @@ -53,7 +53,7 @@ Rectangle { } else { - ctrl.text = tr + qsTr(" invalidated") + ctrl.text = qsTr("invalidated") } } @@ -106,7 +106,7 @@ Rectangle { Layout.preferredWidth: col.width / 2 Label { - text: qsTr("Htpp URL") + text: qsTr("Http URL") anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter } @@ -116,13 +116,12 @@ Rectangle { { id: applicationUrlHttpCtrl Layout.preferredWidth: 235 + } - Label - { - id: verificationUrl - anchors.top: applicationUrlHttpCtrl.bottom - anchors.topMargin: 10 - } + Label + { + id: verificationUrl + anchors.verticalCenter: parent.verticalCenter } } @@ -230,60 +229,78 @@ Rectangle { RowLayout { anchors.bottom: parent.bottom + anchors.bottomMargin: 10 width: parent.width - Button + function registerHash(callback) { - anchors.right: parent.right - anchors.rightMargin: 10 - text: qsTr("Register Dapp") - width: 30 - onClicked: + var inError = []; + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text); + for (var k in ethUrl) { - var inError = []; - var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEthCtrl.text); - for (var k in ethUrl) - { - if (ethUrl[k].length > 32) - inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); - } - if (!worker.stopForInputError(inError)) - { - NetworkDeploymentCode.registerDapp(ethUrl, function(){ - projectModel.applicationUrlEth = applicationUrlEthCtrl.text - projectModel.saveProject() + if (ethUrl[k].length > 32) + inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n"); + } + if (!worker.stopForInputError(inError)) + { + NetworkDeploymentCode.registerDapp(ethUrl, function(){ + projectModel.applicationUrlEth = applicationUrlEthCtrl.text + projectModel.saveProject() + worker.waitForTrReceipt(projectModel.registerContentHashTrHash, function(status, receipt) + { worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) { projectModel.registerContentHashBlockNumber = bn projectModel.saveProject() - root.updateVerification(bn, trLost, verificationEthUrl) + root.updateVerification(bn, bn, trLost, verificationEthUrl) + callback() }); - }) - } + }); + }) + } + } - if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") - deployDialog.open(); - return; - } - inError = []; - if (applicationUrlHttpCtrl.text.length > 32) - inError.push(qsTr(applicationUrlHttpCtrl.text)); - if (!worker.stopForInputError(inError)) - { - registerToUrlHint(applicationUrlHttpCtrl.text, function(){ - projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text - projectModel.saveProject() + function registerUrl() + { + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.") + deployDialog.open(); + return; + } + var inError = []; + if (applicationUrlHttpCtrl.text.length > 32) + inError.push(qsTr(applicationUrlHttpCtrl.text)); + if (!worker.stopForInputError(inError)) + { + registerToUrlHint(applicationUrlHttpCtrl.text, function(){ + projectModel.applicationUrlHttp = applicationUrlHttpCtrl.text + projectModel.saveProject() + worker.waitForTrReceipt(projectModel.registerUrlTrHash, function(status, receipt) + { worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) { projectModel.registerUrlBlockNumber = bn projectModel.saveProject() - root.updateVerification(bn, trLost, verificationUrl) + root.updateVerification(bn, bn, trLost, verificationUrl) }); }) - } + }) + } + } + + Button + { + anchors.right: parent.right + anchors.rightMargin: 10 + text: qsTr("Register Dapp") + width: 30 + onClicked: + { + parent.registerHash(function(){ + parent.registerUrl() + }) } } } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index a91237ec7..c482ac427 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -82,7 +82,7 @@ function saveProjectFile() lastPackageDate: deploymentDialog.packageStep.lastDeployDate, deployBlockNumber: projectModel.deployBlockNumber, localPackageUrl: deploymentDialog.packageStep.localPackageUrl, - deploymentTrHashes: projectModel.deploymentTrHashes, + deploymentTrHashes: JSON.stringify(projectModel.deploymentTrHashes), registerContentHashTrHash: projectModel.registerContentHashTrHash, registerUrlTrHash: projectModel.registerUrlTrHash, registerContentHashBlockNumber: projectModel.registerContentHashBlockNumber, @@ -129,9 +129,9 @@ function loadProject(path) { if (projectData.localPackageUrl) deploymentDialog.packageStep.localPackageUrl = projectData.localPackageUrl if (projectData.deploymentTrHashes) - projectModel.deploymentTrHashes = projectData.deploymentTrHashes + projectModel.deploymentTrHashes = JSON.parse(projectData.deploymentTrHashes) if (projectData.registerUrlTrHash) - projectModel.registerUrlTrHash = projectData.registerUrlHash + projectModel.registerUrlTrHash = projectData.registerUrlTrHash if (projectData.registerContentHashTrHash) projectModel.registerContentHashTrHash = projectData.registerContentHashTrHash if (projectData.registerContentHashBlockNumber) From 4a9b7556d8210d40ea6319c837e2c04939b274af Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 16 Jul 2015 16:18:38 +0200 Subject: [PATCH 10/13] ui changes --- mix/qml/DeploymentDialog.qml | 1 + mix/qml/DeploymentDialogSteps.qml | 5 +++++ mix/qml/DeploymentWorker.qml | 5 +++++ mix/qml/RegisteringStep.qml | 2 ++ 4 files changed, 13 insertions(+) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 0fde7c0fd..39022def2 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -73,6 +73,7 @@ Dialog { DeploymentDialogSteps { id: steps + worker: worker } } diff --git a/mix/qml/DeploymentDialogSteps.qml b/mix/qml/DeploymentDialogSteps.qml index 68abe2a46..5ebd81dea 100644 --- a/mix/qml/DeploymentDialogSteps.qml +++ b/mix/qml/DeploymentDialogSteps.qml @@ -6,8 +6,10 @@ import QtQuick.Controls.Styles 1.3 Rectangle { anchors.fill: parent color: "white" + property var worker property variant sel signal selected(string step) + id: root function refreshCurrent() { @@ -181,8 +183,11 @@ Rectangle { Action { id: clearDeployAction onTriggered: { + worker.forceStopPooling() fileIo.deleteDir(projectModel.deploymentDir) projectModel.cleanDeploymentStatus() + root.refreshCurrent() + log.text = "" } } } diff --git a/mix/qml/DeploymentWorker.qml b/mix/qml/DeploymentWorker.qml index 07b473822..9aef45112 100644 --- a/mix/qml/DeploymentWorker.qml +++ b/mix/qml/DeploymentWorker.qml @@ -91,6 +91,11 @@ Item return false; } + function forceStopPooling() + { + poolLog.stop() + } + function waitForTrReceipt(hash, callback) { poolLog.callBack = callback; diff --git a/mix/qml/RegisteringStep.qml b/mix/qml/RegisteringStep.qml index caae97325..648e04f16 100644 --- a/mix/qml/RegisteringStep.qml +++ b/mix/qml/RegisteringStep.qml @@ -27,6 +27,7 @@ Rectangle { applicationUrlHttpCtrl.text = projectModel.applicationUrlHttp visible = true + verificationEthUrl.text = "" if (projectModel.registerContentHashTrHash !== "") { worker.verifyHash("registerHash", projectModel.registerContentHashTrHash, function(bn, trLost) @@ -35,6 +36,7 @@ Rectangle { }); } + verificationUrl.text = "" if (projectModel.registerUrlTrHash !== "") { worker.verifyHash("registerUrl", projectModel.registerUrlTrHash, function(bn, trLost) From cd61d7476dffea21f5953697f7dc64e246571cd8 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 16 Jul 2015 17:34:39 +0200 Subject: [PATCH 11/13] bug fix --- mix/qml/js/NetworkDeployment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index d9527c550..42cbf5207 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -287,7 +287,7 @@ function packageDapp(addresses) "\taddress: \"" + addresses[c] + "\"\n" + "};\n" + contractAccessor + ".contractClass = web3.eth.contract(" + contractAccessor + ".interface);\n" + - contractAccessor + ".contract = new " + contractAccessor + ".contractClass(" + contractAccessor + ".address);\n"; + contractAccessor + ".contract = " + contractAccessor + ".contractClass.at(" + contractAccessor + ".address);\n"; } fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); deploymentAddresses = addresses; From c72564d25c695490665b5080a6b49daad20a742c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 20 Jul 2015 00:36:48 +0200 Subject: [PATCH 12/13] fixing solidity tests --- libethcore/BlockInfo.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 266f57cc8..8e2e2c4c4 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -186,7 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) m_gasLimit = selectGasLimit(_parent); m_gasUsed = 0; m_difficulty = calculateDifficulty(_parent); - m_parentHash = _parent.hash(); + m_parentHash = _parent.m_hash; } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 4a6507cd6..d44545145 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp() == now && now > 0;\n" + " return block.timestamp == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index f4dbbcb97..0e8637012 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -41,7 +41,11 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } + ExecutionFramework() + { + g_logVerbosity = 0; + m_state.resetCurrent(); + } bytes const& compileAndRunWithoutCheck( std::string const& _sourceCode, From f6c9603a6ba94359b129c79839c19b4d515d3d98 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 20 Jul 2015 11:59:59 +0200 Subject: [PATCH 13/13] small changes --- mix/ClientModel.cpp | 2 +- mix/ClientModel.h | 2 +- mix/MixClient.cpp | 2 +- mix/MixClient.h | 2 +- mix/qml/BlockChain.qml | 3 +-- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index c6cc05722..7e4aefc67 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -302,7 +302,7 @@ void ClientModel::finalizeBlock() } } -TransactionSettings ClientModel::transaction(QVariant _tr) +TransactionSettings ClientModel::transaction(QVariant const& _tr) const { QVariantMap transaction = _tr.toMap(); QString contractId = transaction.value("contractId").toString(); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 4a367f9ba..bf88ad66a 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -270,7 +270,7 @@ private: void finalizeBlock(); void stopExecution(); void setupExecutionChain(); - TransactionSettings transaction(QVariant _tr); + TransactionSettings transaction(QVariant const& _tr) const; std::atomic m_running; std::atomic m_mining; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 72cc194ff..dd571d83d 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -123,7 +123,7 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre return ret; } -ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, LastHashes _lastHashes, bool _call) +ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, LastHashes const& _lastHashes, bool _call) { State execState = _state; execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation diff --git a/mix/MixClient.h b/mix/MixClient.h index 75f45efbf..715ab4d4e 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -61,7 +61,7 @@ public: virtual std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); } std::pair submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto); dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); - ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::LastHashes _lastHashes, bool _call); + ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::LastHashes const& _lastHashes, bool _call); void setAddress(Address _us) override; void startMining() override; void stopMining() override; diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index b6b5e3403..1b1b68862 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -330,10 +330,9 @@ ColumnLayout { for (var c in blinkReasons) { if (blinkReasons[c] === reason) - { return true - } } + return false }