diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index c42cddc4f..674509b53 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -131,6 +131,7 @@ Main::Main(QWidget *parent) : connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); + m_ldb = new QLDB(this); connect(ui->webView, &QWebView::loadStarted, [this]() { @@ -138,8 +139,8 @@ Main::Main(QWidget *parent) : m_whisper = nullptr; // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_dev = new QDev(this); - m_ethereum = new QEthereum(this, ethereum(), owned()); - m_whisper = new QWhisper(this, whisper()); + m_ethereum = new QEthereum(this, ethereum(), m_myKeys); + m_whisper = new QWhisper(this, whisper(), owned()); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebFrame* f = ui->webView->page()->mainFrame(); @@ -147,8 +148,9 @@ Main::Main(QWidget *parent) : auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); - connect(m_whisper, SIGNAL(idsChanged()), this, SLOT(refreshWhisper())); + auto qldb = m_ldb; + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb)); + connect(m_whisper, SIGNAL(newIdToAdd(QString)), this, SLOT(addNewId(QString))); }); connect(ui->webView, &QWebView::loadFinished, [=]() @@ -183,11 +185,20 @@ Main::~Main() // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // *after* the client is dead. m_ethereum->clientDieing(); + m_whisper->faceDieing(); g_logPost = simpleDebugOut; writeSettings(); } +void Main::addNewId(QString _ids) +{ + Secret _id = toSecret(_ids); + KeyPair kp(_id); + m_myIdentities.push_back(kp); + m_whisper->setIdentities(owned()); +} + dev::p2p::NetworkPreferences Main::netPrefs() const { return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); @@ -494,15 +505,28 @@ void Main::on_paranoia_triggered() void Main::writeSettings() { QSettings s("ethereum", "alethzero"); - QByteArray b; - b.resize(sizeof(Secret) * m_myKeys.size()); - auto p = b.data(); - for (auto i: m_myKeys) { - memcpy(p, &(i.secret()), sizeof(Secret)); - p += sizeof(Secret); + QByteArray b; + b.resize(sizeof(Secret) * m_myKeys.size()); + auto p = b.data(); + for (auto i: m_myKeys) + { + memcpy(p, &(i.secret()), sizeof(Secret)); + p += sizeof(Secret); + } + s.setValue("address", b); + } + { + QByteArray b; + b.resize(sizeof(Secret) * m_myIdentities.size()); + auto p = b.data(); + for (auto i: m_myIdentities) + { + memcpy(p, &(i.secret()), sizeof(Secret)); + p += sizeof(Secret); + } + s.setValue("identities", b); } - s.setValue("address", b); s.setValue("upnp", ui->upnp->isChecked()); s.setValue("forceAddress", ui->forceAddress->text()); @@ -538,21 +562,39 @@ void Main::readSettings(bool _skipGeometry) restoreGeometry(s.value("geometry").toByteArray()); restoreState(s.value("windowState").toByteArray()); - m_myKeys.clear(); - QByteArray b = s.value("address").toByteArray(); - if (b.isEmpty()) - m_myKeys.append(KeyPair::create()); - else { - h256 k; - for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + m_myKeys.clear(); + QByteArray b = s.value("address").toByteArray(); + if (b.isEmpty()) + m_myKeys.append(KeyPair::create()); + else { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) - m_myKeys.append(KeyPair(k)); + h256 k; + for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + { + memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) + m_myKeys.append(KeyPair(k)); + } } + ethereum()->setAddress(m_myKeys.back().address()); } - ethereum()->setAddress(m_myKeys.back().address()); + + { + m_myIdentities.clear(); + QByteArray b = s.value("identities").toByteArray(); + if (!b.isEmpty()) + { + h256 k; + for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + { + memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) + m_myIdentities.append(KeyPair(k)); + } + } + } + m_peers = s.value("peers").toByteArray(); ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->forceAddress->setText(s.value("forceAddress", "").toString()); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b6c4c85e1..8905e53dc 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -77,7 +77,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } - QList const& owned() const { return m_myKeys; } + QList owned() const { return m_myIdentities + m_myKeys; } public slots: void load(QString _file); @@ -153,9 +153,11 @@ private slots: void on_newIdentity_triggered(); void refreshWhisper(); + void addNewId(QString); signals: void poll(); + void idsChanged(); private: dev::p2p::NetworkPreferences netPrefs() const; @@ -179,6 +181,8 @@ private: void readSettings(bool _skipGeometry = false); void writeSettings(); + void keysChanged(); + bool isCreation() const; dev::u256 fee() const; dev::u256 total() const; @@ -189,8 +193,6 @@ private: unsigned installWatch(dev::h256 _tf, std::function const& _f); void uninstallWatch(unsigned _w); - void keysChanged(); - void onNewPending(); void onNewBlock(); void onNameRegChange(); @@ -228,6 +230,7 @@ private: QByteArray m_peers; QStringList m_servers; QList m_myKeys; + QList m_myIdentities; QString m_privateChain; dev::bytes m_data; dev::Address m_nameReg; @@ -255,4 +258,5 @@ private: QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; + QLDB* m_ldb = nullptr; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b2d56c7d1..2af4d2808 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -369,7 +369,7 @@ void Host::populateAddresses() shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); - if (_a.port() < 30300 && _a.port() > 30303) + if (_a.port() < 30300 || _a.port() > 30303) cwarn << "Wierd port being recorded!"; if (_a.port() >= /*49152*/32768) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 535c43325..a13559ec5 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -1,3 +1,25 @@ +/* + 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 . +*/ +/** @file QEthereum.cpp + * @author Gav Wood + * @date 2014 + */ + +#include #include #include #include @@ -536,8 +558,9 @@ void QEthereum::poll() // TODO: repot and hook all these up. -QWhisper::QWhisper(QObject* _p, std::shared_ptr const& _c): QObject(_p), m_face(_c) +QWhisper::QWhisper(QObject* _p, std::shared_ptr const& _c, QList _ids): QObject(_p), m_face(_c) { + setIdentities(_ids); } QWhisper::~QWhisper() @@ -613,6 +636,14 @@ void QWhisper::doPost(QString _json) face()->inject(toSealed(_json, m, from)); } +void QWhisper::setIdentities(QList const& _l) +{ + m_ids.clear(); + for (auto i: _l) + m_ids[i.pub()] = i.secret(); + emit idsChanged(); +} + static pair toWatch(QString _json) { shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); @@ -714,11 +745,18 @@ QString QWhisper::newIdentity() Public QWhisper::makeIdentity() { KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.sec(); - emit idsChanged(); + emit newIdToAdd(toQJS(kp.sec())); return kp.pub(); } +QString QWhisper::createGroup(QString _json) +{ +} + +QString QWhisper::addToGroup(QString _group, QString _who) +{ +} + void QWhisper::poll() { for (auto const& w: m_watches) @@ -740,6 +778,51 @@ void QWhisper::poll() } } +#include + +QLDB::QLDB(QObject* _p): QObject(_p) +{ + auto path = getDataDir() + "/.web3"; + boost::filesystem::create_directories(path); + ldb::Options o; + o.create_if_missing = true; + ldb::DB::Open(o, path, &m_db); +} + +QLDB::~QLDB() +{ +} + +void QLDB::put(QString _p, QString _k, QString _v) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + bytes v = toBytes(_v); + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +QString QLDB::get(QString _p, QString _k) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return toQJS(dev::asBytes(ret)); +} + +void QLDB::putString(QString _p, QString _k, QString _v) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string v = _v.toStdString(); + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +QString QLDB::getString(QString _p, QString _k) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return QString::fromStdString(ret); +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 9866a4e7a..042b3c081 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -1,11 +1,39 @@ +/* + 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 . +*/ +/** @file QEthereum.h + * @author Gav Wood + * @date 2014 + */ + #pragma once +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) + #include #include #include #include #include +namespace ldb = leveldb; + namespace dev { namespace eth { class Interface; @@ -214,12 +242,14 @@ class QWhisper: public QObject Q_OBJECT public: - QWhisper(QObject* _p, std::shared_ptr const& _c); + QWhisper(QObject* _p, std::shared_ptr const& _c, QList _ids); virtual ~QWhisper(); std::shared_ptr face() const; void setFace(std::shared_ptr const& _c) { m_face = _c; } + void setIdentities(QList const& _l); + /// Call when the face() is going to be deleted to make this object useless but safe. void faceDieing(); @@ -230,6 +260,9 @@ public: Q_INVOKABLE QString newIdentity(); + Q_INVOKABLE QString newGroup(QString _id, QString _who); + Q_INVOKABLE QString addToGroup(QString _group, QString _who); + // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); @@ -247,6 +280,7 @@ public slots: signals: void watchChanged(unsigned _w, QString _envelopeJson); void idsChanged(); + void newIdToAdd(QString _id); private: std::weak_ptr m_face; @@ -255,16 +289,41 @@ private: std::map m_ids; }; +class QLDB: public QObject +{ + Q_OBJECT + +public: + QLDB(QObject* _p); + ~QLDB(); + + Q_INVOKABLE void put(QString _name, QString _key, QString _value); + Q_INVOKABLE QString get(QString _name, QString _key); + Q_INVOKABLE void putString(QString _name, QString _key, QString _value); + Q_INVOKABLE QString getString(QString _name, QString _key); + +private: + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + + ldb::DB* m_db; +}; + // TODO: add p2p object -#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh) [_frame, _env, _web3, _eth, _shh]() \ +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh, _ldb) [_frame, _env, _web3, _eth, _shh, _ldb]() \ { \ _frame->disconnect(); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \ + if (_ldb) \ + { \ + _frame->addToJavaScriptWindowObject("_web3_dot_db", _ldb, QWebFrame::QtOwnership); \ + _frame->evaluateJavaScript("web3.db = _web3_dot_db"); \ + } \ if (_eth) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_eth", _eth, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(this.w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_eth.watch = function(a) { return _web3_dot_eth.makeWatch(JSON.stringify(a)) }"); \ _frame->evaluateJavaScript("_web3_dot_eth.transact = function(a, f) { var r = _web3_dot_eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ _frame->evaluateJavaScript("_web3_dot_eth.call = function(a, f) { var ret = _web3_dot_eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ @@ -277,7 +336,7 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(ww)); for (var e in existing) f(existing[e]) }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(this.w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(this.w)); for (var e in existing) f(existing[e]) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ diff --git a/third/MainWin.cpp b/third/MainWin.cpp index dd5b01733..1af1de7fc 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -102,19 +102,22 @@ Main::Main(QWidget *parent) : m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"})); m_web3->connect(Host::pocHost()); + m_ldb = new QLDB(this); + connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_dev = new QDev(this); - m_ethereum = new QEthereum(this, ethereum(), owned()); - m_whisper = new QWhisper(this, whisper()); + m_ethereum = new QEthereum(this, ethereum(), m_myKeys); + m_whisper = new QWhisper(this, whisper(), owned()); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); + auto qldb = m_ldb; + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/third/MainWin.h b/third/MainWin.h index 0122cc257..3fa848439 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -61,8 +61,8 @@ public: dev::eth::Client* ethereum() const; std::shared_ptr whisper() const; - QList const& owned() const { return m_myKeys; } - + QList owned() const { return m_myKeys + m_myIdentities; } + public slots: void note(QString _entry); void debug(QString _entry); @@ -121,6 +121,7 @@ private: std::unique_ptr m_web3; QList m_myKeys; + QList m_myIdentities; std::map> m_handlers; unsigned m_nameRegFilter = (unsigned)-1; @@ -135,4 +136,5 @@ private: QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; + QLDB* m_ldb = nullptr; };