Browse Source

DApp load in AZ

cl-refactor
arkpar 10 years ago
committed by arkpar
parent
commit
91d453db92
  1. 1
      alethzero/CMakeLists.txt
  2. 141
      alethzero/DappHost.cpp
  3. 58
      alethzero/DappHost.h
  4. 203
      alethzero/DappLoader.cpp
  5. 94
      alethzero/DappLoader.h
  6. 71
      alethzero/MainWin.cpp
  7. 14
      alethzero/MainWin.h
  8. 4
      alethzero/Transact.cpp
  9. 29
      alethzero/WebPage.cpp
  10. 37
      alethzero/WebPage.h
  11. 2
      mix/FileIo.cpp
  12. 20
      mix/qml/js/ProjectModel.js

1
alethzero/CMakeLists.txt

@ -56,6 +56,7 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec) target_link_libraries(${EXECUTABLE} natspec)
target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES})
if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"))
target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} serpent)

141
alethzero/DappHost.cpp

@ -0,0 +1,141 @@
/*
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 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/>.
*/
/** @file DappHost.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include <microhttpd.h>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
#include <QUrl>
#include "DappHost.h"
using namespace dev;
DappHost::DappHost(int _port, int _threads):
m_port(_port), m_threads(_threads), m_running(false), m_daemon(nullptr)
{
startListening();
}
DappHost::~DappHost()
{
stopListening();
}
void DappHost::startListening()
{
if(!this->m_running)
{
this->m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, this->m_port, nullptr, nullptr, &DappHost::callback, this, MHD_OPTION_THREAD_POOL_SIZE, this->m_threads, MHD_OPTION_END);
if (this->m_daemon != nullptr)
this->m_running = true;
}
}
void DappHost::stopListening()
{
if(this->m_running)
{
MHD_stop_daemon(this->m_daemon);
this->m_running = false;
}
}
void DappHost::sendOptionsResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
//MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");
MHD_add_response_header(result, "Access-Control-Allow-Headers", "origin, content-type, accept");
MHD_add_response_header(result, "DAV", "1");
MHD_queue_response(_connection, MHD_HTTP_OK, result);
MHD_destroy_response(result);
}
void DappHost::sendNotAllowedResponse(MHD_Connection* _connection)
{
MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1);
MHD_add_response_header(result, "Allow", "GET, OPTIONS");
MHD_queue_response(_connection, MHD_HTTP_METHOD_NOT_ALLOWED, result);
MHD_destroy_response(result);
}
void DappHost::sendResponse(std::string const& _url, MHD_Connection* _connection)
{
QUrl requestUrl(QString::fromStdString(_url));
QString path = requestUrl.path().toLower();
if (path.isEmpty())
path = "/";
bytesConstRef response;
unsigned code = MHD_HTTP_NOT_FOUND;
std::string contentType;
while (!path.isEmpty())
{
auto iter = m_entriesByPath.find(path);
if (iter != m_entriesByPath.end())
{
ManifestEntry const* entry = iter->second;
auto contentIter = m_dapp.content.find(entry->hash);
if (contentIter == m_dapp.content.end())
break;
response = bytesConstRef(contentIter->second.data(), contentIter->second.size());
code = entry->httpStatus != 0 ? entry->httpStatus : MHD_HTTP_OK;
contentType = entry->contentType;
break;
}
path.truncate(path.length() - 1);
path = path.mid(0, path.lastIndexOf('/'));
}
MHD_Response *result = MHD_create_response_from_data(response.size(), const_cast<byte*>(response.data()), 0, 1);
if (!contentType.empty())
MHD_add_response_header(result, "Content-Type", contentType.c_str());
//MHD_add_response_header(result, "Access-Control-Allow-Origin", "*");
MHD_queue_response(_connection, code, result);
MHD_destroy_response(result);
}
int DappHost::callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls)
{
(void)_version;
(void)_uploadData;
(void)_uploadDataSize;
(void)_conCls;
DappHost* host = static_cast<DappHost*>(_cls);
if (std::string("GET") == _method)
host->sendResponse(std::string(_url), _connection);
else if (std::string("OPTIONS") == _method)
host->sendOptionsResponse(_connection);
else
host->sendNotAllowedResponse(_connection);
return MHD_YES;
}
QUrl DappHost::hostDapp(Dapp&& _dapp)
{
m_dapp = std::move(_dapp);
m_entriesByPath.clear();
for (ManifestEntry const& entry: m_dapp.manifest.entries)
m_entriesByPath[QString::fromStdString(entry.path)] = &entry;
return QUrl(QString("http://localhost:%1/").arg(m_port));
}

58
alethzero/DappHost.h

@ -0,0 +1,58 @@
/*
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 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/>.
*/
/** @file DappHost.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <QUrl>
#include <QString>
#include "DappLoader.h"
struct MHD_Daemon;
struct MHD_Connection;
/// DApp web server. Servers web content, resolves paths by hashes
class DappHost
{
public:
/// @param _port Network pork to listen for incoming connections
/// @param _threads Max number of threads to process requests
DappHost(int _port, int _threads = 10);
virtual ~DappHost();
/// Load and host a dapp. Previsous dapp in discarded. Synchronous
QUrl hostDapp(Dapp&& _dapp);
private:
void startListening();
void stopListening();
void sendOptionsResponse(MHD_Connection* _connection);
void sendNotAllowedResponse(MHD_Connection* _connection);
void sendResponse(std::string const& _url, MHD_Connection* _connection);
static int callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls);
int m_port;
int m_threads;
bool m_running;
MHD_Daemon* m_daemon;
Dapp m_dapp;
std::map<QString, ManifestEntry const*> m_entriesByPath;
};

203
alethzero/DappLoader.cpp

@ -0,0 +1,203 @@
/*
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 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/>.
*/
/** @file DappLoader.cpp
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#include <algorithm>
#include <json/json.h>
#include <QUrl>
#include <QStringList>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/SHA3.h>
#include <libethcore/CommonJS.h>
#include <libethereum/Client.h>
#include <libwebthree/WebThree.h>
#include "DappLoader.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::crypto;
Address c_registrar = Address("0000000000000000000000000000000000000a28");
Address c_urlHint = Address("0000000000000000000000000000000000000a29");
QString contentsOfQResource(std::string const& res);
DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3):
QObject(_parent), m_web3(_web3)
{
connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete);
}
DappLocation DappLoader::resolveAppUri(QString const& _uri)
{
QUrl url(_uri);
if (!url.scheme().isEmpty() && url.scheme() != "eth")
throw dev::Exception(); //TODO:
QStringList parts = url.host().split('.', QString::SkipEmptyParts);
QStringList domainParts;
std::reverse(parts.begin(), parts.end());
parts.append(url.path().split('/', QString::SkipEmptyParts));
Address address = c_registrar;
Address lastAddress;
int partIndex = 0;
h256 contentHash;
while (address && partIndex < parts.length())
{
lastAddress = address;
string32 name = { 0 };
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
address = abiOut<Address>(web3()->ethereum()->call(address, abiIn("addr(string32)", name)));
domainParts.append(parts[partIndex]);
if (!address)
{
//we have the address of the last part, try to get content hash
contentHash = abiOut<h256>(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)));
if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address");
}
++partIndex;
}
string32 contentUrl = abiOut<string32>(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)));
QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/');
QString contentUrlString = QString::fromUtf8(std::string(contentUrl.data(), contentUrl.size()).c_str());
if (!contentUrlString.startsWith("http://") || !contentUrlString.startsWith("https://"))
contentUrlString = "http://" + contentUrlString;
return DappLocation { domain, path, contentUrlString, contentHash };
}
void DappLoader::downloadComplete(QNetworkReply* _reply)
{
try
{
//try to interpret as rlp
QByteArray data = _reply->readAll();
_reply->deleteLater();
h256 expected = m_uriHashes[_reply->request().url()];
bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
Secp256k1 dec;
dec.decrypt(expected, package);
h256 got = sha3(package);
if (got != expected)
{
//try base64
data = QByteArray::fromBase64(data);
package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
dec.decrypt(expected, package);
got = sha3(package);
if (got != expected)
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
RLP rlp(package);
loadDapp(rlp);
}
catch (...)
{
qWarning() << tr("Error downloading DApp: ") << boost::current_exception_diagnostic_information().c_str();
emit dappError();
}
}
void DappLoader::loadDapp(RLP const& _rlp)
{
Dapp dapp;
unsigned len = _rlp.itemCountStrict();
dapp.manifest = loadManifest(_rlp[0].toString());
for (unsigned c = 1; c < len; ++c)
{
bytesConstRef content = _rlp[c].toBytesConstRef();
h256 hash = sha3(content);
auto entry = std::find_if(dapp.manifest.entries.cbegin(), dapp.manifest.entries.cend(), [=](ManifestEntry const& _e) { return _e.hash == hash; });
if (entry != dapp.manifest.entries.cend())
{
if (entry->path == "/deployment.js")
{
//inject web3 code
QString code;
code += contentsOfQResource(":/js/bignumber.min.js");
code += "\n";
code += contentsOfQResource(":/js/webthree.js");
code += "\n";
code += contentsOfQResource(":/js/setup.js");
code += "\n";
QByteArray res = code.toLatin1();
bytes b(res.data(), res.data() + res.size());
b.insert(b.end(), content.begin(), content.end());
dapp.content[hash] = b;
}
else
dapp.content[hash] = content.toBytes();
}
else
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
}
emit dappReady(dapp);
}
Manifest DappLoader::loadManifest(std::string const& _manifest)
{
/// https://github.com/ethereum/go-ethereum/wiki/URL-Scheme
Manifest manifest;
Json::Reader jsonReader;
Json::Value root;
jsonReader.parse(_manifest, root, false);
Json::Value entries = root["entries"];
for (Json::ValueIterator it = entries.begin(); it != entries.end(); ++it)
{
Json::Value const& entryValue = *it;
std::string path = entryValue["path"].asString();
if (path.size() == 0 || path[0] != '/')
path = "/" + path;
std::string contentType = entryValue["contentType"].asString();
std::string strHash = entryValue["hash"].asString();
if (strHash.length() == 64)
strHash = "0x" + strHash;
h256 hash = jsToFixed<32>(strHash);
unsigned httpStatus = entryValue["status"].asInt();
manifest.entries.push_back(ManifestEntry{ path, hash, contentType, httpStatus });
}
return manifest;
}
void DappLoader::loadDapp(QString const& _uri)
{
DappLocation location = resolveAppUri(_uri);
QUrl uri(location.contentUri);
QNetworkRequest request(uri);
m_uriHashes[uri] = location.contentHash;
m_net.get(request);
}

94
alethzero/DappLoader.h

@ -0,0 +1,94 @@
/*
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 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/>.
*/
/** @file DappLoader.h
* @author Arkadiy Paronyan <arkadiy@ethdev.org>
* @date 2015
*/
#pragma once
#include <map>
#include <string>
#include <vector>
#include <QObject>
#include <QString>
#include <QUrl>
#include <QNetworkAccessManager>
#include <libdevcore/FixedHash.h>
namespace dev
{
class WebThreeDirect;
class RLP;
}
struct ManifestEntry
{
std::string path;
dev::h256 hash;
std::string contentType;
unsigned httpStatus;
};
struct Manifest
{
std::vector<ManifestEntry> entries;
};
struct Dapp
{
Manifest manifest;
std::map<dev::h256, dev::bytes> content;
};
struct DappLocation
{
QString canonDomain;
QString path;
QString contentUri;
dev::h256 contentHash;
};
///Downloads, unpacks and prepares DApps for hosting
class DappLoader: public QObject
{
Q_OBJECT
public:
DappLoader(QObject* _parent, dev::WebThreeDirect* _web3);
///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise
///@param _uri Eth name path
void loadDapp(QString const& _uri);
signals:
void dappReady(Dapp& _dapp);
void dappError();
private slots:
void downloadComplete(QNetworkReply* _reply);
private:
dev::WebThreeDirect* web3() const { return m_web3; }
DappLocation resolveAppUri(QString const& _uri);
void loadDapp(dev::RLP const& _rlp);
Manifest loadManifest(std::string const& _manifest);
dev::WebThreeDirect* m_web3;
QNetworkAccessManager m_net;
std::map<QUrl, dev::h256> m_uriHashes;
};

71
alethzero/MainWin.cpp

@ -19,7 +19,6 @@
* @date 2014 * @date 2014
*/ */
#define QWEBENGINEINSPECTOR 1
#include <fstream> #include <fstream>
// Make sure boost/asio.hpp is included before windows.h. // Make sure boost/asio.hpp is included before windows.h.
@ -68,6 +67,9 @@
#include "OurWebThreeStubServer.h" #include "OurWebThreeStubServer.h"
#include "Transact.h" #include "Transact.h"
#include "Debugger.h" #include "Debugger.h"
#include "DappLoader.h"
#include "DappHost.h"
#include "WebPage.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -116,7 +118,9 @@ Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
Main::Main(QWidget *parent) : Main::Main(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::Main), ui(new Ui::Main),
m_transact(this, this) m_transact(this, this),
m_dappLoader(nullptr),
m_webPage(nullptr)
{ {
QtWebEngine::initialize(); QtWebEngine::initialize();
setWindowFlags(Qt::Window); setWindowFlags(Qt::Window);
@ -166,10 +170,12 @@ Main::Main(QWidget *parent) :
m_server->setIdentities(keysAsVector(owned())); m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening(); m_server->StartListening();
WebPage* webPage= new WebPage(this);
m_webPage = webPage;
connect(webPage, &WebPage::consoleMessage, [this](QString const& _msg) { Main::addConsoleMessage(_msg, QString()); });
ui->webView->setPage(m_webPage);
connect(ui->webView, &QWebEngineView::loadFinished, [this]() connect(ui->webView, &QWebEngineView::loadFinished, [this]()
{ {
// f->disconnect();
// f->addToJavaScriptWindowObject("env", this, QWebFrame::QtOwnership);
auto f = ui->webView->page(); auto f = ui->webView->page();
f->runJavaScript(contentsOfQResource(":/js/bignumber.min.js")); f->runJavaScript(contentsOfQResource(":/js/bignumber.min.js"));
f->runJavaScript(contentsOfQResource(":/js/webthree.js")); f->runJavaScript(contentsOfQResource(":/js/webthree.js"));
@ -181,6 +187,9 @@ Main::Main(QWidget *parent) :
ui->tabWidget->setTabText(0, ui->webView->title()); ui->tabWidget->setTabText(0, ui->webView->title());
}); });
m_dappHost.reset(new DappHost(8081));
m_dappLoader = new DappLoader(this, web3());
connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded);
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
@ -425,13 +434,7 @@ void Main::eval(QString const& _js)
s = "<span style=\"color: #840\">" + jsonEv.toString().toHtmlEscaped() + "</span>"; s = "<span style=\"color: #840\">" + jsonEv.toString().toHtmlEscaped() + "</span>";
else else
s = "<span style=\"color: #888\">unknown type</span>"; s = "<span style=\"color: #888\">unknown type</span>";
m_consoleHistory.push_back(qMakePair(_js, s)); addConsoleMessage(_js, s);
s = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
s += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
s += "</div></body></html>";
ui->jsConsole->setHtml(s);
}; };
ui->webView->page()->runJavaScript("JSON.stringify(___RET)", f2); ui->webView->page()->runJavaScript("JSON.stringify(___RET)", f2);
}; };
@ -439,6 +442,17 @@ void Main::eval(QString const& _js)
ui->webView->page()->runJavaScript(c, f); ui->webView->page()->runJavaScript(c, f);
} }
void Main::addConsoleMessage(QString const& _js, QString const& _s)
{
m_consoleHistory.push_back(qMakePair(_js, _s));
QString r = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory)
r += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
r += "</div></body></html>";
ui->jsConsole->setHtml(r);
}
static Public stringToPublic(QString const& _a) static Public stringToPublic(QString const& _a)
{ {
string sn = _a.toStdString(); string sn = _a.toStdString();
@ -780,15 +794,28 @@ void Main::on_jitvm_triggered()
void Main::on_urlEdit_returnPressed() void Main::on_urlEdit_returnPressed()
{ {
QString s = ui->urlEdit->text(); QString s = ui->urlEdit->text();
QRegExp r("([a-z]+://)?([^/]*)(.*)"); QUrl url(s);
if (r.exactMatch(s)) if (url.scheme().isEmpty() || url.scheme() == "eth")
if (r.cap(2).isEmpty()) {
s = (r.cap(1).isEmpty() ? "file://" : r.cap(1)) + r.cap(3); try
{
//try do resolve dapp url
m_dappLoader->loadDapp(s);
}
catch (...)
{
qWarning() << boost::current_exception_diagnostic_information().c_str();
}
}
if (url.scheme().isEmpty())
if (url.path().indexOf('/') < url.path().indexOf('.'))
url.setScheme("file");
else else
s = (r.cap(1).isEmpty() ? "http://" : r.cap(1)) + lookup(r.cap(2)) + r.cap(3); url.setScheme("http");
else{} else {}
qDebug() << s; qDebug() << url.toString();
ui->webView->setUrl(s); ui->webView->page()->setUrl(url);
} }
void Main::on_nameReg_textChanged() void Main::on_nameReg_textChanged()
@ -1835,3 +1862,9 @@ void Main::refreshWhispers()
ui->whispers->addItem(item); ui->whispers->addItem(item);
} }
} }
void Main::dappLoaded(Dapp& _dapp)
{
QUrl url = m_dappHost->hostDapp(std::move(_dapp));
ui->webView->page()->setUrl(url);
}

14
alethzero/MainWin.h

@ -54,8 +54,11 @@ namespace jsonrpc {
class HttpServer; class HttpServer;
} }
class QQuickView; class QWebEnginePage;
class OurWebThreeStubServer; class OurWebThreeStubServer;
class DappLoader;
class DappHost;
struct Dapp;
using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>; using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>;
@ -99,6 +102,7 @@ public slots:
private slots: private slots:
void eval(QString const& _js); void eval(QString const& _js);
void addConsoleMessage(QString const& _js, QString const& _s);
// Application // Application
void on_about_triggered(); void on_about_triggered();
@ -172,6 +176,9 @@ private slots:
void refreshBlockChain(); void refreshBlockChain();
void addNewId(QString _ids); void addNewId(QString _ids);
// Dapps
void dappLoaded(Dapp& _dapp); //qt does not support rvalue refs for signals
signals: signals:
void poll(); void poll();
@ -234,8 +241,6 @@ private:
QString m_privateChain; QString m_privateChain;
dev::Address m_nameReg; dev::Address m_nameReg;
QNetworkAccessManager m_webCtrl;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;
QString m_logHistory; QString m_logHistory;
@ -248,4 +253,7 @@ private:
NatspecHandler m_natSpecDB; NatspecHandler m_natSpecDB;
Transact m_transact; Transact m_transact;
std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader;
QWebEnginePage* m_webPage;
}; };

4
alethzero/Transact.cpp

@ -175,7 +175,7 @@ void Transact::rejigData()
m_data = fromHex(src); m_data = fromHex(src);
else if (sourceIsSolidity(src)) else if (sourceIsSolidity(src))
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler(true);
try try
{ {
// compiler.addSources(dev::solidity::StandardSources); // compiler.addSources(dev::solidity::StandardSources);
@ -287,7 +287,7 @@ void Transact::on_send_clicked()
if (sourceIsSolidity(src)) if (sourceIsSolidity(src))
try try
{ {
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler(true);
m_data = compiler.compile(src, ui->optimize->isChecked()); m_data = compiler.compile(src, ui->optimize->isChecked());
for (string const& s: compiler.getContractNames()) for (string const& s: compiler.getContractNames())
{ {

29
alethzero/WebPage.cpp

@ -0,0 +1,29 @@
/*
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 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/>.
*/
/** @file WebPage.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#pragma GCC diagnostic ignored "-Wpedantic" //QtWebEngineWidgets/qwebenginecertificateerror.h:78:348: error: extra ';'
#include "WebPage.h"
void WebPage::javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID)
{
QString prefix = _level == QWebEnginePage::ErrorMessageLevel ? "error" : _level == QWebEnginePage::WarningMessageLevel ? "warning" : "";
emit consoleMessage(QString("%1(%2:%3):%4").arg(prefix).arg(_sourceID).arg(_lineNumber).arg(_message));
}

37
alethzero/WebPage.h

@ -0,0 +1,37 @@
/*
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 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/>.
*/
/** @file WebPage.h
* @author Arkadiy Paronyan arkadiy@ethdev.com>
* @date 2015
*/
#pragma once
#include <QString>
#include <QtWebEngineWidgets/QWebEnginePage>
class WebPage: public QWebEnginePage
{
Q_OBJECT
public:
WebPage(QObject* _parent): QWebEnginePage(_parent) { }
signals:
void consoleMessage(QString const& _msg);
protected:
void javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _level, const QString& _message, int _lineNumber, const QString& _sourceID) override;
};

2
mix/FileIo.cpp

@ -158,6 +158,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
} }
rlpStr.appendList(k); rlpStr.appendList(k);
manifest["entries"] = entries;
std::stringstream jsonStr; std::stringstream jsonStr;
jsonStr << manifest; jsonStr << manifest;
QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8();
@ -166,7 +167,6 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
for (unsigned int k = 0; k < files.size(); k++) for (unsigned int k = 0; k < files.size(); k++)
rlpStr.append(files.at(k)); rlpStr.append(files.at(k));
manifest["entries"] = entries;
bytes dapp = rlpStr.out(); bytes dapp = rlpStr.out();
dev::h256 dappHash = dev::sha3(dapp); dev::h256 dappHash = dev::sha3(dapp);
//encrypt //encrypt

20
mix/qml/js/ProjectModel.js

@ -377,8 +377,6 @@ function finalizeDeployment(deploymentId, addresses) {
else else
insertAt += 6; insertAt += 6;
html = html.substr(0, insertAt) + html = html.substr(0, insertAt) +
"<script src=\"bignumber.min.js\"></script>" +
"<script src=\"ethereum.js\"></script>" +
"<script src=\"deployment.js\"></script>" + "<script src=\"deployment.js\"></script>" +
html.substr(insertAt); html.substr(insertAt);
fileIo.writeFile(deploymentDir + doc.fileName, html); fileIo.writeFile(deploymentDir + doc.fileName, html);
@ -388,9 +386,8 @@ function finalizeDeployment(deploymentId, addresses) {
} }
//write deployment js //write deployment js
var deploymentJs = var deploymentJs =
"// Autogenerated by Mix\n" + "// Autogenerated by Mix\n" +
"web3 = require(\"web3\");\n" + "contracts = {};\n";
"contracts = {};\n";
for (var c in codeModel.contracts) { for (var c in codeModel.contracts) {
var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
deploymentJs += contractAccessor + " = {\n" + deploymentJs += contractAccessor + " = {\n" +
@ -400,9 +397,6 @@ function finalizeDeployment(deploymentId, addresses) {
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
} }
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); 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");
deploymentAddresses = addresses; deploymentAddresses = addresses;
saveProject(); saveProject();
@ -435,7 +429,7 @@ function checkEthPath(dappUrl, callBack)
//register() //register()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], params: [ { "gas": 150000, "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -472,7 +466,7 @@ function checkRegistration(dappUrl, addr, callBack)
//getOwner() //getOwner()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], params: [ { "gas" : 2000, "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -537,7 +531,7 @@ function checkRegistration(dappUrl, addr, callBack)
//setRegister() //setRegister()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
@ -570,7 +564,7 @@ function registerContentHash(registrar, callBack)
//setContent() //setContent()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", 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": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
@ -587,7 +581,7 @@ function registerToUrlHint()
//urlHint => suggestUrl //urlHint => suggestUrl
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 2000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 30000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });

Loading…
Cancel
Save