From b10c5daad26be8bfb8d0aa17234a28d0ee13f88f Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Feb 2015 19:18:46 +0100 Subject: [PATCH 01/12] - Account Selection in DeploymentDialog.qml - Mime type in swarm.json - Use of ownedregistrar --- mix/FileIo.cpp | 11 +- mix/FileIo.h | 2 + mix/qml/DeploymentDialog.qml | 215 +++++++++++++++++++--- mix/qml/ProjectModel.qml | 18 +- mix/qml/js/ProjectModel.js | 315 +++++++++++++++++++------------- mix/qml/js/TransactionHelper.js | 25 +++ 6 files changed, 415 insertions(+), 171 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 506715767..cfc0b6a94 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -20,6 +20,9 @@ * Ethereum IDE client. */ +#include +#include +#include #include #include #include @@ -37,6 +40,11 @@ using namespace dev; using namespace dev::crypto; using namespace dev::mix; +void FileIo::openFileBrowser(QString _dir) +{ + QDesktopServices::openUrl(QUrl(_dir)); +} + void FileIo::makeDir(QString const& _url) { QUrl url(_url); @@ -123,6 +131,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) dev::RLPStream rlpStr; int k = 1; std::vector files; + QMimeDatabase mimeDb; for (auto item: deployDir.entryInfoList(QDir::Files)) { QFile qFile(item.filePath()); @@ -134,7 +143,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString(); jsonValue["path"] = path; //TODO: Manage relative sub folder jsonValue["file"] = "/" + fileInfo.fileName().toStdString(); - jsonValue["contentType"] = "text/html"; //TODO: manage multiple content type + jsonValue["contentType"] = mimeDb.mimeTypeForFile(qFile.fileName()).name().toStdString(); QByteArray a = qFile.readAll(); bytes data = bytes(a.begin(), a.end()); files.push_back(data); diff --git a/mix/FileIo.h b/mix/FileIo.h index 3646627b8..9c8f91b86 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -55,6 +55,8 @@ public: Q_INVOKABLE bool fileExists(QString const& _url); /// Compress a folder, @returns sha3 of the compressed file. Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); + /// Open a file browser + Q_INVOKABLE void openFileBrowser(QString _dir); private: QString getHomePath() const; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 5033d02b8..6aaf3b359 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -12,9 +12,10 @@ import "." Window { + id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 600 + width: 800 height: 350 visible: false property alias applicationUrlEth: applicationUrlEth.text @@ -22,8 +23,9 @@ Window { property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" property string packageHash property alias packageBase64: base64Value.text - property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4"; - property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d"; + property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; + property string yanndappRegistrar: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a"; + property string currentAccount color: Style.generic.layout.backgroundColor @@ -34,6 +36,23 @@ Window { function open() { + var requests = []; + requests.push({ + //accounts + jsonrpc: "2.0", + method: "eth_accounts", + params: null, + id: 0 + }); + + TransactionHelper.rpcCall(requests, function(arg1, arg2) + { + modelAccounts.clear(); + modelAccounts.append({ "id": JSON.parse(arg2)[0].result[0] }) + modelAccounts.append({ "id": JSON.parse(arg2)[0].result[1] }) + currentAccount = modelAccounts.get(0).id; + }); + modalDeploymentDialog.setX((Screen.width - width) / 2); modalDeploymentDialog.setY((Screen.height - height) / 2); visible = true; @@ -49,6 +68,46 @@ Window { return h; } + function waitForTrCountToIncrement(callBack) + { + poolLog.callBack = callBack; + poolLog.k = 0; + poolLog.start(); + } + + Timer + { + id: poolLog + property var callBack + property var k: -1 + interval: 500 + running: false + repeat: true + onTriggered: { + var requests = []; + var jsonRpcRequestId = 0; + requests.push({ + jsonrpc: "2.0", + method: "eth_countAt", + params: [ currentAccount ], + id: jsonRpcRequestId++ + }); + TransactionHelper.rpcCall(requests, function (httpRequest, response){ + console.log(response); + response = response.replace(/,0+/, ''); + console.log(response); + var count = JSON.parse(response)[0].result + if (k < parseInt(count) && k > 0) + { + stop(); + callBack(); + } + else + k = parseInt(JSON.parse(response)[0].result); + }) + } + } + Rectangle { anchors.fill : parent @@ -60,6 +119,22 @@ Window { anchors.top: parent.top anchors.left: parent.left width: parent.width + DefaultLabel + { + text: qsTr("Account used to deploy:") + } + + ComboBox { + id: comboAccounts + onCurrentIndexChanged : { + if (modelAccounts.count > 0) + currentAccount = modelAccounts.get(currentIndex).id; + } + model: ListModel { + id: modelAccounts + } + } + DefaultLabel { text: qsTr("Ethereum Application URL: ") @@ -95,6 +170,20 @@ Window { height: 60 enabled: base64Value.text != "" } + + DefaultLabel + { + text: qsTr("open package directory"); + visible: projectModel.deploymentDir !== "" + MouseArea + { + anchors.fill: parent; + onClicked: + { + fileIo.openFileBrowser(projectModel.deploymentDir); + } + } + } } MessageDialog { @@ -109,13 +198,22 @@ Window { anchors.right: parent.right; anchors.bottomMargin: 10 Button { - text: qsTr("Deploy to Ethereum"); + text: qsTr("Deploy contract / Package resources"); tooltip: qsTr("Deploy contract and package resources files.") onClicked: { deployWarningDialog.open(); } } + Button { + text: qsTr("Package resources only"); + tooltip: qsTr("Package resources files.") + enabled: Object.keys(projectModel.deploymentAddresses).length > 0 + onClicked: { + ProjectModelCode.startDeployProject(false); + } + } + Button { text: qsTr("Register Web Application"); tooltip: qsTr("Register hosted Web Application.") @@ -137,27 +235,42 @@ Window { } Button { - text: qsTr("Check Ownership"); + text: qsTr("Checking eth/yanndapp"); visible : false onClicked: { var requests = []; - var ethStr = QEtherHelper.createString("wallet"); - - var ethHash = QEtherHelper.createHash(eth); + var ethStr = QEtherHelper.createString("yanndapp"); requests.push({ //owner - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], - id: 3 - }); - - requests.push({ //register - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], - id: 4 - }); + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], //check for yanndappRegistrar in eth + id: 1 + }); + + requests.push({ //register + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], //getregister yanndappRegistrar in eth + id: 2 + }); + + + requests.push({ //getOwner + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.yanndappRegistrar, "data": "0x893d20e8" } ], //check owner of this registrar + id: 3 + }); + + /*requests.push({ //register + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.yanndappRegistrar, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], + id: 2 + });*/ + + var jsonRpcUrl = "http://localhost:8080"; var rpcRequest = JSON.stringify(requests); @@ -180,30 +293,76 @@ Window { } } + Button { + text: qsTr("add contracts"); + visible : false + onClicked: { + var jsonRpcRequestId = 0; + var requests = []; + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "gas": 20000, "code": "0x60056011565b600180601c6000396000f35b6008600081905550560000" } ], + id: jsonRpcRequestId++ + }); + + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + console.log(httpRequest.responseText); + var requests = []; + + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "gas": 20000, "code": "0x60056011565b600180601c6000396000f35b6009600081905550560000" } ], + id: jsonRpcRequestId++ + }); + rpcRequest = JSON.stringify(requests); + httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + console.log(httpRequest.responseText); + } + } + httpRequest.send(rpcRequest); + } + } + httpRequest.send(rpcRequest); + } + } + Button { - text: qsTr("Generate registrar init"); + text: qsTr("Registering eth/yanndapp"); visible: false onClicked: { - console.log("registering eth/wallet") + console.log("registering eth/yanndapp") var jsonRpcRequestId = 0; - var requests = []; - - var walletStr = QEtherHelper.createString("wallet"); + var ydapp = QEtherHelper.createString("yanndapp"); requests.push({ //reserve jsonrpc: "2.0", method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ], + params: [ { "gas": 2000, "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + ydapp.encodeValueAsString() } ], id: jsonRpcRequestId++ }); - requests.push({ //setRegister jsonrpc: "2.0", method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ], + params: [ { "gas": 2000, "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + ydapp.encodeValueAsString() + modalDeploymentDialog.pad(modalDeploymentDialog.yanndappRegistrar) } ], id: jsonRpcRequestId++ }); diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 19008be5e..86eab956a 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -7,6 +7,7 @@ import Qt.labs.settings 1.0 import "js/ProjectModel.js" as ProjectModelCode Item { + id: projectModel signal projectClosed @@ -33,6 +34,7 @@ Item { property string projectTitle: "" property string currentDocumentId: "" property var deploymentAddresses: [] + property string deploymentDir property var listModel: projectListModel property var stateListModel: projectStateListModel.model property CodeEditorView codeEditor: null @@ -93,28 +95,17 @@ Item { MessageDialog { id: deployWarningDialog - property bool redeploy title: qsTr("Project") text: { if (Object.keys(projectModel.deploymentAddresses).length > 0) - { - redeploy = true - standardButtons = StandardButton.Ok | StandardButton.Reset | StandardButton.Abort; - return qsTr("This project has been already deployed to the network. Do you want to repackage the resources only, or also reset the deployed contract to its initial state?") - } + return qsTr("This project has been already deployed to the network. Do you want to redeploy it? (Contract state will be reseted)") else - { - redeploy = false; - standardButtons = StandardButton.Ok | StandardButton.Abort; return qsTr("This action will deploy to the network. Do you want to deploy it?") - } } icon: StandardIcon.Question + standardButtons: StandardButton.Ok | StandardButton.Abort onAccepted: { - ProjectModelCode.startDeployProject(!redeploy); - } - onReset: { ProjectModelCode.startDeployProject(true); } } @@ -123,7 +114,6 @@ Item { id: deployRessourcesDialog title: qsTr("Project") standardButtons: StandardButton.Ok - icon: StandardIcon.Info } DeploymentDialog diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index d60dc4124..734e50698 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -20,6 +20,7 @@ * Ethereum IDE client. */ Qt.include("QEtherHelper.js") +Qt.include("TransactionHelper.js") var htmlTemplate = "\n\n\n\n\n\n\n"; var contractTemplate = "contract Contract {\n}\n"; @@ -50,7 +51,8 @@ function saveProject() { applicationUrlEth: deploymentDialog.applicationUrlEth, applicationUrlHttp: deploymentDialog.applicationUrlHttp, packageHash: deploymentDialog.packageHash, - packageBase64: deploymentDialog.packageBase64 + packageBase64: deploymentDialog.packageBase64, + deploymentDir: projectModel.deploymentDir }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push(projectListModel.get(i).fileName) @@ -68,6 +70,8 @@ function loadProject(path) { var projectFile = path + projectFileName; var json = fileIo.readFile(projectFile); var projectData = JSON.parse(json); + if (projectData.deploymentDir) + projectModel.deploymentDir = projectData.deploymentDir if (projectData.packageHash) deploymentDialog.packageHash = projectData.packageHash if (projectData.packageBase64) @@ -289,6 +293,7 @@ function deployProject(force) { deploymentDialog.open(); } +var codeTest = ""; function startDeployProject(erasePrevious) { var date = new Date(); @@ -309,12 +314,13 @@ function startDeployProject(erasePrevious) for (var c in codeModel.contracts) { //TODO: order based on dependencies var code = codeModel.contracts[c].codeHex; requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "code": code } ], - id: jsonRpcRequestId++ - }); + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": code /* "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" */ } ], + id: jsonRpcRequestId++ + }); requestNames.push(c); + codeTest = code; } var rpcRequest = JSON.stringify(requests); @@ -327,11 +333,18 @@ function startDeployProject(erasePrevious) if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { var rpcResponse = JSON.parse(httpRequest.responseText); + console.log("crea" + httpRequest.responseText); if (rpcResponse.length === requestNames.length) { var contractAddresses = {}; for (var r = 0; r < rpcResponse.length; r++) contractAddresses[requestNames[r]] = rpcResponse[r].result; - finalizeDeployment(deploymentId, contractAddresses); + + var txt = qsTr("Please wait while the contract is published ...") + deploymentStepChanged(txt); + console.log(txt); + deploymentDialog.waitForTrCountToIncrement(function() { + finalizeDeployment(deploymentId, contractAddresses); + }); } } else { var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; @@ -346,6 +359,7 @@ function startDeployProject(erasePrevious) function finalizeDeployment(deploymentId, addresses) { deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; + projectModel.deploymentDir = deploymentDir; fileIo.makeDir(deploymentDir); for (var i = 0; i < projectListModel.count; i++) { var doc = projectListModel.get(i); @@ -372,16 +386,16 @@ function finalizeDeployment(deploymentId, addresses) { } //write deployment js var deploymentJs = - "// Autogenerated by Mix\n" + - "web3 = require(\"web3\");\n" + - "contracts = {};\n"; + "// Autogenerated by Mix\n" + + "web3 = require(\"web3\");\n" + + "contracts = {};\n"; for (var c in codeModel.contracts) { var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; deploymentJs += contractAccessor + " = {\n" + - "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + - "\taddress: \"" + addresses[c] + "\"\n" + - "};\n" + - contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; + "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + + "\taddress: \"" + addresses[c] + "\"\n" + + "};\n" + + contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; } fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); //copy scripts @@ -398,135 +412,181 @@ function finalizeDeployment(deploymentId, addresses) { applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); - checkRegistration(applicationUrlEth, deploymentDialog.eth, function () { + applicationUrlEth.splice(0, 1); //Remove eth (already exists). + applicationUrlEth.push(projectModel.projectTitle); + checkEthPath(applicationUrlEth, function () { deploymentComplete(); deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); deployRessourcesDialog.open(); }); } -function rpcCall(requests, callBack) +function checkEthPath(dappUrl, callBack) { - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status !== 200) - { - var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; - console.log(errorText); - deploymentError(errorText); - return; - } - callBack(httpRequest.status, httpRequest.responseText) + var str = createString(dappUrl[0]); + var requests = []; + console.log(" ggg " + deploymentDialog.currentAccount); + console.log(" ggg " + deploymentDialog.eth); + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response) { + console.log("checking in path eth: found " + response); + var res = JSON.parse(response); + var addr = normalizeAddress(res[0].result); + if (addr === "") + { + var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting."); + deploymentError(errorTxt); + console.log(errorTxt); } - } - httpRequest.send(rpcRequest); + else + { + dappUrl.splice(0, 1); + checkRegistration(dappUrl, addr, callBack); + } + }); } function checkRegistration(dappUrl, addr, callBack) { + var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr); + deploymentStepChanged(txt); + console.log(txt); var requests = []; - var data = ""; - if (dappUrl.length > 0) - { - //checking path (register). - var str = createString(dappUrl[0]); - data = "0x6be16bed" + str.encodeValueAsString(); - console.log("checking if path exists (register) => " + JSON.stringify(dappUrl)); - requests.push({ - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + addr, "data": data } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function (httpRequest, response) { - var address = JSON.parse(response)[0].result.replace('0x', ''); - if (address === "") - { - var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + " cannot continue"); - deploymentError(errorTxt); - console.log(errorTxt); - return; - } - - dappUrl.splice(0, 1); - checkRegistration(dappUrl, address, callBack); - }); - } - else - { - var paramTitle = createString(projectModel.projectTitle); - requests.push({ - //owner() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + addr, "data": "0xec7b9200" + paramTitle.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); + var registrar = {} + var str = createString(dappUrl[0]); + requests.push({ + //getOwner() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], + id: jsonRpcRequestId++ + }); - requests.push({ - //accounts - jsonrpc: "2.0", - method: "eth_accounts", - params: null, - id: jsonRpcRequestId++ - }); + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); - rpcCall(requests, function (httpRequest, response) { + rpcCall(requests, function (httpRequest, response) { + console.log(" >> " +response); + var res = JSON.parse(response); + var nextAddr = normalizeAddress(res[1].result); + var errorTxt; + if (res[1].result === "0x") + { + errorTxt = qsTr("Error when creating new owned path. Please use the regsitration Dapp. Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result)) + { + errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (nextAddr !== "") + { + dappUrl.splice(0, 1); + if (dappUrl.length > 0) + checkRegistration(dappUrl, nextAddr, callBack); + else + registerContentHash(addr, callBack); + } + else + { + var txt = qsTr("Creating sub domain " + dappUrl[0] + " ..."); + console.log(txt); + deploymentStepChanged(txt); + //current registrar is owned => ownedregistrar creation and continue. requests = []; - var res = JSON.parse(response); - var currentOwner = res[0].result; - var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === ''; - - if (noOwner) - { - requests.push({ - //reserve() + + requests.push({ jsonrpc: "2.0", method: "eth_transact", - params: [ { "to": '0x' + addr, "data": "0x1c83171b" + paramTitle.encodeValueAsString() } ], + params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ], id: jsonRpcRequestId++ }); - } - else - { - var bOwner = false; - currentOwner = normalizeAddress(currentOwner); - for (var u in res[1].result) - { - if (normalizeAddress(res[1].result[u]) === currentOwner) - bOwner = true; - } - if (!bOwner) - { - var errorTxt = qsTr("Current user is not the owner of this path. Cannot continue") - deploymentError(errorTxt); - console.log(errorTxt); - return; - } - } - console.log("setContentHash"); - requests.push({ - //setContent() - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], - id: jsonRpcRequestId++ - }); - rpcCall(requests, function (httpRequest, response) { - callBack(); + rpcCall(requests, function(httpRequest, response) { + console.log("crea2" + response); + var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result); + requests = []; + console.log('new created addr ' + newCtrAddress); + + var txt = qsTr("Please wait while " + dappUrl[0] + " is creating ..."); + deploymentStepChanged(txt); + console.log(txt); + + deploymentDialog.waitForTrCountToIncrement(function() { + + var crLevel = createString(dappUrl[0]).encodeValueAsString(); + console.log("registering " + dappUrl[0]); + requests.push({ + //setRegister() + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function(){ + dappUrl.splice(0, 1); + if (dappUrl.length > 0) + checkRegistration(dappUrl, newCtrAddress, callBack); + else + registerContentHash(addr, callBack); + }); + }); }); - }); - } + } + }); +} + +var filterId; +function createFilter(callBack) +{ + var requests = []; + var jsonRpcRequestId = 0; + requests.push({ + jsonrpc: "2.0", + method: "eth_newFilterString", + params: [ "pending" ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response){ + console.log(response); + filterId = JSON.parse(response)[0].result; + callBack(filterId); + }) +} + +function registerContentHash(registrar, callBack) +{ + var txt = qsTr("Finalizing Dapp registration ..."); + deploymentStepChanged(txt); + console.log(txt); + var requests = []; + var paramTitle = createString(projectModel.projectTitle); + requests.push({ + //setContent() + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": "2000", "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response) { + callBack(); + }); } function registerToUrlHint() @@ -535,12 +595,12 @@ function registerToUrlHint() var requests = []; var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); requests.push({ - //urlHint => suggestUrl - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); + //urlHint => suggestUrl + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); rpcCall(requests, function (httpRequest, response) { deploymentComplete(); @@ -556,7 +616,7 @@ function normalizeAddress(addr) if (addr[k] !== "0") break; else - i++; + i++; } return addr.substring(i); } @@ -586,4 +646,3 @@ function formatAppUrl(url) return ret; } } - diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index 62399161e..b5a909354 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -10,3 +10,28 @@ function defaultTransaction() parameters: {} }; } + +function rpcCall(requests, callBack) +{ + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status !== 200) + { + var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; + console.log(errorText); + deploymentError(errorText); + return; + } + callBack(httpRequest.status, httpRequest.responseText) + } + } + httpRequest.send(rpcRequest); +} + From 42bd1dc6602325677bd45903193475964075fab2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Feb 2015 21:18:47 +0100 Subject: [PATCH 02/12] small changes --- mix/qml/js/ProjectModel.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 734e50698..05efa6d32 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -425,8 +425,6 @@ function checkEthPath(dappUrl, callBack) { var str = createString(dappUrl[0]); var requests = []; - console.log(" ggg " + deploymentDialog.currentAccount); - console.log(" ggg " + deploymentDialog.eth); requests.push({ //register() jsonrpc: "2.0", @@ -435,7 +433,6 @@ function checkEthPath(dappUrl, callBack) id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { - console.log("checking in path eth: found " + response); var res = JSON.parse(response); var addr = normalizeAddress(res[0].result); if (addr === "") @@ -478,7 +475,6 @@ function checkRegistration(dappUrl, addr, callBack) }); rpcCall(requests, function (httpRequest, response) { - console.log(" >> " +response); var res = JSON.parse(response); var nextAddr = normalizeAddress(res[1].result); var errorTxt; @@ -530,7 +526,6 @@ function checkRegistration(dappUrl, addr, callBack) deploymentDialog.waitForTrCountToIncrement(function() { var crLevel = createString(dappUrl[0]).encodeValueAsString(); - console.log("registering " + dappUrl[0]); requests.push({ //setRegister() jsonrpc: "2.0", @@ -613,7 +608,7 @@ function normalizeAddress(addr) var i = 0; for (var k in addr) { - if (addr[k] !== "0") + if (addr[k] !== "0" || addr.length === 40) break; else i++; From 22d322f40ef83917d49bc25ba6b83ed16e6de917 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Feb 2015 13:22:03 +0100 Subject: [PATCH 03/12] - Display balance. - Deploy contracts in a sync way. - Timeout for contract creation. --- mix/qml/DeploymentDialog.qml | 142 ++++++++++++++++++++++---------- mix/qml/StatusPane.qml | 11 ++- mix/qml/js/ProjectModel.js | 124 +++++++++++++--------------- mix/qml/js/TransactionHelper.js | 1 - 4 files changed, 166 insertions(+), 112 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 6aaf3b359..eddad1a68 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -15,7 +15,7 @@ Window { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 800 + width: 930 height: 350 visible: false property alias applicationUrlEth: applicationUrlEth.text @@ -26,6 +26,7 @@ Window { property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; property string yanndappRegistrar: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a"; property string currentAccount + property alias gasToUse: gasToUseInput.text color: Style.generic.layout.backgroundColor @@ -36,26 +37,48 @@ Window { function open() { - var requests = []; - requests.push({ - //accounts - jsonrpc: "2.0", - method: "eth_accounts", - params: null, - id: 0 - }); + modalDeploymentDialog.setX((Screen.width - width) / 2); + modalDeploymentDialog.setY((Screen.height - height) / 2); + visible = true; + + var requests = [{ + //accounts + jsonrpc: "2.0", + method: "eth_accounts", + params: null, + id: 0 + }]; TransactionHelper.rpcCall(requests, function(arg1, arg2) { modelAccounts.clear(); - modelAccounts.append({ "id": JSON.parse(arg2)[0].result[0] }) - modelAccounts.append({ "id": JSON.parse(arg2)[0].result[1] }) - currentAccount = modelAccounts.get(0).id; - }); + 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_balanceAt", + params: [ids[k]], + id: k + }); + } - modalDeploymentDialog.setX((Screen.width - width) / 2); - modalDeploymentDialog.setY((Screen.height - height) / 2); - visible = true; + 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()); + } + balance.text = comboAccounts.balances[0]; + }); + }); } function pad(h) @@ -71,7 +94,8 @@ Window { function waitForTrCountToIncrement(callBack) { poolLog.callBack = callBack; - poolLog.k = 0; + poolLog.k = -1; + poolLog.elapsed = 0; poolLog.start(); } @@ -79,11 +103,13 @@ Window { { id: poolLog property var callBack - property var k: -1 + property int k: -1 + property int elapsed interval: 500 running: false repeat: true onTriggered: { + elapsed += interval; var requests = []; var jsonRpcRequestId = 0; requests.push({ @@ -93,14 +119,17 @@ Window { id: jsonRpcRequestId++ }); TransactionHelper.rpcCall(requests, function (httpRequest, response){ - console.log(response); - response = response.replace(/,0+/, ''); - console.log(response); + response = response.replace(/,0+/, ''); // ==> result:27,00000000 var count = JSON.parse(response)[0].result if (k < parseInt(count) && k > 0) { stop(); - callBack(); + callBack(1); + } + else if (elapsed > 25000) + { + stop(); + callBack(-1); } else k = parseInt(JSON.parse(response)[0].result); @@ -124,17 +153,36 @@ Window { text: qsTr("Account used to deploy:") } - ComboBox { - id: comboAccounts - onCurrentIndexChanged : { - if (modelAccounts.count > 0) - currentAccount = modelAccounts.get(currentIndex).id; + Rectangle + { + width: 300 + height: 25 + color: "transparent" + ComboBox { + id: comboAccounts + property var balances: [] + onCurrentIndexChanged : { + if (modelAccounts.count > 0) + { + currentAccount = modelAccounts.get(currentIndex).id; + balance.text = balances[currentIndex]; + } + } + model: ListModel { + id: modelAccounts + } } - model: ListModel { - id: modelAccounts + + DefaultLabel + { + anchors.verticalCenter: parent.verticalCenter + anchors.left: comboAccounts.right + anchors.leftMargin: 20 + id: balance; } } + DefaultLabel { text: qsTr("Ethereum Application URL: ") @@ -157,6 +205,18 @@ Window { id: applicationUrlHttp } + DefaultLabel + { + text: qsTr("Amount of gas to use for each contract deployment: ") + } + + DefaultTextField + { + text: "20000" + Layout.fillWidth: true + id: gasToUseInput + } + DefaultLabel { text: qsTr("Package (Base64): ") @@ -170,20 +230,6 @@ Window { height: 60 enabled: base64Value.text != "" } - - DefaultLabel - { - text: qsTr("open package directory"); - visible: projectModel.deploymentDir !== "" - MouseArea - { - anchors.fill: parent; - onClicked: - { - fileIo.openFileBrowser(projectModel.deploymentDir); - } - } - } } MessageDialog { @@ -214,6 +260,14 @@ Window { } } + Button { + text: qsTr("Open Package Directory"); + enabled: projectModel.deploymentDir !== "" + onClicked: { + fileIo.openFileBrowser(projectModel.deploymentDir); + } + } + Button { text: qsTr("Register Web Application"); tooltip: qsTr("Register hosted Web Application.") @@ -297,7 +351,7 @@ Window { text: qsTr("add contracts"); visible : false onClicked: { - var jsonRpcRequestId = 0; + var jsonRpcRequestId = 0; var requests = []; requests.push({ jsonrpc: "2.0", diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 1f226279d..0980c31e4 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -35,17 +35,24 @@ Rectangle { logslink.visible = false; } + function errorMessage(text) + { + status.state = "error"; + status.text = text + logslink.visible = false; + } + Connections { target:clientModel onRunStarted: infoMessage(qsTr("Running transactions...")); - onRunFailed: infoMessage(qsTr("Error running transactions")); + onRunFailed: errorMessage(qsTr("Error running transactions")); onRunComplete: infoMessage(qsTr("Run complete")); onNewBlock: infoMessage(qsTr("New block created")); } Connections { target:projectModel onDeploymentStarted: infoMessage(qsTr("Running deployment...")); - onDeploymentError: infoMessage(error); + onDeploymentError: errorMessage(error); onDeploymentComplete: infoMessage(qsTr("Deployment complete")); onDeploymentStepChanged: infoMessage(message); } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 05efa6d32..d1f197d5d 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -293,7 +293,6 @@ function deployProject(force) { deploymentDialog.open(); } -var codeTest = ""; function startDeployProject(erasePrevious) { var date = new Date(); @@ -308,52 +307,54 @@ function startDeployProject(erasePrevious) console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); - var requests = []; - var requestNames = []; - - for (var c in codeModel.contracts) { //TODO: order based on dependencies - var code = codeModel.contracts[c].codeHex; - requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": code /* "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" */ } ], - id: jsonRpcRequestId++ - }); - requestNames.push(c); - codeTest = code; - } + var ctrNames = Object.keys(codeModel.contracts); + var ctrAddresses = {}; + deployContracts(0, ctrAddresses, ctrNames, function (){ + finalizeDeployment(deploymentId, ctrAddresses); + }); +} - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - var rpcResponse = JSON.parse(httpRequest.responseText); - console.log("crea" + httpRequest.responseText); - if (rpcResponse.length === requestNames.length) { - var contractAddresses = {}; - for (var r = 0; r < rpcResponse.length; r++) - contractAddresses[requestNames[r]] = rpcResponse[r].result; - - var txt = qsTr("Please wait while the contract is published ...") - deploymentStepChanged(txt); - console.log(txt); - deploymentDialog.waitForTrCountToIncrement(function() { - finalizeDeployment(deploymentId, contractAddresses); - }); - } - } else { - var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; - console.log(errorText); - deploymentError(errorText); +function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack) +{ + var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex; + var requests = [{ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ], + id: 0 + }]; + rpcCall(requests, function (httpCall, response){ + var txt = qsTr("Please wait while " + ctrNames[ctrIndex] + " is published ...") + deploymentStepChanged(txt); + console.log(txt); + ctrAddresses[ctrNames[ctrIndex]] = JSON.parse(response)[0].result + deploymentDialog.waitForTrCountToIncrement(function(status) { + if (status === -1) + { + trCountIncrementTimeOut(); + return; } - } - } - httpRequest.send(rpcRequest); + ctrIndex++; + if (ctrIndex < ctrNames.length) + deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack); + else + callBack(); + }); + }); +} + +function checkNewLog() +{ + var requests = []; + requests.push({ + jsonrpc: "2.0", + method: "eth_changed", + params: [0], + id: 0 + }); + rpcCall(requests, function (httpRequest, response) { + console.log("eth log: " + response); + }); } function finalizeDeployment(deploymentId, addresses) { @@ -480,7 +481,7 @@ function checkRegistration(dappUrl, addr, callBack) var errorTxt; if (res[1].result === "0x") { - errorTxt = qsTr("Error when creating new owned path. Please use the regsitration Dapp. Aborting"); + errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting"); deploymentError(errorTxt); console.log(errorTxt); } @@ -500,7 +501,7 @@ function checkRegistration(dappUrl, addr, callBack) } else { - var txt = qsTr("Creating sub domain " + dappUrl[0] + " ..."); + var txt = qsTr("Registering sub domain " + dappUrl[0] + " ..."); console.log(txt); deploymentStepChanged(txt); //current registrar is owned => ownedregistrar creation and continue. @@ -519,12 +520,16 @@ function checkRegistration(dappUrl, addr, callBack) requests = []; console.log('new created addr ' + newCtrAddress); - var txt = qsTr("Please wait while " + dappUrl[0] + " is creating ..."); + var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); deploymentStepChanged(txt); console.log(txt); - deploymentDialog.waitForTrCountToIncrement(function() { - + deploymentDialog.waitForTrCountToIncrement(function(status) { + if (status === -1) + { + trCountIncrementTimeOut(); + return; + } var crLevel = createString(dappUrl[0]).encodeValueAsString(); requests.push({ //setRegister() @@ -547,22 +552,11 @@ function checkRegistration(dappUrl, addr, callBack) }); } -var filterId; -function createFilter(callBack) +function trCountIncrementTimeOut() { - var requests = []; - var jsonRpcRequestId = 0; - requests.push({ - jsonrpc: "2.0", - method: "eth_newFilterString", - params: [ "pending" ], - id: jsonRpcRequestId++ - }); - rpcCall(requests, function (httpRequest, response){ - console.log(response); - filterId = JSON.parse(response)[0].result; - callBack(filterId); - }) + var error = qsTr("Something went wrong during the deployment. Please verify the amount of gas for this transaction and check your balance.") + console.log(error); + deploymentError(error); } function registerContentHash(registrar, callBack) diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index b5a909354..ca004e126 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -27,7 +27,6 @@ function rpcCall(requests, callBack) var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; console.log(errorText); deploymentError(errorText); - return; } callBack(httpRequest.status, httpRequest.responseText) } From fb8d5ae7250809eb33011e6d4745030c89f33fb1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Feb 2015 13:27:26 +0100 Subject: [PATCH 04/12] small changes --- mix/FileIo.cpp | 2 +- mix/FileIo.h | 2 +- mix/qml/js/ProjectModel.js | 14 -------------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index cfc0b6a94..204da5f15 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -40,7 +40,7 @@ using namespace dev; using namespace dev::crypto; using namespace dev::mix; -void FileIo::openFileBrowser(QString _dir) +void FileIo::openFileBrowser(QString const& _dir) { QDesktopServices::openUrl(QUrl(_dir)); } diff --git a/mix/FileIo.h b/mix/FileIo.h index 9c8f91b86..f91b32441 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -56,7 +56,7 @@ public: /// Compress a folder, @returns sha3 of the compressed file. Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); /// Open a file browser - Q_INVOKABLE void openFileBrowser(QString _dir); + Q_INVOKABLE void openFileBrowser(QString const& _dir); private: QString getHomePath() const; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index d1f197d5d..16670242c 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -343,20 +343,6 @@ function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack) }); } -function checkNewLog() -{ - var requests = []; - requests.push({ - jsonrpc: "2.0", - method: "eth_changed", - params: [0], - id: 0 - }); - rpcCall(requests, function (httpRequest, response) { - console.log("eth log: " + response); - }); -} - function finalizeDeployment(deploymentId, addresses) { deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; From e8b972a0942167d6b88e9e9ee99cab312406aacc Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Feb 2015 18:41:22 +0100 Subject: [PATCH 05/12] Add comments: warn about temporary code. --- mix/qml/DeploymentDialog.qml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index eddad1a68..65c63be8d 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -20,11 +20,11 @@ Window { visible: false property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlHttp: applicationUrlHttp.text - property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" + property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" /* TODO: replace with the good address */ property string packageHash property alias packageBase64: base64Value.text - property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; - property string yanndappRegistrar: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a"; + property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; /* TODO: replace with the good address */ + property string yanndappRegistrar: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a"; /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ property string currentAccount property alias gasToUse: gasToUseInput.text @@ -288,6 +288,7 @@ Window { onClicked: close(); } + /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ Button { text: qsTr("Checking eth/yanndapp"); visible : false @@ -347,6 +348,7 @@ Window { } } + /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ Button { text: qsTr("add contracts"); visible : false @@ -396,7 +398,7 @@ Window { } } - + /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ Button { text: qsTr("Registering eth/yanndapp"); visible: false From b07046e3f062aecfe212ea4836c3159505642b7b Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Feb 2015 19:02:26 +0100 Subject: [PATCH 06/12] small changes --- mix/qml/DeploymentDialog.qml | 156 ----------------------------------- mix/qml/ProjectModel.qml | 2 +- mix/qml/js/ProjectModel.js | 13 +-- 3 files changed, 5 insertions(+), 166 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 65c63be8d..b9a194220 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -24,7 +24,6 @@ Window { property string packageHash property alias packageBase64: base64Value.text property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; /* TODO: replace with the good address */ - property string yanndappRegistrar: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a"; /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ property string currentAccount property alias gasToUse: gasToUseInput.text @@ -287,161 +286,6 @@ Window { text: qsTr("Close"); onClicked: close(); } - - /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ - Button { - text: qsTr("Checking eth/yanndapp"); - visible : false - onClicked: { - var requests = []; - var ethStr = QEtherHelper.createString("yanndapp"); - - requests.push({ //owner - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], //check for yanndappRegistrar in eth - id: 1 - }); - - requests.push({ //register - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], //getregister yanndappRegistrar in eth - id: 2 - }); - - - requests.push({ //getOwner - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.yanndappRegistrar, "data": "0x893d20e8" } ], //check owner of this registrar - id: 3 - }); - - /*requests.push({ //register - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.yanndappRegistrar, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], - id: 2 - });*/ - - - - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - console.log(httpRequest.responseText); - } else { - var errorText = qsTr("path registration failed ") + httpRequest.status; - console.log(errorText); - } - } - } - httpRequest.send(rpcRequest); - } - } - - /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ - Button { - text: qsTr("add contracts"); - visible : false - onClicked: { - var jsonRpcRequestId = 0; - var requests = []; - requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "gas": 20000, "code": "0x60056011565b600180601c6000396000f35b6008600081905550560000" } ], - id: jsonRpcRequestId++ - }); - - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - console.log(httpRequest.responseText); - var requests = []; - - requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "gas": 20000, "code": "0x60056011565b600180601c6000396000f35b6009600081905550560000" } ], - id: jsonRpcRequestId++ - }); - rpcRequest = JSON.stringify(requests); - httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - console.log(httpRequest.responseText); - } - } - httpRequest.send(rpcRequest); - } - } - httpRequest.send(rpcRequest); - } - } - - /* TODO: Only fur testing purpose. To remove when registrar contract will be deployed in genesis block */ - Button { - text: qsTr("Registering eth/yanndapp"); - visible: false - onClicked: { - console.log("registering eth/yanndapp") - var jsonRpcRequestId = 0; - var requests = []; - var ydapp = QEtherHelper.createString("yanndapp"); - - requests.push({ //reserve - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "gas": 2000, "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + ydapp.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - requests.push({ //setRegister - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "gas": 2000, "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + ydapp.encodeValueAsString() + modalDeploymentDialog.pad(modalDeploymentDialog.yanndappRegistrar) } ], - id: jsonRpcRequestId++ - }); - - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - console.log(httpRequest.responseText); - } else { - var errorText = qsTr("path registration failed ") + httpRequest.status; - console.log(errorText); - } - } - } - httpRequest.send(rpcRequest); - } - } } } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 86eab956a..7e4e8cb49 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -99,7 +99,7 @@ Item { text: { if (Object.keys(projectModel.deploymentAddresses).length > 0) - return qsTr("This project has been already deployed to the network. Do you want to redeploy it? (Contract state will be reseted)") + return qsTr("This project has been already deployed to the network. Do you want to redeploy it? (Contract state will be reset)") else return qsTr("This action will deploy to the network. Do you want to deploy it?") } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 16670242c..55408c6d8 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -585,15 +585,10 @@ function registerToUrlHint() function normalizeAddress(addr) { addr = addr.replace('0x', ''); - var i = 0; - for (var k in addr) - { - if (addr[k] !== "0" || addr.length === 40) - break; - else - i++; - } - return addr.substring(i); + if (addr.length <= 40) + return addr; + var left = addr.length - 40; + return addr.substring(left); } function formatAppUrl(url) From 0aee93a3b39d2dacfedf8c01830977a60401cb3e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 27 Feb 2015 09:33:33 +0100 Subject: [PATCH 07/12] do need write memory to vm trace if greater than 1000 bytes --- libethereum/Executive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index f407a6f0b..86e2d5568 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -176,7 +176,7 @@ OnOpFunc Executive::simpleTrace() o << endl << " STACK" << endl; for (auto i: vm.stack()) o << (h256)i << endl; - o << " MEMORY" << endl << memDump(vm.memory()); + o << " MEMORY" << endl << (vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory()); o << " STORAGE" << endl; for (auto const& i: ext.state().storage(ext.myAddress)) o << showbase << hex << i.first << ": " << i.second << endl; From b476d9fe4d770038647fe5ad8f385fe430bf061e Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 27 Feb 2015 11:08:23 +0100 Subject: [PATCH 08/12] - Mine: change to 'new block' and display new line in list view. - bug fix : doesn't show number of line with error #1118 - Clicking on Compile error "log" link leads to debugger, not error #935 - Add background to make difference between section. - Improve StatusPane.qml UI - TransactionLog.qml: instead of record transactions, display filter. Show tr/Show call/display initial. - WebPreview.qml: Change combobox by a text box with url. --- mix/AppContext.cpp | 1 + mix/ClientModel.cpp | 14 +- mix/ClientModel.h | 6 +- mix/MixClient.cpp | 6 + mix/MixClient.h | 2 + mix/qml/Debugger.qml | 55 ++++-- mix/qml/FilesSection.qml | 348 +++++++++++++++++----------------- mix/qml/MainContent.qml | 6 + mix/qml/ProjectFilesStyle.qml | 2 +- mix/qml/ProjectList.qml | 20 +- mix/qml/StatusPane.qml | 123 ++++++++---- mix/qml/TransactionLog.qml | 44 +++-- mix/qml/WebPreview.qml | 60 +++--- mix/qml/main.qml | 13 +- 14 files changed, 414 insertions(+), 286 deletions(-) diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 64bc59ff8..29124a39a 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -73,6 +73,7 @@ void AppContext::load() qmlRegisterType("org.ethereum.qml.QHashType", 1, 0, "QHashType"); qmlRegisterType("org.ethereum.qml.QBoolType", 1, 0, "QBoolType"); qmlRegisterType("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration"); + qmlRegisterType("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry"); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QObject* projectModel = projectModelComponent.create(); if (projectModelComponent.isError()) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 45198c114..da07a4461 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -82,7 +82,7 @@ ClientModel::ClientModel(AppContext* _context): qRegisterMetaType("QInstruction"); qRegisterMetaType("QCode"); qRegisterMetaType("QCallData"); - qRegisterMetaType("RecordLogEntry"); + qRegisterMetaType("RecordLogEntry*"); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); @@ -349,6 +349,18 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); } +RecordLogEntry* ClientModel::lastBlock() const +{ + eth::BlockInfo blockInfo = m_client->blockInfo(); + std::stringstream strGas; + strGas << blockInfo.gasUsed; + std::stringstream strNumber; + strNumber << blockInfo.number; + RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), QString(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(blockInfo.hash.abridged())), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false); + QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); + return record; +} + void ClientModel::onStateReset() { m_contractAddresses.clear(); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index dda60cb10..96c34d3ed 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -123,11 +123,12 @@ public: Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) /// @returns deployed contracts addresses Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) + // @returns the last block + Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT) /// ethereum.js RPC request entry point /// @param _message RPC request in Json format /// @returns RPC response in Json format Q_INVOKABLE QString apiCall(QString const& _message); - /// Simulate mining. Creates a new block Q_INVOKABLE void mine(); @@ -177,6 +178,7 @@ signals: void stateCleared(); private: + RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; void executeSequence(std::vector const& _sequence, u256 _balance); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); @@ -199,3 +201,5 @@ private: } } + +Q_DECLARE_METATYPE(dev::mix::RecordLogEntry*) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index a78bc017d..9a89c1c25 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -436,6 +436,12 @@ h256 MixClient::hashFromNumber(unsigned _number) const eth::BlockInfo MixClient::blockInfo(h256 _hash) const { return BlockInfo(bc().block(_hash)); + +} + +eth::BlockInfo MixClient::blockInfo() const +{ + return BlockInfo(bc().block()); } eth::BlockDetails MixClient::blockDetails(h256 _hash) const diff --git a/mix/MixClient.h b/mix/MixClient.h index 2fe92a7ae..cd231cd43 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -89,6 +89,8 @@ public: eth::MineProgress miningProgress() const override; std::pair getWork() override { return std::pair(); } bool submitNonce(h256 const&) override { return false; } + /// @returns the last mined block information + eth::BlockInfo blockInfo() const; private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 52587dd4e..9c1257613 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -12,7 +12,7 @@ Rectangle { id: debugPanel property alias transactionLog : transactionLog - + property string compilationErrorMessage objectName: "debugPanel" color: "#ededed" clip: true @@ -23,25 +23,27 @@ Rectangle { forceActiveFocus(); } + function displayCompilationErrorIfAny() + { + debugScrollArea.visible = false; + compilationErrorArea.visible = true; + machineStates.visible = false; + var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false); + errorLocation.text = errorInfo.errorLocation; + errorDetail.text = errorInfo.errorDetail; + errorLine.text = errorInfo.errorLine; + } + function update(data, giveFocus) { - if (statusPane && codeModel.hasContract) + if (codeModel.hasContract) { - Debugger.init(data); + if (data !== null) + Debugger.init(data); debugScrollArea.visible = true; compilationErrorArea.visible = false; machineStates.visible = true; } - else - { - debugScrollArea.visible = false; - compilationErrorArea.visible = true; - machineStates.visible = false; - var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, false); - errorLocation.text = errorInfo.errorLocation; - errorDetail.text = errorInfo.errorDetail; - errorLine.text = errorInfo.errorLine; - } if (giveFocus) forceActiveFocus(); } @@ -55,7 +57,15 @@ Rectangle { Connections { target: codeModel - onCompilationComplete: update(null, false); + onCompilationComplete: + { + debugPanel.compilationErrorMessage = ""; + update(null, false); + } + + onCompilationError: { + debugPanel.compilationErrorMessage = _error; + } } Settings { @@ -73,7 +83,7 @@ Rectangle { visible: false; id: compilationErrorArea width: parent.width - 20 - height: 500 + height: 600 color: "#ededed" anchors.left: parent.left anchors.top: parent.top @@ -82,7 +92,20 @@ Rectangle { { width: parent.width anchors.top: parent.top - spacing: 25 + spacing: 15 + Rectangle + { + height: 15 + Button { + text: qsTr("Back to Debugger") + onClicked: { + debugScrollArea.visible = true; + compilationErrorArea.visible = false; + machineStates.visible = true; + } + } + } + RowLayout { height: 100 diff --git a/mix/qml/FilesSection.qml b/mix/qml/FilesSection.qml index 518e85595..cc5a67741 100644 --- a/mix/qml/FilesSection.qml +++ b/mix/qml/FilesSection.qml @@ -6,17 +6,19 @@ import QtQuick.Controls.Styles 1.3 import "." -ColumnLayout { +Rectangle +{ + Layout.fillWidth: true + Layout.minimumHeight: hiddenHeightTopLevel() + height: hiddenHeightTopLevel() + Layout.maximumHeight: hiddenHeightTopLevel() id: wrapperItem signal documentSelected(string doc, string groupName) property alias model: filesList.model property string sectionName; property variant selManager; - Layout.fillWidth: true - Layout.minimumHeight: hiddenHeightTopLevel() - height: hiddenHeightTopLevel() - Layout.maximumHeight: hiddenHeightTopLevel() - spacing: 0 + property int index; + color: index % 2 === 0 ? "transparent" : ProjectFilesStyle.title.background function hiddenHeightTopLevel() { @@ -48,196 +50,203 @@ ColumnLayout { model.remove(i); } - SourceSansProRegular - { - id: fileNameFont - } - - SourceSansProBold - { - id: boldFont - } + ColumnLayout { + anchors.fill: parent + spacing: 0 - RowLayout - { - anchors.top: parent.top - id: rowCol - width: parent.width - height: ProjectFilesStyle.documentsList.height - - Image { - source: "qrc:/qml/img/opentriangleindicator_filesproject.png" - width: 15 - sourceSize.width: 12 - id: imgArrow - anchors.right: section.left - anchors.rightMargin: 8 - anchors.top: parent.top - anchors.topMargin: 6 + SourceSansProRegular + { + id: fileNameFont } - Text + SourceSansProBold { - id: section - text: sectionName - anchors.left: parent.left - anchors.leftMargin: ProjectFilesStyle.general.leftMargin - color: ProjectFilesStyle.documentsList.sectionColor - font.family: boldFont.name - font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize - states: [ - State { - name: "hidden" - PropertyChanges { target: filesList; visible: false; } - PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; } - PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" } - } - ] + id: boldFont } - MouseArea { - id: titleMouseArea - anchors.fill: parent - hoverEnabled: true - z: 2 - onClicked: { - if (section.state === "hidden") - section.state = ""; - else - section.state = "hidden"; + RowLayout + { + anchors.top: parent.top + id: rowCol + height: ProjectFilesStyle.documentsList.height + Layout.fillWidth: true + + + Image { + source: "qrc:/qml/img/opentriangleindicator_filesproject.png" + width: 15 + sourceSize.width: 12 + id: imgArrow + anchors.right: section.left + anchors.rightMargin: 8 + anchors.top: parent.top + anchors.topMargin: 10 + } + + Text + { + id: section + text: sectionName + anchors.left: parent.left + anchors.leftMargin: ProjectFilesStyle.general.leftMargin + color: ProjectFilesStyle.documentsList.sectionColor + font.family: boldFont.name + font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize + states: [ + State { + name: "hidden" + PropertyChanges { target: filesList; visible: false; } + PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; } + PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" } + } + ] + } + + MouseArea { + id: titleMouseArea + anchors.fill: parent + hoverEnabled: true + z: 2 + onClicked: { + if (section.state === "hidden") + section.state = ""; + else + section.state = "hidden"; + } } } - } - ColumnLayout { - height: wrapperItem.hiddenHeightRepeater() - Layout.minimumHeight: wrapperItem.hiddenHeightRepeater() - Layout.preferredHeight: wrapperItem.hiddenHeightRepeater() - Layout.maximumHeight: wrapperItem.hiddenHeightRepeater() - width: parent.width - visible: section.state !== "hidden" - spacing: 0 - Repeater - { - id: filesList + ColumnLayout { + height: wrapperItem.hiddenHeightRepeater() + Layout.minimumHeight: wrapperItem.hiddenHeightRepeater() + Layout.preferredHeight: wrapperItem.hiddenHeightRepeater() + Layout.maximumHeight: wrapperItem.hiddenHeightRepeater() + width: parent.width visible: section.state !== "hidden" - Rectangle + spacing: 0 + + Repeater { + id: filesList visible: section.state !== "hidden" - id: rootItem - Layout.fillWidth: true - Layout.minimumHeight: wrapperItem.hiddenHeightElement() - Layout.preferredHeight: wrapperItem.hiddenHeightElement() - Layout.maximumHeight: wrapperItem.hiddenHeightElement() - height: wrapperItem.hiddenHeightElement() - color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : ProjectFilesStyle.documentsList.background - property bool isSelected - property bool renameMode - Text { - id: nameText - height: parent.height - visible: !renameMode - color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color - text: name; - font.family: fileNameFont.name - font.pointSize: ProjectFilesStyle.documentsList.fontSize - anchors.verticalCenter: parent.verticalCenter - verticalAlignment: Text.AlignVCenter - anchors.left: parent.left - anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 - width: parent.width - Connections - { - target: selManager - onSelected: { - if (groupName != sectionName) - rootItem.isSelected = false; - else if (doc === documentId) - rootItem.isSelected = true; - else - rootItem.isSelected = false; + Rectangle + { + visible: section.state !== "hidden" + id: rootItem + Layout.fillWidth: true + Layout.minimumHeight: wrapperItem.hiddenHeightElement() + Layout.preferredHeight: wrapperItem.hiddenHeightElement() + Layout.maximumHeight: wrapperItem.hiddenHeightElement() + height: wrapperItem.hiddenHeightElement() + color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent" + property bool isSelected + property bool renameMode + Text { + id: nameText + height: parent.height + visible: !renameMode + color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color + text: name; + font.family: fileNameFont.name + font.pointSize: ProjectFilesStyle.documentsList.fontSize + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + anchors.left: parent.left + anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 + width: parent.width + Connections + { + target: selManager + onSelected: { + if (groupName != sectionName) + rootItem.isSelected = false; + else if (doc === documentId) + rootItem.isSelected = true; + else + rootItem.isSelected = false; - if (rootItem.isSelected && section.state === "hidden") - section.state = ""; + if (rootItem.isSelected && section.state === "hidden") + section.state = ""; + } } } - } - TextInput { - id: textInput - text: nameText.text - visible: renameMode - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: ProjectFilesStyle.general.leftMargin - MouseArea { - id: textMouseArea - anchors.fill: parent - hoverEnabled: true - z: 2 - onClicked: { - textInput.forceActiveFocus(); + TextInput { + id: textInput + text: nameText.text + visible: renameMode + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: ProjectFilesStyle.general.leftMargin + MouseArea { + id: textMouseArea + anchors.fill: parent + hoverEnabled: true + z: 2 + onClicked: { + textInput.forceActiveFocus(); + } } - } - onVisibleChanged: { - if (visible) { - selectAll(); - forceActiveFocus(); + onVisibleChanged: { + if (visible) { + selectAll(); + forceActiveFocus(); + } } - } - onAccepted: close(true); - onCursorVisibleChanged: { - if (!cursorVisible) - close(false); - } - onFocusChanged: { - if (!focus) - close(false); - } - function close(accept) { - rootItem.renameMode = false; - if (accept) - { - var i = getDocumentIndex(documentId); - projectModel.renameDocument(documentId, textInput.text); - wrapperItem.model.set(i, projectModel.getDocument(documentId)); + onAccepted: close(true); + onCursorVisibleChanged: { + if (!cursorVisible) + close(false); + } + onFocusChanged: { + if (!focus) + close(false); + } + function close(accept) { + rootItem.renameMode = false; + if (accept) + { + var i = getDocumentIndex(documentId); + projectModel.renameDocument(documentId, textInput.text); + wrapperItem.model.set(i, projectModel.getDocument(documentId)); + } } } - } - MouseArea { - id: mouseArea - z: 1 - hoverEnabled: false - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked:{ - if (mouse.button === Qt.RightButton && !isContract) - contextMenu.popup(); - else if (mouse.button === Qt.LeftButton) - { - rootItem.isSelected = true; - projectModel.openDocument(documentId); - documentSelected(documentId, groupName); + MouseArea { + id: mouseArea + z: 1 + hoverEnabled: false + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked:{ + if (mouse.button === Qt.RightButton && !isContract) + contextMenu.popup(); + else if (mouse.button === Qt.LeftButton) + { + rootItem.isSelected = true; + projectModel.openDocument(documentId); + documentSelected(documentId, groupName); + } } } - } - Menu { - id: contextMenu - MenuItem { - text: qsTr("Rename") - onTriggered: { - rootItem.renameMode = true; + Menu { + id: contextMenu + MenuItem { + text: qsTr("Rename") + onTriggered: { + rootItem.renameMode = true; + } } - } - MenuItem { - text: qsTr("Delete") - onTriggered: { - projectModel.removeDocument(documentId); - wrapperItem.removeDocument(documentId); + MenuItem { + text: qsTr("Delete") + onTriggered: { + projectModel.removeDocument(documentId); + wrapperItem.removeDocument(documentId); + } } } } @@ -245,4 +254,3 @@ ColumnLayout { } } } - diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 15a7a638f..7a5593e5a 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -75,6 +75,12 @@ Rectangle { codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical); } + function displayCompilationErrorIfAny() + { + rightView.visible = true; + rightView.displayCompilationErrorIfAny(); + } + CodeEditorExtensionManager { headerView: headerPaneTabs; } diff --git a/mix/qml/ProjectFilesStyle.qml b/mix/qml/ProjectFilesStyle.qml index cb8225e0d..f4b83c728 100644 --- a/mix/qml/ProjectFilesStyle.qml +++ b/mix/qml/ProjectFilesStyle.qml @@ -25,7 +25,7 @@ QtObject { property string sectionColor: "#808080" property string selectedColor: "white" property string highlightColor: "#4a90e2" - property int height: 25 + property int height: 35 property int fileNameHeight: 30 property int fontSize: absoluteSize(2)// 13 property int sectionFontSize: absoluteSize(2)// 13 diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index ba162793b..18e7a0d5b 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -26,11 +26,9 @@ Item { Image { id: projectIcon source: "qrc:/qml/img/dappProjectIcon.png" - //sourceSize.height: 32 anchors.right: projectTitle.left anchors.verticalCenter: parent.verticalCenter anchors.rightMargin: 6 - //anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: 32 height: 32 @@ -65,7 +63,7 @@ Item { Rectangle { Layout.fillWidth: true - height: 10 + height: 3 color: ProjectFilesStyle.documentsList.background } @@ -82,14 +80,24 @@ Item { anchors.top: parent.top width: parent.width spacing: 0 - Repeater { model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")]; signal selected(string doc, string groupName) + property int incr: -1; id: sectionRepeater FilesSection { + id: section; sectionName: modelData + index: + { + for (var k in sectionRepeater.model) + { + if (sectionRepeater.model[k] === modelData) + return k; + } + } + model: sectionModel selManager: sectionRepeater @@ -119,7 +127,7 @@ Item { ci++; } } - } + } } } @@ -170,10 +178,10 @@ Item { projectModel.openDocument(newDoc.documentId); sectionRepeater.selected(newDoc.documentId, modelData); } - } } } + } } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 6a8a0093d..1b1384380 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -1,6 +1,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.3 import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." @@ -13,7 +14,7 @@ Rectangle { if (!message) { status.state = ""; - status.text = qsTr("Compile without errors."); + status.text = qsTr("Compile successfully."); logslink.visible = false; debugImg.state = "active"; } @@ -35,17 +36,24 @@ Rectangle { logslink.visible = false; } + function errorMessage(text) + { + status.state = "error"; + status.text = text + logslink.visible = false; + } + Connections { target:clientModel onRunStarted: infoMessage(qsTr("Running transactions...")); - onRunFailed: infoMessage(qsTr("Error running transactions")); + onRunFailed: errorMessage(qsTr("Error running transactions")); onRunComplete: infoMessage(qsTr("Run complete")); onNewBlock: infoMessage(qsTr("New block created")); } Connections { target:projectModel onDeploymentStarted: infoMessage(qsTr("Running deployment...")); - onDeploymentError: infoMessage(error); + onDeploymentError: errorMessage(error); onDeploymentComplete: infoMessage(qsTr("Deployment complete")); } Connections { @@ -56,6 +64,7 @@ Rectangle { color: "transparent" anchors.fill: parent + Rectangle { id: statusContainer anchors.horizontalCenter: parent.horizontalCenter @@ -64,49 +73,87 @@ Rectangle { width: 500 height: 30 color: "#fcfbfc" - RowLayout { + + + Text { + anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter + font.pointSize: StatusPaneStyle.general.statusFontSize + height: 15 + font.family: "sans serif" + objectName: "status" + wrapMode: Text.WrapAnywhere + elide: Text.ElideRight + maximumLineCount: 1 + clip: true + id: status + states: [ + State { + name: "error" + PropertyChanges { + target: status + color: "red" + } + PropertyChanges { + target: statusContainer + color: "#fffcd5" + } + } + ] + onTextChanged: + { + updateWidth() + toolTipInfo.tooltip = text; + } + + function updateWidth() + { + if (text.length > 80) + width = parent.width - 10 + else + width = undefined + } + } + + Button + { anchors.verticalCenter: parent.verticalCenter - spacing: 5 + anchors.left: parent.right + anchors.leftMargin: 10 + width: 38 + height: 28 + visible: false + text: qsTr("Log") + objectName: "status" + id: logslink + action: displayLogAction + } - Text { - font.pointSize: StatusPaneStyle.general.statusFontSize - height: 9 - font.family: "sans serif" - objectName: "status" - id: status - states:[ - State { - name: "error" - PropertyChanges { - target: status - color: "red" - } - PropertyChanges { - target: statusContainer - color: "#fffcd5" - } - } - ] + Action { + id: displayLogAction + onTriggered: { + mainContent.displayCompilationErrorIfAny(); } + } - Text { - visible: false - font.pointSize: StatusPaneStyle.general.logLinkFontSize - height: 9 - text: qsTr("See Log.") - font.family: "Monospace" - objectName: "status" - id: logslink - color: "#8c8a74" - MouseArea { - anchors.fill: parent - onClicked: { - mainContent.ensureRightView(); - } + Button + { + anchors.fill: parent + id: toolTip + action: toolTipInfo + text: "" + style: + ButtonStyle { + background:Rectangle { + color: "transparent" } } } + + Action { + id: toolTipInfo + tooltip: "" + } } Rectangle diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 75f7a4da3..971bf8513 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -6,12 +6,9 @@ import QtQuick.Layouts 1.1 Item { - property bool showLogs: true property ListModel fullModel: ListModel{} property ListModel transactionModel: ListModel{} - onShowLogsChanged: { - logTable.model = showLogs ? fullModel : transactionModel - } + property ListModel callModel: ListModel{} Action { id: addStateAction @@ -78,13 +75,24 @@ Item { action: mineAction } - CheckBox { - id: recording - text: qsTr("Record transactions"); - checked: true - Layout.fillWidth: true + ComboBox { + id: itemFilter + + function getCurrentModel() + { + return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel; + } + model: ListModel { + ListElement { text: qsTr("Calls and Transactions"); value: 0; } + ListElement { text: qsTr("Only Transactions"); value: 1; } + ListElement { text: qsTr("Only Calls"); value: 2; } + } + onCurrentIndexChanged: + { + logTable.model = itemFilter.getCurrentModel(); + } } } TableView { @@ -141,14 +149,20 @@ Item { onStateCleared: { fullModel.clear(); transactionModel.clear(); + callModel.clear(); } onNewRecord: { - if (recording.checked) - { - fullModel.append(_r); - if (!_r.call) - transactionModel.append(_r); - } + fullModel.append(_r); + if (!_r.call) + transactionModel.append(_r); + else + callModel.append(_r); + } + onMiningComplete: { + var block = clientModel.lastBlock; + console.log(block); + fullModel.append(block); + console.log(JSON.stringify(block)); } } diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 0d0d70d31..6f03088a4 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -26,7 +26,8 @@ Item { function reload() { if (initialized) { updateContract(); - webView.runJavaScript("reloadPage()"); + //webView.runJavaScript("reloadPage()"); + setPreviewUrl(urlInput.text); } } @@ -55,11 +56,13 @@ Item { } function changePage() { - if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) { + setPreviewUrl(urlInput.text); + /*if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) { + urlInput.text = httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId; setPreviewUrl(httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId); } else { setPreviewUrl(""); - } + }*/ } Connections { target: appContext @@ -98,24 +101,16 @@ Item { updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } ) } - onDocumentOpened: { - if (!document.isHtml) - return; - for (var i = 0; i < pageListModel.count; i++) { - var doc = pageListModel.get(i); - if (doc.documentId === document.documentId) { - pageCombo.currentIndex = i; - } - } - } - onProjectLoading: { for (var i = 0; i < target.listModel.count; i++) { var document = target.listModel.get(i); if (document.isHtml) { pageListModel.append(document); if (pageListModel.count === 1) //first page added - changePage(); + { + urlInput.text = httpServer.url + "/" + document.documentId; + setPreviewUrl(httpServer.url + "/" + document.documentId); + } } } } @@ -151,13 +146,20 @@ Item { else { //document request + if (urlPath === "/") + urlPath = "/index.html"; var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1); var content = ""; if (projectModel.codeEditor.isDocumentOpen(documentId)) content = projectModel.codeEditor.getDocumentText(documentId); else - content = fileIo.readFile(projectModel.getDocument(documentId).path); - if (documentId === pageListModel.get(pageCombo.currentIndex).documentId) { + { + var doc = projectModel.getDocument(documentId); + if (doc !== undefined) + content = fileIo.readFile(doc.path); + } + + if (documentId === urlInput.text.replace(httpServer.url + "/", "")) { //root page, inject deployment script content = "\n" + content; _request.setResponseContentType("text/html"); @@ -181,19 +183,23 @@ Item { anchors.fill: parent anchors.leftMargin: 3 spacing: 3 - DefaultLabel { - text: qsTr("Preview of") - anchors.verticalCenter: parent.verticalCenter - } - ComboBox { - id: pageCombo - model: pageListModel - textRole: "name" - currentIndex: -1 - onCurrentIndexChanged: changePage() + DefaultTextField + { + id: urlInput anchors.verticalCenter: parent.verticalCenter height: 21 + width: 300 + Keys.onEnterPressed: + { + setPreviewUrl(text); + } + Keys.onReturnPressed: + { + setPreviewUrl(text); + } + + focus: true } Action { diff --git a/mix/qml/main.qml b/mix/qml/main.qml index c9e8c8225..7814f07e0 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -56,7 +56,7 @@ ApplicationWindow { MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewOrientationAction } - MenuItem { action: toggleCallsInLog } + //MenuItem { action: toggleCallsInLog } } } @@ -92,7 +92,7 @@ ApplicationWindow { Action { id: mineAction - text: qsTr("Mine") + text: qsTr("New Block") shortcut: "Ctrl+M" onTriggered: clientModel.mine(); enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining @@ -165,15 +165,6 @@ ApplicationWindow { onTriggered: mainContent.toggleWebPreviewOrientation(); } - Action { - id: toggleCallsInLog - text: qsTr("Show Calls in Transaction Log") - shortcut: "" - checkable: true - checked: mainContent.rightPane.transactionLog.showLogs - onTriggered: mainContent.rightPane.transactionLog.showLogs = !mainContent.rightPane.transactionLog.showLogs - } - Action { id: toggleRunOnLoadAction text: qsTr("Load State on Startup") From a65f90e5cc20a8fb486a8d50c6c9f4227576de8d Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 27 Feb 2015 11:43:52 +0100 Subject: [PATCH 09/12] Eet gas to 2000 for the urlHint tr. --- mix/qml/js/ProjectModel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 891bb1320..086902f75 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -555,7 +555,7 @@ function registerContentHash(registrar, callBack) //setContent() jsonrpc: "2.0", method: "eth_transact", - params: [ { "from": deploymentDialog.currentAccount, "gas": "2000", "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], + params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], id: jsonRpcRequestId++ }); rpcCall(requests, function (httpRequest, response) { @@ -572,7 +572,7 @@ function registerToUrlHint() //urlHint => suggestUrl jsonrpc: "2.0", method: "eth_transact", - params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], + params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 2000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], id: jsonRpcRequestId++ }); From d7a61fcb16c6e10321e8dedeeb0fac9d63ee9c7d Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 27 Feb 2015 11:48:40 +0100 Subject: [PATCH 10/12] Activate "warnings treated as errors" for gcc. --- cmake/EthCompilerSettings.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 4d56c808b..35a855a45 100755 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -3,7 +3,7 @@ # C++11 check and activation if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") From 8f95591290d1bf86ee1e0b3df86ce56c47053a32 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 27 Feb 2015 13:26:42 +0100 Subject: [PATCH 11/12] - Do not create a registrar for the dapp itself - eth:// scheme - Handle empty path - Don't wait for transactions to be mined, setDefault to zero --- mix/qml/DeploymentDialog.qml | 17 ++- mix/qml/js/ProjectModel.js | 257 +++++++++++++++++++---------------- 2 files changed, 154 insertions(+), 120 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index b9a194220..5dbdd356e 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -187,10 +187,23 @@ Window { text: qsTr("Ethereum Application URL: ") } - DefaultTextField + Rectangle { Layout.fillWidth: true - id: applicationUrlEth + height: 25 + color: "transparent" + DefaultTextField + { + width: 350 + id: applicationUrlEth + } + + DefaultLabel + { + anchors.verticalCenter: parent.verticalCenter; + anchors.left: applicationUrlEth.right + text: "/" + projectModel.projectTitle + } } DefaultLabel diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 086902f75..6737a0c9a 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -309,8 +309,23 @@ function startDeployProject(erasePrevious) var ctrNames = Object.keys(codeModel.contracts); var ctrAddresses = {}; - deployContracts(0, ctrAddresses, ctrNames, function (){ - finalizeDeployment(deploymentId, ctrAddresses); + setDefaultBlock(0, function() { + deployContracts(0, ctrAddresses, ctrNames, function (){ + finalizeDeployment(deploymentId, ctrAddresses); + }); + }); +} + +function setDefaultBlock(val, callBack) +{ + var requests = [{ + jsonrpc: "2.0", + method: "eth_setDefaultBlock", + params: [val], + id: 0 + }]; + rpcCall(requests, function (httpCall, response){ + callBack(); }); } @@ -398,143 +413,143 @@ function finalizeDeployment(deploymentId, addresses) { var applicationUrlEth = deploymentDialog.applicationUrlEth; applicationUrlEth = formatAppUrl(applicationUrlEth); - deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); - applicationUrlEth.push(projectModel.projectTitle); checkEthPath(applicationUrlEth, function () { deploymentComplete(); deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); deployRessourcesDialog.open(); + setDefaultBlock(-1, function() {}); }); } function checkEthPath(dappUrl, callBack) { - var str = createString(dappUrl[0]); - var requests = []; - requests.push({ - //register() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - rpcCall(requests, function (httpRequest, response) { - var res = JSON.parse(response); - var addr = normalizeAddress(res[0].result); - if (addr === "") - { - var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting."); - deploymentError(errorTxt); - console.log(errorTxt); - } - else - { - dappUrl.splice(0, 1); - checkRegistration(dappUrl, addr, callBack); - } - }); + if (dappUrl.length === 1) + registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar. + else + { + // the first owned reigstrar must have been created to follow the path. + var str = createString(dappUrl[0]); + var requests = []; + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response) { + var res = JSON.parse(response); + var addr = normalizeAddress(res[0].result); + if (addr.replace(/0+/g, "") === "") + { + var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting."); + deploymentError(errorTxt); + console.log(errorTxt); + } + else + { + dappUrl.splice(0, 1); + checkRegistration(dappUrl, addr, callBack); + } + }); + } } function checkRegistration(dappUrl, addr, callBack) { - var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr); - deploymentStepChanged(txt); - console.log(txt); - var requests = []; - var registrar = {} - var str = createString(dappUrl[0]); - requests.push({ - //getOwner() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], - id: jsonRpcRequestId++ - }); - - requests.push({ - //register() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function (httpRequest, response) { - var res = JSON.parse(response); - var nextAddr = normalizeAddress(res[1].result); - var errorTxt; - if (res[1].result === "0x") - { - errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting"); - deploymentError(errorTxt); - console.log(errorTxt); - } - else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result)) - { - errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting"); - deploymentError(errorTxt); - console.log(errorTxt); - } - else if (nextAddr.replace(/0+/g, "") !== "") - { - dappUrl.splice(0, 1); - if (dappUrl.length > 0) + if (dappUrl.length === 1) + registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash. + else + { + var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr); + deploymentStepChanged(txt); + console.log(txt); + var requests = []; + var registrar = {} + var str = createString(dappUrl[0]); + requests.push({ + //getOwner() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], + id: jsonRpcRequestId++ + }); + + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function (httpRequest, response) { + var res = JSON.parse(response); + var nextAddr = normalizeAddress(res[1].result); + var errorTxt; + if (res[1].result === "0x") + { + errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result)) + { + errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (nextAddr.replace(/0+/g, "") !== "") + { + dappUrl.splice(0, 1); checkRegistration(dappUrl, nextAddr, callBack); + } else - registerContentHash(addr, callBack); - } - else - { - var txt = qsTr("Registering sub domain " + dappUrl[0] + " ..."); - console.log(txt); - deploymentStepChanged(txt); - //current registrar is owned => ownedregistrar creation and continue. - requests = []; - - requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function(httpRequest, response) { - console.log("crea2" + response); - var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result); - requests = []; - console.log('new created addr ' + newCtrAddress); - - var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); - deploymentStepChanged(txt); + { + var txt = qsTr("Registering sub domain " + dappUrl[0] + " ..."); console.log(txt); + deploymentStepChanged(txt); + //current registrar is owned => ownedregistrar creation and continue. + requests = []; - deploymentDialog.waitForTrCountToIncrement(function(status) { - if (status === -1) - { - trCountIncrementTimeOut(); - return; - } - var crLevel = createString(dappUrl[0]).encodeValueAsString(); - requests.push({ - //setRegister() - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function(){ - dappUrl.splice(0, 1); - if (dappUrl.length > 0) + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function(httpRequest, response) { + var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result); + requests = []; + var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); + deploymentStepChanged(txt); + console.log(txt); + deploymentDialog.waitForTrCountToIncrement(function(status) { + if (status === -1) + { + trCountIncrementTimeOut(); + return; + } + var crLevel = createString(dappUrl[0]).encodeValueAsString(); + requests.push({ + //setRegister() + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function(request, response){ + dappUrl.splice(0, 1); checkRegistration(dappUrl, newCtrAddress, callBack); - else - registerContentHash(addr, callBack); + }); }); }); - }); - } - }); + } + }); + } } function trCountIncrementTimeOut() @@ -592,6 +607,11 @@ function normalizeAddress(addr) function formatAppUrl(url) { + if (url.toLowerCase().indexOf("eth://") === 0) + url = url.substring(6); + if (url === "") + return [projectModel.projectTitle]; + var ret; if (url.indexOf("/") === -1) ret = url.split('.').reverse(); @@ -608,5 +628,6 @@ function formatAppUrl(url) } if (ret[0].toLowerCase() === "eth") ret.splice(0, 1); + ret.push(projectModel.projectTitle); return ret; } From 92762f9d0d881d04674ce27f47d9bbd40da09d4e Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 27 Feb 2015 14:56:46 +0100 Subject: [PATCH 12/12] - Clear debugger view if empty record. --- mix/ClientModel.cpp | 9 +++++++-- mix/ClientModel.h | 19 +++++++++++++++---- mix/qml/Debugger.qml | 9 ++++++--- mix/qml/TransactionLog.qml | 13 +++++++------ mix/qml/js/ProjectModel.js | 4 ++-- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index da07a4461..86b5ea050 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -325,6 +325,11 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) debugDataReady(debugData); } +void ClientModel::emptyRecord() +{ + debugDataReady(new QDebugData()); +} + void ClientModel::debugRecord(unsigned _index) { @@ -356,7 +361,7 @@ RecordLogEntry* ClientModel::lastBlock() const strGas << blockInfo.gasUsed; std::stringstream strNumber; strNumber << blockInfo.number; - RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), QString(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(blockInfo.hash.abridged())), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false); + RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash.ref()))), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false, RecordLogEntry::RecordType::Block); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; } @@ -436,7 +441,7 @@ void ClientModel::onNewTransaction() } } - RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall()); + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); emit newRecord(log); } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 96c34d3ed..60a70a065 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -72,6 +72,7 @@ struct TransactionSettings class RecordLogEntry: public QObject { Q_OBJECT + Q_ENUMS(RecordType) /// Recording index Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT) /// Human readable transaction bloack and transaction index @@ -88,13 +89,20 @@ class RecordLogEntry: public QObject Q_PROPERTY(QString returned MEMBER m_returned CONSTANT) /// true if call, false if transaction Q_PROPERTY(bool call MEMBER m_call CONSTANT) - + /// @returns record type + Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) public: + enum RecordType + { + Transaction, + Block + }; + RecordLogEntry(): - m_recordIndex(0), m_call(false) {} - RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call): - m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call) {} + m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} + RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type): + m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type) {} private: unsigned m_recordIndex; @@ -105,6 +113,7 @@ private: QString m_address; QString m_returned; bool m_call; + RecordType m_type; }; /** @@ -140,6 +149,8 @@ public slots: void setupState(QVariantMap _state); /// Show the debugger for a specified record Q_INVOKABLE void debugRecord(unsigned _index); + /// Show the debugger for an empty record + Q_INVOKABLE void emptyRecord(); private slots: /// Update UI with machine states result. Display a modal dialog. diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 9c1257613..17ab1d8b7 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -36,10 +36,13 @@ Rectangle { function update(data, giveFocus) { - if (codeModel.hasContract) + if (data === null) + Debugger.init(null); + else if (data.states.length === 0) + Debugger.init(null); + else if (codeModel.hasContract) { - if (data !== null) - Debugger.init(data); + Debugger.init(data); debugScrollArea.visible = true; compilationErrorArea.visible = false; machineStates.visible = true; diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 971bf8513..2821e235c 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 +import org.ethereum.qml.RecordLogEntry 1.0 Item { @@ -133,7 +134,10 @@ Item { } onActivated: { var item = logTable.model.get(row); - clientModel.debugRecord(item.recordIndex); + if (item.type === RecordLogEntry.Transaction) + clientModel.debugRecord(item.recordIndex); + else + clientModel.emptyRecord(); } Keys.onPressed: { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { @@ -159,11 +163,8 @@ Item { callModel.append(_r); } onMiningComplete: { - var block = clientModel.lastBlock; - console.log(block); - fullModel.append(block); - console.log(JSON.stringify(block)); + fullModel.append(clientModel.lastBlock); + transactionModel.append(clientModel.lastBlock); } } - } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 9ca9bae39..182a0587f 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -282,7 +282,7 @@ function deployProject(force) { var date = new Date(); var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - var jsonRpcUrl = "http://127.0.0.1:8080"; + var jsonRpcUrl = "http://127.0.0.1:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); @@ -369,7 +369,7 @@ function finalizeDeployment(deploymentId, addresses) { //copy scripts fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js"); fileIo.copyFile("qrc:///js/webthree.js", deploymentDir + "ethereum.js"); - deploymentAddress = address; + deploymentAddress = addresses; saveProject(); deploymentComplete(); }