Browse Source

deploy to network

cl-refactor
arkpar 10 years ago
parent
commit
6810ad3d86
  1. 9
      mix/CodeModel.cpp
  2. 6
      mix/CodeModel.h
  3. 7
      mix/qml/ProjectModel.qml
  4. 8
      mix/qml/StatusPane.qml
  5. 93
      mix/qml/js/ProjectModel.js
  6. 13
      mix/qml/main.qml

9
mix/CodeModel.cpp

@ -28,6 +28,7 @@
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/InterfaceHandler.h>
#include <libevmcore/Instruction.h>
#include <libethcore/CommonJS.h>
#include "QContractDefinition.h"
#include "QFunctionDefinition.h"
#include "QVariableDeclaration.h"
@ -61,7 +62,6 @@ CompilationResult::CompilationResult(const dev::solidity::CompilerStack& _compil
auto const& contractDefinition = _compiler.getContractDefinition(std::string());
m_contract.reset(new QContractDefinition(&contractDefinition));
m_bytes = _compiler.getBytecode();
m_assemblyCode = QString::fromStdString(dev::eth::disassemble(m_bytes));
dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty())
@ -78,11 +78,16 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con
m_contract(_prev.m_contract),
m_compilerMessage(_compilerMessage),
m_bytes(_prev.m_bytes),
m_assemblyCode(_prev.m_assemblyCode),
m_contractInterface(_prev.m_contractInterface),
m_codeHighlighter(_prev.m_codeHighlighter)
{}
QString CompilationResult::codeHex() const
{
return QString::fromStdString(toJS(m_bytes));
}
CodeModel::CodeModel(QObject* _parent):
QObject(_parent),
m_compiling(false),

6
mix/CodeModel.h

@ -69,6 +69,7 @@ class CompilationResult: public QObject
Q_PROPERTY(QString compilerMessage READ compilerMessage CONSTANT)
Q_PROPERTY(bool successful READ successful CONSTANT)
Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT)
Q_PROPERTY(QString codeHex READ codeHex CONSTANT)
public:
/// Empty compilation result constructor
@ -88,8 +89,8 @@ public:
QString compilerMessage() const { return m_compilerMessage; }
/// @returns contract bytecode
dev::bytes const& bytes() const { return m_bytes; }
/// @returns contract bytecode in human-readable form
QString assemblyCode() const { return m_assemblyCode; }
/// @returns contract bytecode as hex string
QString codeHex() const;
/// @returns contract definition in JSON format
QString contractInterface() const { return m_contractInterface; }
/// Get code highlighter
@ -101,7 +102,6 @@ private:
std::shared_ptr<QContractDefinition> m_contract;
QString m_compilerMessage; ///< @todo: use some structure here
dev::bytes m_bytes;
QString m_assemblyCode;
QString m_contractInterface;
std::shared_ptr<CodeHighlighter> m_codeHighlighter;

7
mix/qml/ProjectModel.qml

@ -20,6 +20,9 @@ Item {
signal projectSaved()
signal newProject(var projectData)
signal documentSaved(var documentId)
signal deploymentStarted()
signal deploymentComplete()
signal deploymentError(string error)
property bool isEmpty: (projectPath === "")
readonly property string projectFileName: ".mix"
@ -28,6 +31,7 @@ Item {
property string projectPath: ""
property string projectTitle: ""
property string currentDocumentId: ""
property string deploymentAddress: ""
property var listModel: projectListModel
property var stateListModel: projectStateListModel.model
@ -48,7 +52,8 @@ Item {
function removeDocument(documentId) { ProjectModelCode.removeDocument(documentId); }
function getDocument(documentId) { return ProjectModelCode.getDocument(documentId); }
function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); }
function doAddExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function deployProject() { ProjectModelCode.deployProject(); }
Connections {
target: appContext

8
mix/qml/StatusPane.qml

@ -38,11 +38,17 @@ Rectangle {
Connections {
target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions.."));
onRunStarted: infoMessage(qsTr("Running transactions..."));
onRunFailed: infoMessage(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);
onDeploymentComplete: infoMessage(qsTr("Deployment complete"));
}
color: "transparent"
anchors.fill: parent

93
mix/qml/js/ProjectModel.js

@ -39,7 +39,11 @@ function closeProject() {
function saveProject() {
if (!isEmpty) {
var projectData = { files: [] };
var projectData = {
files: [],
title: projectTitle,
deploymentAddress: deploymentAddress
};
for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName)
projectSaving(projectData);
@ -60,6 +64,7 @@ function loadProject(path) {
var parts = path.split("/");
projectData.title = parts[parts.length - 2];
}
deploymentAddress = projectData.deploymentAddress ? projectData.deploymentAddress : "";
projectTitle = projectData.title;
projectPath = path;
if (!projectData.files)
@ -246,3 +251,89 @@ function generateFileName(name, extension) {
return fileName
}
var jsonRpcRequestId = 1;
function deployProject() {
saveAll(); //TODO: ask user
var deploymentId = Date.now().toLocaleString("ddMMyyyHHmmsszzz");
var jsonRpcUrl = "http://localhost:8080";
console.log("Deploying " + deploymentId + " to " + jsonRpcUrl);
deploymentStarted();
var code = codeModel.codeHex
var rpcRequest = JSON.stringify({
jsonrpc: "2.0",
method: "eth_transact",
params: [ {
"code": code
} ],
id: jsonRpcRequestId++
});
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);
var address = rpcResponse.result;
console.log("Created contract, address: " + address);
finalizeDeployment(deploymentId, address);
} else {
var errorText = qsTr("Deployment error: RPC server HTTP status ") + http.status;
console.log(errorText);
deploymentError(errorText);
}
}
}
httpRequest.send(rpcRequest);
}
function finalizeDeployment(deploymentId, address) {
//create a dir for frontend files and copy them
var deploymentDir = projectPath + deploymentId + "/";
fileIo.makeDir(deploymentDir);
for (var i = 0; i < projectListModel.count; i++) {
var doc = projectListModel.get(i);
if (doc.isContract)
continue;
if (doc.isHtml) {
//inject the script to access contract API
//TODO: use a template
var html = fileIo.readFile(doc.path);
var insertAt = html.indexOf("<head>")
if (insertAt < 0)
insertAt = 0;
else
insertAt += 6;
html = html.substr(0, insertAt) +
"<script src=\"bignumber.min.js\"></script>" +
"<script src=\"ethereum.js\"></script>" +
"<script src=\"deployment.js\"></script>" +
html.substr(insertAt);
fileIo.writeFile(deploymentDir + doc.fileName, html);
}
else
fileIo.copyFile(doc.path, deploymentDir + doc.fileName);
}
//write deployment js
var deploymentJs =
"// Autogenerated by Mix\n" +
"var web3 = require(\"web3\");\n" +
"var contractInterface = " + codeModel.code.contractInterface + ";\n" +
"deployment = {\n" +
"\tweb3: web3,\n" +
"\tcontractAddress: \"" + address + "\",\n" +
"\tcontractInterface: contractInterface,\n" +
"};\n" +
"deplyment.contract = web3.eth.contract(deplyment.contractAddress, deployment.contractInterface);\n";
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
//copy scripts
fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js");
fileIo.copyFile("qrc:///js/webthree.js", deploymentDir + "ethereum.js");
saveProject();
deploymentComplete();
}

13
mix/qml/main.qml

@ -42,6 +42,8 @@ ApplicationWindow {
MenuSeparator {}
MenuItem { action: editStatesAction }
MenuSeparator {}
MenuItem { action: deployViaRpcAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
}
Menu {
@ -265,7 +267,7 @@ ApplicationWindow {
selectFolder: false
onAccepted: {
var paths = addExistingFileDialog.fileUrls;
projectModel.doAddExistingFiles(paths);
projectModel.addExistingFiles(paths);
}
}
@ -301,4 +303,13 @@ ApplicationWindow {
onTriggered: projectModel.openPrevDocument();
}
Action {
id: deployViaRpcAction
text: qsTr("Deploy to Network")
shortcut: "Ctrl+Shift+D"
enabled: !projectModel.isEmpty && codeModel.hasContract
onTriggered: projectModel.deployProject();
}
}

Loading…
Cancel
Save