Browse Source

Merge pull request #1089 from yann300/ui_improvement

Contract Deployment
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
8217cd57bb
  1. 99
      mix/FileIo.cpp
  2. 25
      mix/FileIo.h
  3. 2
      mix/QVariableDefinition.h
  4. 232
      mix/qml/DeploymentDialog.qml
  5. 39
      mix/qml/ProjectModel.qml
  6. 1
      mix/qml/StatusPane.qml
  7. 1
      mix/qml/Style.qml
  8. 2
      mix/qml/TransactionDialog.qml
  9. 244
      mix/qml/js/ProjectModel.js
  10. 16
      mix/qml/js/QEtherHelper.js
  11. 1
      mix/res.qrc

99
mix/FileIo.cpp

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FileIo.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com
@ -20,13 +20,21 @@
* Ethereum IDE client.
*/
#include <QDirIterator>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QUrl>
#include <json/json.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
#include "FileIo.h"
using namespace dev;
using namespace dev::crypto;
using namespace dev::mix;
void FileIo::makeDir(QString const& _url)
@ -101,3 +109,72 @@ bool FileIo::fileExists(QString const& _url)
QFile file(url.path());
return file.exists();
}
QStringList FileIo::makePackage(QString const& _deploymentFolder)
{
Json::Value manifest;
Json::Value entries(Json::arrayValue);
QUrl folder(_deploymentFolder);
QString path(folder.path());
QDir deployDir = QDir(path);
dev::RLPStream rlpStr;
int k = 1;
std::vector<bytes> files;
for (auto item: deployDir.entryInfoList(QDir::Files))
{
QFile qFile(item.filePath());
if (qFile.open(QIODevice::ReadOnly))
{
k++;
QFileInfo fileInfo = QFileInfo(qFile.fileName());
Json::Value jsonValue;
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
QByteArray a = qFile.readAll();
bytes data = bytes(a.begin(), a.end());
files.push_back(data);
jsonValue["hash"] = toHex(dev::sha3(data).ref());
entries.append(jsonValue);
}
qFile.close();
}
rlpStr.appendList(k);
std::stringstream jsonStr;
jsonStr << manifest;
QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8();
rlpStr.append(bytesConstRef((const unsigned char*)b.data(), b.size()));
for (unsigned int k = 0; k < files.size(); k++)
rlpStr.append(files.at(k));
manifest["entries"] = entries;
bytes dapp = rlpStr.out();
dev::h256 dappHash = dev::sha3(dapp);
//encrypt
KeyPair key(dappHash);
Secp256k1 enc;
enc.encrypt(key.pub(), dapp);
QUrl url(_deploymentFolder + "package.dapp");
QFile compressed(url.path());
QByteArray qFileBytes((char*)dapp.data(), dapp.size());
if (compressed.open(QIODevice::WriteOnly))
{
compressed.write(qFileBytes);
compressed.flush();
}
else
error(tr("Error creating package.dapp"));
compressed.close();
QStringList ret;
ret.append(QString::fromStdString(toHex(dappHash.ref())));
ret.append(qFileBytes.toBase64());
return ret;
}

25
mix/FileIo.h

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FileIo.h
* @author Arkadiy Paronyan arkadiy@ethdev.com
@ -22,6 +22,7 @@
#pragma once
#include <libdevcore/CommonData.h>
#include <QObject>
namespace dev
@ -52,6 +53,8 @@ public:
Q_INVOKABLE void moveFile(QString const& _sourceUrl, QString const& _destUrl);
/// Check if file exists
Q_INVOKABLE bool fileExists(QString const& _url);
/// Compress a folder, @returns sha3 of the compressed file.
Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder);
private:
QString getHomePath() const;

2
mix/QVariableDefinition.h

@ -53,6 +53,8 @@ public:
virtual bytes encodeValue() = 0;
/// Decode the return value @a _rawValue.
virtual void decodeValue(dev::bytes const& _rawValue) = 0;
/// returns String representation of the encoded value.
Q_INVOKABLE QString encodeValueAsString() { return QString::fromStdString(dev::toHex(encodeValue())); }
protected:
QString m_value;

232
mix/qml/DeploymentDialog.qml

@ -0,0 +1,232 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.1
import QtQuick.Controls.Styles 1.3
import org.ethereum.qml.QEther 1.0
import "js/TransactionHelper.js" as TransactionHelper
import "js/ProjectModel.js" as ProjectModelCode
import "js/QEtherHelper.js" as QEtherHelper
import "."
Window {
id: modalDeploymentDialog
modality: Qt.ApplicationModal
width: 600
height: 350
visible: false
property alias applicationUrlEth: applicationUrlEth.text
property alias applicationUrlHttp: applicationUrlHttp.text
property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d"
property string packageHash
property alias packageBase64: base64Value.text
property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4";
property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d";
color: Style.generic.layout.backgroundColor
function close()
{
visible = false;
}
function open()
{
modalDeploymentDialog.setX((Screen.width - width) / 2);
modalDeploymentDialog.setY((Screen.height - height) / 2);
visible = true;
}
function pad(h)
{
// TODO move this to QHashType class
while (h.length < 64)
{
h = '0' + h;
}
return h;
}
Rectangle
{
anchors.fill : parent
anchors.margins: 10
color: Style.generic.layout.backgroundColor
GridLayout
{
columns: 2
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
DefaultLabel
{
text: qsTr("Ethereum Application URL: ")
}
DefaultTextField
{
Layout.fillWidth: true
id: applicationUrlEth
}
DefaultLabel
{
text: qsTr("Web Application Ressources URL: ")
}
DefaultTextField
{
Layout.fillWidth: true
id: applicationUrlHttp
}
DefaultLabel
{
text: qsTr("Package (Base64): ")
}
TextArea
{
Layout.fillWidth: true
readOnly: true
id: base64Value
height: 60
enabled: base64Value.text != ""
}
}
MessageDialog {
id: deployDialog
standardButtons: StandardButton.Ok
icon: StandardIcon.Warning
}
RowLayout
{
anchors.bottom: parent.bottom
anchors.right: parent.right;
anchors.bottomMargin: 10
Button {
text: qsTr("Deploy to Ethereum");
tooltip: qsTr("Deploy contract and package resources files.")
onClicked: {
deployWarningDialog.open();
}
}
Button {
text: qsTr("Register Web Application");
tooltip: qsTr("Register hosted Web Application.")
onClicked: {
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
{
deployDialog.title = text;
deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step. ")
deployDialog.open();
}
else
ProjectModelCode.registerToUrlHint();
}
}
Button {
text: qsTr("Close");
onClicked: close();
}
Button {
text: qsTr("Check Ownership");
visible : false
onClicked: {
var requests = [];
var ethStr = QEtherHelper.createString("wallet");
var ethHash = QEtherHelper.createHash(eth);
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
});
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);
}
}
Button {
text: qsTr("Generate registrar init");
visible: false
onClicked: {
console.log("registering eth/wallet")
var jsonRpcRequestId = 0;
var requests = [];
var walletStr = QEtherHelper.createString("wallet");
requests.push({ //reserve
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ],
id: jsonRpcRequestId++
});
requests.push({ //setRegister
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ],
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);
}
}
}
}
}

39
mix/qml/ProjectModel.qml

@ -21,6 +21,7 @@ Item {
signal newProject(var projectData)
signal documentSaved(var documentId)
signal deploymentStarted()
signal deploymentStepChanged(string message)
signal deploymentComplete()
signal deploymentError(string error)
@ -31,7 +32,7 @@ Item {
property string projectPath: ""
property string projectTitle: ""
property string currentDocumentId: ""
property string deploymentAddress: ""
property var deploymentAddresses: []
property var listModel: projectListModel
property var stateListModel: projectStateListModel.model
property CodeEditorView codeEditor: null
@ -55,6 +56,7 @@ Item {
function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); }
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function deployProject() { ProjectModelCode.deployProject(false); }
function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); }
Connections {
target: appContext
@ -91,15 +93,44 @@ Item {
MessageDialog {
id: deployWarningDialog
property bool redeploy
title: qsTr("Project")
text: qsTr("This project has been already deployed to the network. Do you want to re-deploy it?")
standardButtons: StandardButton.Ok | StandardButton.Cancel
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?")
}
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
onAccepted: {
ProjectModelCode.deployProject(true);
ProjectModelCode.startDeployProject(!redeploy);
}
onReset: {
ProjectModelCode.startDeployProject(true);
}
}
MessageDialog {
id: deployRessourcesDialog
title: qsTr("Project")
standardButtons: StandardButton.Ok
icon: StandardIcon.Info
}
DeploymentDialog
{
id: deploymentDialog
}
ListModel {
id: projectListModel
}

1
mix/qml/StatusPane.qml

@ -47,6 +47,7 @@ Rectangle {
onDeploymentStarted: infoMessage(qsTr("Running deployment..."));
onDeploymentError: infoMessage(error);
onDeploymentComplete: infoMessage(qsTr("Deployment complete"));
onDeploymentStepChanged: infoMessage(message);
}
Connections {
target: codeModel

1
mix/qml/Style.qml

@ -11,6 +11,7 @@ QtObject {
property QtObject generic: QtObject {
property QtObject layout: QtObject {
property string separatorColor: "#808080"
property string backgroundColor: "#ededed"
}
property QtObject size: QtObject {
property string titlePointSize: absoluteSize(0)

2
mix/qml/TransactionDialog.qml

@ -405,7 +405,7 @@ Window {
return boolViewComp;
else if (type.indexOf("string") !== -1)
return stringViewComp;
else if (type.indexOf("hash") !== -1)
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
return hashViewComp;
else
return null;

244
mix/qml/js/ProjectModel.js

@ -19,6 +19,7 @@
* @date 2015
* Ethereum IDE client.
*/
Qt.include("QEtherHelper.js")
var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>";
var contractTemplate = "contract Contract {\n}\n";
@ -45,7 +46,11 @@ function saveProject() {
var projectData = {
files: [],
title: projectTitle,
deploymentAddress: deploymentAddress
deploymentAddresses: deploymentAddresses,
applicationUrlEth: deploymentDialog.applicationUrlEth,
applicationUrlHttp: deploymentDialog.applicationUrlHttp,
packageHash: deploymentDialog.packageHash,
packageBase64: deploymentDialog.packageBase64
};
for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName)
@ -63,11 +68,19 @@ function loadProject(path) {
var projectFile = path + projectFileName;
var json = fileIo.readFile(projectFile);
var projectData = JSON.parse(json);
if (projectData.packageHash)
deploymentDialog.packageHash = projectData.packageHash
if (projectData.packageBase64)
deploymentDialog.packageBase64 = projectData.packageBase64
if (projectData.applicationUrlEth)
deploymentDialog.applicationUrlEth = projectData.applicationUrlEth
if (projectData.applicationUrlHttp)
deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp
if (!projectData.title) {
var parts = path.split("/");
projectData.title = parts[parts.length - 2];
}
deploymentAddress = projectData.deploymentAddress ? projectData.deploymentAddress : "";
deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : [];
projectTitle = projectData.title;
projectPath = path;
if (!projectData.files)
@ -272,22 +285,27 @@ function generateFileName(name, extension) {
var jsonRpcRequestId = 1;
function deployProject(force) {
saveAll(); //TODO: ask user
deploymentDialog.open();
}
if (!force && deploymentAddress !== "") {
deployWarningDialog.visible = true;
function startDeployProject(erasePrevious)
{
var date = new Date();
var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz");
if (!erasePrevious)
{
finalizeDeployment(deploymentId, projectModel.deploymentAddresses);
return;
}
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();
var requests = [];
var requestNames = [];
for (var c in codeModel.contracts) { //TODO: order based on dependencies
var code = codeModel.contracts[c].codeHex;
requests.push({
@ -299,8 +317,8 @@ function deployProject(force) {
requestNames.push(c);
}
var rpcRequest = JSON.stringify(requests);;
var httpRequest = new XMLHttpRequest()
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);
@ -311,8 +329,8 @@ function deployProject(force) {
var rpcResponse = JSON.parse(httpRequest.responseText);
if (rpcResponse.length === requestNames.length) {
var contractAddresses = {};
for (var r = 0; r < rpcResponse.lenght; r++)
contractAddresses[requestNames[r]] = rpcResponse.result;
for (var r = 0; r < rpcResponse.length; r++)
contractAddresses[requestNames[r]] = rpcResponse[r].result;
finalizeDeployment(deploymentId, contractAddresses);
}
} else {
@ -326,7 +344,7 @@ function deployProject(force) {
}
function finalizeDeployment(deploymentId, addresses) {
//create a dir for frontend files and copy them
deploymentStepChanged(qsTr("Packaging application ..."));
var deploymentDir = projectPath + deploymentId + "/";
fileIo.makeDir(deploymentDir);
for (var i = 0; i < projectListModel.count; i++) {
@ -369,7 +387,203 @@ 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;
deploymentAddresses = addresses;
saveProject();
deploymentComplete();
var packageRet = fileIo.makePackage(deploymentDir);
deploymentDialog.packageHash = packageRet[0];
deploymentDialog.packageBase64 = packageRet[1];
var applicationUrlEth = deploymentDialog.applicationUrlEth;
applicationUrlEth = formatAppUrl(applicationUrlEth);
deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkRegistration(applicationUrlEth, deploymentDialog.eth, function () {
deploymentComplete();
deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployRessourcesDialog.open();
});
}
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);
}
function checkRegistration(dappUrl, addr, callBack)
{
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++
});
requests.push({
//accounts
jsonrpc: "2.0",
method: "eth_accounts",
params: null,
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
requests = [];
var res = JSON.parse(response);
var currentOwner = res[0].result;
var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === '';
if (noOwner)
{
requests.push({
//reserve()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + addr, "data": "0x1c83171b" + paramTitle.encodeValueAsString() } ],
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();
});
});
}
}
function registerToUrlHint()
{
deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ...");
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++
});
rpcCall(requests, function (httpRequest, response) {
deploymentComplete();
});
}
function normalizeAddress(addr)
{
addr = addr.replace('0x', '');
var i = 0;
for (var k in addr)
{
if (addr[k] !== "0")
break;
else
i++;
}
return addr.substring(i);
}
function formatAppUrl(url)
{
var slash = url.indexOf("/");
var dot = url.indexOf(".");
if (slash === -1 && dot === -1)
return url;
if ((slash !== -1 && slash < dot) || dot === -1)
return url.split("/");
else
{
var dotted;
var ret = [];
if (slash !== -1)
{
ret.push(url.split("/"));
dotted = ret[0].split(".");
}
else
dotted = url.split(".");
for (var k in dotted)
ret.unshift(dotted[k]);
return ret;
}
}

16
mix/qml/js/QEtherHelper.js

@ -15,3 +15,19 @@ function createBigInt(_value)
return bigint;
}
function createString(_value)
{
var stringComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
var stringC = stringComponent.createObject();
stringC.setValue(_value);
return stringC;
}
function createHash(_value)
{
var hComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
var hC = hComponent.createObject();
hC.setValue(_value);
return hC;
}

1
mix/res.qrc

@ -101,5 +101,6 @@
<file>qml/Style.qml</file>
<file>qml/WebPreviewStyle.qml</file>
<file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file>
</qresource>
</RCC>

Loading…
Cancel
Save