Browse Source

Merge remote-tracking branch 'upstream/develop' into develop

Conflicts:
	alethzero/MainWin.cpp
	libwebthree/WebThree.h
cl-refactor
Christoph Jentzsch 10 years ago
parent
commit
1bfbec8702
  1. 8
      alethzero/Main.ui
  2. 77
      alethzero/MainWin.cpp
  3. 6
      alethzero/MainWin.h
  4. 6
      libdevcrypto/Common.cpp
  5. 3
      libdevcrypto/Common.h
  6. 5
      libdevcrypto/CryptoHeaders.h
  7. 29
      libdevcrypto/SHA3.cpp
  8. 2
      libdevcrypto/SHA3.h
  9. 59
      libqethereum/QEthereum.cpp
  10. 55
      libqethereum/QEthereum.h
  11. 6
      libwebthree/WebThree.cpp
  12. 4
      libwebthree/WebThree.h
  13. 47
      libwhisper/Interface.cpp
  14. 132
      libwhisper/Interface.h
  15. 28
      libwhisper/Message.cpp
  16. 63
      libwhisper/Message.h
  17. 123
      libwhisper/WhisperHost.cpp
  18. 77
      libwhisper/WhisperHost.h
  19. 111
      libwhisper/WhisperPeer.cpp
  20. 154
      libwhisper/WhisperPeer.h
  21. 3
      libwhisper/_libwhisper.cpp
  22. 9
      third/MainWin.cpp
  23. 8
      third/MainWin.h

8
alethzero/Main.ui

@ -194,11 +194,6 @@
<addaction name="dumpTraceStorage"/>
<addaction name="dumpTracePretty"/>
</widget>
<widget class="QMenu" name="menuType_Here">
<property name="title">
<string>Type Here</string>
</property>
</widget>
<addaction name="debugCurrent"/>
<addaction name="menu_Dump_Trace"/>
<addaction name="separator"/>
@ -208,7 +203,6 @@
<addaction name="debugStepBack"/>
<addaction name="debugStepBackInto"/>
<addaction name="debugStepBackOut"/>
<addaction name="menuType_Here"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_View"/>
@ -1762,7 +1756,7 @@ font-size: 14pt</string>
</action>
<action name="importKeyFile">
<property name="text">
<string>Import Key &amp;File...</string>
<string>Claim Ether Presale &amp;Wallet...</string>
</property>
</action>
<action name="go">

77
alethzero/MainWin.cpp

@ -25,6 +25,7 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog>
#include <QtWebKitWidgets/QWebFrame>
#include <QWebSettings>
#include <QtGui/QClipboard>
#include <QtCore/QtCore>
#include <boost/algorithm/string.hpp>
@ -135,11 +136,14 @@ Main::Main(QWidget *parent) :
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qeth = m_ethereum;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, this));
auto qshh = m_whisper;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
@ -562,8 +566,7 @@ void Main::on_importKey_triggered()
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end())
{
m_myKeys.append(k);
m_keysChanged = true;
update();
keysChanged();
}
else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
@ -579,33 +582,40 @@ void Main::on_importKeyFile_triggered()
{
js::mValue val;
json_spirit::read_string(asString(contents(s.toStdString())), val);
js::mObject obj = val.get_obj();
KeyPair k;
auto obj = val.get_obj();
if (obj["encseed"].type() == js::str_type)
{
string encseedstr = obj["encseed"].get_str();
bytes encseed = fromHex(encseedstr);
Secret sec = sha3(encseed);
k = KeyPair(sec);
if (obj["ethaddr"].type() == js::str_type)
auto encseed = fromHex(obj["encseed"].get_str());
KeyPair k;
for (bool gotit = false; !gotit;)
{
gotit = true;
k = KeyPair::fromEncryptedSeed(&encseed, QInputDialog::getText(this, "Enter Password", "Enter the wallet's passphrase", QLineEdit::Password).toStdString());
if (obj["ethaddr"].type() == js::str_type)
{
Address a(obj["ethaddr"].get_str());
Address b = k.address();
if (a != b)
{
if (QMessageBox::warning(this, "Password Wrong", "Could not import the secret key: the password you gave appears to be wrong.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return;
else
gotit = false;
}
}
}
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end())
{
Address a(obj["ethaddr"].get_str());
Address b = k.address();
if (a != b && QMessageBox::warning(this, "Key File Invalid", "Could not import the secret key: it doesn't agree with the given address.\nWould you like to attempt to import anyway?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
m_myKeys.append(k);
keysChanged();
}
else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
}
else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("encseed type is not js::str_type") );
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end())
{
m_myKeys.append(k);
m_keysChanged = true;
update();
}
else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
}
catch (...)
{
@ -822,11 +832,7 @@ static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256
if (_f.size() > 1 && _f.size() < 10 && _f[0] == '#' && stoul(_f.substr(1)) == _b.number)
return true;
}
catch (...)
{
cerr << "Unhandled exception!" << endl <<
boost::current_exception_diagnostic_information();
}
catch (...) {}
if (toHex(_h.ref()).find(_f) != string::npos)
return true;
BlockInfo bi(_bc.block(_h));
@ -1285,14 +1291,6 @@ void Main::on_contracts_currentItemChanged()
{
ui->contractInfo->appendHtml("Corrupted trie.");
}
catch (dev::Exception &_e)
{
_e << dev::errinfo_comment("Could not get contract info.");
cerr << "Unhandled exception!" << endl <<
boost::diagnostic_information(_e);
throw;
}
ui->contractInfo->moveCursor(QTextCursor::Start);
}
}
@ -1603,6 +1601,11 @@ void Main::on_send_clicked()
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
void Main::keysChanged()
{
onBalancesChange();
}
void Main::on_debug_clicked()
{
debugFinished();
@ -1640,7 +1643,7 @@ void Main::on_debug_clicked()
void Main::on_create_triggered()
{
m_myKeys.append(KeyPair::create());
m_keysChanged = true;
keysChanged();
}
void Main::on_debugStep_triggered()

6
alethzero/MainWin.h

@ -75,7 +75,7 @@ public:
dev::WebThreeDirect* web3() const { return m_webThree.get(); }
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
dev::shh::WhisperHost* whisper() const { return m_webThree->whisper(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
QList<dev::KeyPair> const& owned() const { return m_myKeys; }
@ -184,6 +184,8 @@ private:
unsigned installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f);
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void keysChanged();
void onNewPending();
void onNewBlock();
void onNameRegChange();
@ -221,7 +223,6 @@ private:
QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QString m_privateChain;
bool m_keysChanged = false;
dev::bytes m_data;
dev::Address m_nameReg;
@ -246,4 +247,5 @@ private:
bool m_logChanged = true;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
};

6
libdevcrypto/Common.cpp

@ -102,3 +102,9 @@ KeyPair::KeyPair(h256 _sec):
cout << "ADR: " << m_address << endl;
#endif
}
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{
return KeyPair(sha3(aesDecrypt(_seed, _password)));
}

3
libdevcrypto/Common.h

@ -63,6 +63,9 @@ public:
/// Create a new, randomly generated object.
static KeyPair create();
/// Create from an encrypted seed.
static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const& _password);
/// Retrieve the secret key.
Secret const& secret() const { return m_secret; }
/// Retrieve the secret key.

5
libdevcrypto/CryptoHeaders.h

@ -28,9 +28,14 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#include <aes.h>
#include <pwdbased.h>
#include <modes.h>
#include <filters.h>
#include <secp256k1/secp256k1.h>
#pragma warning(pop)
#pragma GCC diagnostic pop

29
libdevcrypto/SHA3.cpp

@ -72,5 +72,34 @@ h256 sha3(bytesConstRef _input)
return ret;
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{
bytes pw = asBytes(_password);
if (!_salt.size())
_salt = &pw;
bytes target(64);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds);
try
{
CryptoPP::AES::Decryption aesDecryption(target.data(), 16);
auto cipher = _ivCipher.cropped(16);
auto iv = _ivCipher.cropped(0, 16);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
std::string decrypted;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted));
stfDecryptor.Put(cipher.data(), cipher.size());
stfDecryptor.MessageEnd();
return asBytes(decrypted);
}
catch (exception const& e)
{
cerr << e.what() << endl;
return bytes();
}
}
}
}

2
libdevcrypto/SHA3.h

@ -60,5 +60,7 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input))
extern h256 EmptySHA3;
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef());
}
}

59
libqethereum/QEthereum.cpp

@ -476,6 +476,65 @@ void QEthereum::poll()
emit watchChanged(w);
}
// TODO: repot and hook all these up.
QWhisper::QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c): QObject(_p), m_face(_c)
{
}
QWhisper::~QWhisper()
{
}
// probably want a better way of doing this. somehow guarantee that the face() will always be available as long as this object is.
struct NoInterface: public Exception {};
std::shared_ptr<dev::shh::Interface> QWhisper::face() const
{
auto ret = m_face.lock();
if (!ret)
throw NoInterface();
return ret;
}
void QWhisper::faceDieing()
{
}
void QWhisper::send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload)
{
(void)_dest;
(void)_from;
(void)_topic;
(void)_payload;
}
unsigned QWhisper::newWatch(QString _json)
{
(void)_json;
return 0;
}
QString QWhisper::watchMessages(unsigned _w)
{
(void)_w;
return "";
}
void QWhisper::killWatch(unsigned _w)
{
(void)_w;
}
void QWhisper::clearWatches()
{
}
void QWhisper::poll()
{
}
// extra bits needed to link on VS
#ifdef _MSC_VER

55
libqethereum/QEthereum.h

@ -6,9 +6,14 @@
#include <libdevcore/CommonIO.h>
#include <libethcore/CommonEth.h>
namespace dev { namespace eth {
namespace dev {
namespace eth {
class Interface;
}}
}
namespace shh {
class Interface;
}
}
class QJSEngine;
class QWebFrame;
@ -203,11 +208,51 @@ private:
QList<dev::KeyPair> m_accounts;
};
#define QETH_INSTALL_JS_NAMESPACE(frame, eth, env) [frame, eth, env]() \
class QWhisper: public QObject
{
Q_OBJECT
public:
QWhisper(QObject* _p, std::shared_ptr<dev::shh::Interface> const& _c);
virtual ~QWhisper();
std::shared_ptr<dev::shh::Interface> face() const;
void setFace(std::shared_ptr<dev::shh::Interface> const& _c) { m_face = _c; }
/// Call when the face() is going to be deleted to make this object useless but safe.
void faceDieing();
Q_INVOKABLE QWhisper* self() { return this; }
/// Basic message send.
Q_INVOKABLE void send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload);
// Watches interface
Q_INVOKABLE unsigned newWatch(QString _json);
Q_INVOKABLE QString watchMessages(unsigned _w);
Q_INVOKABLE void killWatch(unsigned _w);
void clearWatches();
public slots:
/// Check to see if anything has changed, fire off signals if so.
/// @note Must be called in the QObject's thread.
void poll();
signals:
void watchChanged(unsigned _w);
private:
std::weak_ptr<dev::shh::Interface> m_face;
std::vector<unsigned> m_watches;
};
#define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, env) [frame, eth, shh, env]() \
{ \
frame->disconnect(); \
frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \
frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \
frame->addToJavaScriptWindowObject("shh", eth, QWebFrame::ScriptOwnership); \
frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \
frame->evaluateJavaScript("eth.watchChain = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.watch('chain') INSTEAD.'); return eth.makeWatch('chain') }"); \
@ -224,8 +269,8 @@ private:
frame->evaluateJavaScript("String.prototype.dec = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toDecimal(this) }"); \
frame->evaluateJavaScript("String.prototype.fix = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toFixed(this) }"); \
frame->evaluateJavaScript("String.prototype.sha3 = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.sha3old(this) }"); \
frame->evaluateJavaScript("console.log = env.note"); \
frame->evaluateJavaScript("window.onerror = function (errorMsg, url, lineNumber, column, errorObj) { env.warn('Error: ' + errorMsg + ', Script: ' + url + ', Line: ' + lineNumber + ', Column: ' + column + ', StackTrace: ' + String(errorObj)) }"); \
frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \
}
template <unsigned N> inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> toInt(QString const& _s)

6
libwebthree/WebThree.cpp

@ -28,7 +28,7 @@
#include <libp2p/Host.h>
#include <libethereum/Defaults.h>
#include <libethereum/EthereumHost.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
@ -45,8 +45,8 @@ WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string co
if (_interfaces.count("eth"))
m_ethereum.reset(new eth::Client(&m_net, _dbPath, _forceClean));
// if (_interfaces.count("shh"))
// m_whisper = new eth::Whisper(m_net.get());
if (_interfaces.count("shh"))
m_whisper = m_net.registerCapability<WhisperHost>(new WhisperHost);
}
WebThreeDirect::~WebThreeDirect()

4
libwebthree/WebThree.h

@ -32,7 +32,7 @@
#include <libdevcore/Exceptions.h>
#include <libp2p/Host.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
#include <libethereum/Client.h>
namespace dev
@ -118,7 +118,7 @@ private:
std::string m_clientVersion; ///< Our end-application client's name/version.
std::unique_ptr<eth::Client> m_ethereum; ///< Main interface for Ethereum ("eth") protocol.
std::unique_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
std::weak_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
};

47
libwhisper/Interface.cpp

@ -0,0 +1,47 @@
/*
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 Interface.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Interface.h"
#include <libdevcore/Log.h>
#include <libp2p/All.h>
#include "WhisperHost.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
bool MessageFilter::matches(Message const& _m) const
{
for (auto const& t: m_topicMasks)
{
if (t.first.size() != t.second.size() || _m.topic.size() < t.first.size())
continue;
for (unsigned i = 0; i < t.first.size(); ++i)
if (((t.first[i] ^ _m.topic[i]) & t.second[i]) != 0)
goto NEXT;
return true;
NEXT:;
}
return false;
}

132
libwhisper/Interface.h

@ -0,0 +1,132 @@
/*
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 WhisperHost.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
#include "Message.h"
namespace dev
{
namespace shh
{
class MessageFilter
{
public:
MessageFilter() {}
MessageFilter(std::vector<std::pair<bytes, bytes> > const& _m): m_topicMasks(_m) {}
MessageFilter(RLP const& _r): m_topicMasks((std::vector<std::pair<bytes, bytes>>)_r) {}
void fillStream(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); }
bool matches(Message const& _m) const;
private:
std::vector<std::pair<bytes, bytes> > m_topicMasks;
};
struct InstalledFilter
{
InstalledFilter(MessageFilter const& _f): filter(_f) {}
MessageFilter filter;
unsigned refCount = 1;
};
struct ClientWatch
{
ClientWatch() {}
explicit ClientWatch(h256 _id): id(_id) {}
h256 id;
h256s changes;
};
class Interface
{
public:
virtual ~Interface() {}
virtual void inject(Message const& _m, WhisperPeer* _from = nullptr) = 0;
virtual unsigned installWatch(MessageFilter const& _filter) = 0;
virtual unsigned installWatch(h256 _filterId) = 0;
virtual void uninstallWatch(unsigned _watchId) = 0;
virtual h256s peekWatch(unsigned _watchId) const = 0;
virtual h256s checkWatch(unsigned _watchId) = 0;
virtual Message message(h256 _m) const = 0;
virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) = 0;
};
struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; };
#define cwatshh dev::LogOutputStream<shh::WatshhChannel, true>()
}
}
/*
namespace std { void swap(shh::Watch& _a, shh::Watch& _b); }
namespace shh
{
class Watch: public boost::noncopyable
{
friend void std::swap(Watch& _a, Watch& _b);
public:
Watch() {}
Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {}
Watch(Whisper& _c, MessageFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
~Watch() { if (m_c) m_c->uninstallWatch(m_id); }
bool check() { return m_c ? m_c->checkWatch(m_id) : false; }
bool peek() { return m_c ? m_c->peekWatch(m_id) : false; }
private:
Whisper* m_c;
unsigned m_id;
};
}
namespace shh
{
inline void swap(shh::Watch& _a, shh::Watch& _b)
{
swap(_a.m_c, _b.m_c);
swap(_a.m_id, _b.m_id);
}
}
*/

28
libwhisper/Message.cpp

@ -0,0 +1,28 @@
/*
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 Message.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Message.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "

63
libwhisper/Message.h

@ -0,0 +1,63 @@
/*
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 Message.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
namespace dev
{
namespace shh
{
struct Message
{
unsigned expiry = 0;
unsigned ttl = 0;
bytes topic; // TODO: change to h256
bytes payload;
Message() {}
Message(unsigned _exp, unsigned _ttl, bytes const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {}
Message(RLP const& _m)
{
expiry = _m[0].toInt<unsigned>();
ttl = _m[1].toInt<unsigned>();
topic = _m[2].toBytes();
payload = _m[3].toBytes();
}
operator bool () const { return !!expiry; }
void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; }
h256 sha3() const { RLPStream s; streamOut(s); return dev::eth::sha3(s.out()); }
};
}
}

123
libwhisper/WhisperHost.cpp

@ -0,0 +1,123 @@
/*
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 WhisperHost.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "WhisperHost.h"
#include <libdevcore/Log.h>
#include <libp2p/All.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
WhisperHost::WhisperHost()
{
}
WhisperHost::~WhisperHost()
{
}
void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
{
UpgradableGuard l(x_messages);
if (m_messages.count(_m))
{
UpgradeGuard ll(l);
m_messages.at(_m).streamOut(_s);
}
}
void WhisperHost::inject(Message const& _m, WhisperPeer* _p)
{
auto h = _m.sha3();
{
UpgradableGuard l(x_messages);
if (m_messages.count(h))
return;
UpgradeGuard ll(l);
m_messages[h] = _m;
}
if (_p)
{
Guard l(m_filterLock);
for (auto const& f: m_filters)
if (f.second.filter.matches(_m))
noteChanged(h, f.first);
}
for (auto& i: peers())
if (i->cap<WhisperPeer>().get() == _p)
i->addRating(1);
else
i->cap<WhisperPeer>()->noteNewMessage(h, _m);
}
void WhisperHost::noteChanged(h256 _messageHash, h256 _filter)
{
for (auto& i: m_watches)
if (i.second.id == _filter)
{
cwatshh << "!!!" << i.first << i.second.id;
i.second.changes.push_back(_messageHash);
}
}
unsigned WhisperHost::installWatch(h256 _h)
{
auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h);
cwatshh << "+++" << ret << _h;
return ret;
}
unsigned WhisperHost::installWatch(shh::MessageFilter const& _f)
{
Guard l(m_filterLock);
h256 h = _f.sha3();
if (!m_filters.count(h))
m_filters.insert(make_pair(h, _f));
return installWatch(h);
}
void WhisperHost::uninstallWatch(unsigned _i)
{
cwatshh << "XXX" << _i;
Guard l(m_filterLock);
auto it = m_watches.find(_i);
if (it == m_watches.end())
return;
auto id = it->second.id;
m_watches.erase(it);
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
m_filters.erase(fit);
}

77
libwhisper/WhisperHost.h

@ -0,0 +1,77 @@
/*
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 WhisperHost.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <mutex>
#include <array>
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
#include "WhisperPeer.h"
#include "Interface.h"
namespace dev
{
namespace shh
{
class WhisperHost: public HostCapability<WhisperPeer>, public Interface
{
friend class WhisperPeer;
public:
WhisperHost();
virtual ~WhisperHost();
unsigned protocolVersion() const { return 0; }
virtual void inject(Message const& _m, WhisperPeer* _from = nullptr);
virtual unsigned installWatch(MessageFilter const& _filter);
virtual unsigned installWatch(h256 _filterId);
virtual void uninstallWatch(unsigned _watchId);
virtual h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
virtual h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
virtual Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } }
virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); }
private:
void streamMessage(h256 _m, RLPStream& _s) const;
void noteChanged(h256 _messageHash, h256 _filter);
mutable dev::SharedMutex x_messages;
std::map<h256, Message> m_messages;
mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
};
}
}

111
libwhisper/WhisperPeer.cpp

@ -14,7 +14,7 @@
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 Whisper.cpp
/** @file WhisperPeer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
@ -23,11 +23,11 @@
#include <libdevcore/Log.h>
#include <libp2p/All.h>
#include "WhisperHost.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h): Capability(_s, _h)
@ -108,110 +108,3 @@ void WhisperPeer::noteNewMessage(h256 _h, Message const& _m)
Guard l(x_unseen);
m_unseen[rating(_m)] = _h;
}
WhisperHost::WhisperHost()
{
}
WhisperHost::~WhisperHost()
{
}
void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
{
UpgradableGuard l(x_messages);
if (m_messages.count(_m))
{
UpgradeGuard ll(l);
m_messages.at(_m).streamOut(_s);
}
}
void WhisperHost::inject(Message const& _m, WhisperPeer* _p)
{
auto h = _m.sha3();
{
UpgradableGuard l(x_messages);
if (m_messages.count(h))
return;
UpgradeGuard ll(l);
m_messages[h] = _m;
}
if (_p)
{
Guard l(m_filterLock);
for (auto const& f: m_filters)
if (f.second.filter.matches(_m))
noteChanged(h, f.first);
}
for (auto& i: peers())
if (i->cap<WhisperPeer>().get() == _p)
i->addRating(1);
else
i->cap<WhisperPeer>()->noteNewMessage(h, _m);
}
void WhisperHost::noteChanged(h256 _messageHash, h256 _filter)
{
for (auto& i: m_watches)
if (i.second.id == _filter)
{
cwatshh << "!!!" << i.first << i.second.id;
i.second.changes.push_back(_messageHash);
}
}
bool MessageFilter::matches(Message const& _m) const
{
for (auto const& t: m_topicMasks)
{
if (t.first.size() != t.second.size() || _m.topic.size() < t.first.size())
continue;
for (unsigned i = 0; i < t.first.size(); ++i)
if (((t.first[i] ^ _m.topic[i]) & t.second[i]) != 0)
goto NEXT;
return true;
NEXT:;
}
return false;
}
unsigned WhisperHost::installWatch(h256 _h)
{
auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
m_watches[ret] = ClientWatch(_h);
cwatshh << "+++" << ret << _h;
return ret;
}
unsigned WhisperHost::installWatch(shh::MessageFilter const& _f)
{
Guard l(m_filterLock);
h256 h = _f.sha3();
if (!m_filters.count(h))
m_filters.insert(make_pair(h, _f));
return installWatch(h);
}
void WhisperHost::uninstallWatch(unsigned _i)
{
cwatshh << "XXX" << _i;
Guard l(m_filterLock);
auto it = m_watches.find(_i);
if (it == m_watches.end())
return;
auto id = it->second.id;
m_watches.erase(it);
auto fit = m_filters.find(id);
if (fit != m_filters.end())
if (!--fit->second.refCount)
m_filters.erase(fit);
}

154
libwhisper/WhisperPeer.h

@ -14,7 +14,7 @@
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 Whisper.h
/** @file WhisperPeer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
@ -30,6 +30,7 @@
#include <libdevcore/Guards.h>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
#include "Message.h"
namespace dev
{
@ -41,29 +42,6 @@ using p2p::HostCapabilityFace;
using p2p::HostCapability;
using p2p::Capability;
struct Message
{
unsigned expiry = 0;
unsigned ttl = 0;
bytes topic;
bytes payload;
Message() {}
Message(unsigned _exp, unsigned _ttl, bytes const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {}
Message(RLP const& _m)
{
expiry = _m[0].toInt<unsigned>();
ttl = _m[1].toInt<unsigned>();
topic = _m[2].toBytes();
payload = _m[3].toBytes();
}
operator bool () const { return !!expiry; }
void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; }
h256 sha3() const { RLPStream s; streamOut(s); return dev::eth::sha3(s.out()); }
};
/**
*/
class WhisperPeer: public Capability
@ -90,133 +68,5 @@ private:
std::map<unsigned, h256> m_unseen; ///< Rated according to what they want.
};
class MessageFilter
{
public:
MessageFilter() {}
MessageFilter(std::vector<std::pair<bytes, bytes> > const& _m): m_topicMasks(_m) {}
MessageFilter(RLP const& _r): m_topicMasks((std::vector<std::pair<bytes, bytes>>)_r) {}
void fillStream(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); }
bool matches(Message const& _m) const;
private:
std::vector<std::pair<bytes, bytes> > m_topicMasks;
};
struct InstalledFilter
{
InstalledFilter(MessageFilter const& _f): filter(_f) {}
MessageFilter filter;
unsigned refCount = 1;
};
struct ClientWatch
{
ClientWatch() {}
explicit ClientWatch(h256 _id): id(_id) {}
h256 id;
h256s changes;
};
class Interface
{
public:
virtual ~Interface() {}
virtual void inject(Message const& _m, WhisperPeer* _from = nullptr) = 0;
virtual unsigned installWatch(MessageFilter const& _filter) = 0;
virtual unsigned installWatch(h256 _filterId) = 0;
virtual void uninstallWatch(unsigned _watchId) = 0;
virtual h256s peekWatch(unsigned _watchId) const = 0;
virtual h256s checkWatch(unsigned _watchId) = 0;
virtual Message message(h256 _m) const = 0;
virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) = 0;
};
class WhisperHost: public HostCapability<WhisperPeer>, public Interface
{
friend class WhisperPeer;
public:
WhisperHost();
virtual ~WhisperHost();
unsigned protocolVersion() const { return 0; }
void inject(Message const& _m, WhisperPeer* _from = nullptr);
unsigned installWatch(MessageFilter const& _filter);
unsigned installWatch(h256 _filterId);
void uninstallWatch(unsigned _watchId);
h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } }
h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; }
Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } }
void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); }
private:
void streamMessage(h256 _m, RLPStream& _s) const;
void noteChanged(h256 _messageHash, h256 _filter);
mutable dev::SharedMutex x_messages;
std::map<h256, Message> m_messages;
mutable dev::Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;
std::map<unsigned, ClientWatch> m_watches;
};
struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; };
#define cwatshh dev::LogOutputStream<shh::WatshhChannel, true>()
class Watch;
}
}
/*
namespace std { void swap(shh::Watch& _a, shh::Watch& _b); }
namespace shh
{
class Watch: public boost::noncopyable
{
friend void std::swap(Watch& _a, Watch& _b);
public:
Watch() {}
Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {}
Watch(Whisper& _c, MessageFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
~Watch() { if (m_c) m_c->uninstallWatch(m_id); }
bool check() { return m_c ? m_c->checkWatch(m_id) : false; }
bool peek() { return m_c ? m_c->peekWatch(m_id) : false; }
private:
Whisper* m_c;
unsigned m_id;
};
}
namespace shh
{
inline void swap(shh::Watch& _a, shh::Watch& _b)
{
swap(_a.m_c, _b.m_c);
swap(_a.m_id, _b.m_id);
}
}
*/

3
libwhisper/_libwhisper.cpp

@ -2,4 +2,7 @@
#include "All.h"
#include "Common.cpp"
#include "WhisperPeer.cpp"
#include "WhisperHost.cpp"
#include "Message.cpp"
#include "Interface.cpp"
#endif

9
third/MainWin.cpp

@ -106,11 +106,13 @@ Main::Main(QWidget *parent) :
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qeth = m_ethereum;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, this));
auto qshh = m_whisper;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
@ -153,6 +155,11 @@ eth::Client* Main::ethereum() const
return m_web3->ethereum();
}
std::shared_ptr<dev::shh::WhisperHost> Main::whisper() const
{
return m_web3->whisper();
}
void Main::onKeysChanged()
{
installBalancesWatch();

8
third/MainWin.h

@ -41,7 +41,11 @@ namespace eth {
class Client;
class State;
class MessageFilter;
}}
}
namespace shh {
class WhisperHost;
}
}
class QQuickView;
@ -55,6 +59,7 @@ public:
dev::WebThreeDirect* web3() const { return m_web3.get(); }
dev::eth::Client* ethereum() const;
std::shared_ptr<dev::shh::WhisperHost> whisper() const;
QList<dev::KeyPair> const& owned() const { return m_myKeys; }
@ -128,4 +133,5 @@ private:
QNetworkAccessManager m_webCtrl;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
};

Loading…
Cancel
Save