diff --git a/libp2p/Common.h b/libp2p/Common.h index 4fd9ac189..4c7fa837b 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -239,6 +239,7 @@ public: ~DeadlineOps() { stop(); } void schedule(unsigned _msInFuture, std::function const& _f) { if (m_stopped) return; DEV_GUARDED(x_timers) m_timers.emplace_back(m_io, _msInFuture, _f); } + void stop() { m_stopped = true; DEV_GUARDED(x_timers) m_timers.clear(); } protected: @@ -300,4 +301,3 @@ template <> struct hash }; } - diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 29101a35e..f53cb17a7 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -64,15 +64,15 @@ public: virtual ~Interface(); virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; + virtual Topics const& fullTopics(unsigned _id) const = 0; virtual unsigned installWatch(Topics const& _filter) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; virtual h256s checkWatch(unsigned _watchId) = 0; virtual h256s watchMessages(unsigned _watchId) = 0; + virtual Envelope envelope(h256 _m) const = 0; - virtual void saveTopicsToDB(std::string const& _app, std::string const& _password) = 0; - virtual std::vector restoreTopicsFromDB(std::string const& _app, std::string const& _password) = 0; void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } diff --git a/libwhisper/WhisperDB.cpp b/libwhisper/WhisperDB.cpp index a31e2a6eb..118c1cb12 100644 --- a/libwhisper/WhisperDB.cpp +++ b/libwhisper/WhisperDB.cpp @@ -22,39 +22,30 @@ #include "WhisperDB.h" #include #include +#include "WhisperHost.h" + using namespace std; using namespace dev; using namespace dev::shh; namespace fs = boost::filesystem; -WhisperDB::WhisperDB(DBType _t): m_type(_t) +WhisperDB::WhisperDB(string const& _type) { m_readOptions.verify_checksums = true; string path = dev::getDataDir("shh"); fs::create_directories(path); fs::permissions(path, fs::owner_all); + path.append("\\").append(_type); leveldb::Options op; op.create_if_missing = true; op.max_open_files = 256; - string suffix = getTypeSuffix(); leveldb::DB* p = nullptr; - leveldb::Status status = leveldb::DB::Open(op, path + suffix, &p); + leveldb::Status status = leveldb::DB::Open(op, path, &p); m_db.reset(p); if (!status.ok()) BOOST_THROW_EXCEPTION(FailedToOpenLevelDB(status.ToString())); } -string WhisperDB::getTypeSuffix() -{ - switch(m_type) - { - case Messages: return "\\messages"; - case Filters: return "\\filters"; - } - - return "\\misc"; -} - string WhisperDB::lookup(dev::h256 const& _key) const { string ret; @@ -91,11 +82,8 @@ void WhisperDB::kill(dev::h256 const& _key) BOOST_THROW_EXCEPTION(FailedDeleteInLevelDB(status.ToString())); } -void WhisperDB::loadAllMessages(std::map& o_dst) +void WhisperMessagesDB::loadAllMessages(std::map& o_dst) { - if (m_type != Messages) - BOOST_THROW_EXCEPTION(WrongTypeLevelDB()); - leveldb::ReadOptions op; op.fill_cache = false; op.verify_checksums = true; @@ -150,11 +138,8 @@ void WhisperDB::loadAllMessages(std::map& o_dst) } } -void WhisperDB::save(h256 const& _key, Envelope const& _e) +void WhisperMessagesDB::saveSingleMessage(h256 const& _key, Envelope const& _e) { - if (m_type != Messages) - BOOST_THROW_EXCEPTION(WrongTypeLevelDB()); - try { RLPStream rlp; @@ -172,3 +157,37 @@ void WhisperDB::save(h256 const& _key, Envelope const& _e) cwarn << boost::diagnostic_information(ex); } } + +vector WhisperFiltersDB::restoreTopicsFromDB(WhisperHost* _host, string const& _app) +{ + vector ret; + h256 s = sha3(_app); + h256 h = sha3(s); + string raw = lookup(h); + + bytes plain; + + decryptSym(s, raw, plain); + + RLP rlp(plain); + auto sz = rlp.itemCountStrict(); + + for (unsigned i = 0; i < sz; ++i) + { + RLP r = rlp[i]; + bytesConstRef ref(r.toBytesConstRef()); + Topics topics; + unsigned num = ref.size() / h256::size; + for (unsigned j = 0; j < num; ++j) + { + h256 topic(ref.data() + j * h256::size, h256::ConstructFromPointerType()); + topics.push_back(topic); + } + + unsigned w = _host->installWatch(topics); + ret.push_back(w); + } + + return ret; +} + diff --git a/libwhisper/WhisperDB.h b/libwhisper/WhisperDB.h index 3c7fc4375..1ea29d5a3 100644 --- a/libwhisper/WhisperDB.h +++ b/libwhisper/WhisperDB.h @@ -37,30 +37,39 @@ struct FailedInsertInLevelDB: virtual Exception { FailedInsertInLevelDB(std::str struct FailedLookupInLevelDB: virtual Exception { FailedLookupInLevelDB(std::string const& _message): Exception(_message) {} }; struct FailedDeleteInLevelDB: virtual Exception { FailedDeleteInLevelDB(std::string const& _message): Exception(_message) {} }; +class WhisperHost; + class WhisperDB { public: - enum DBType { Messages, Filters }; - - WhisperDB(DBType _t); - ~WhisperDB() {} - + WhisperDB(std::string const& _type); + virtual ~WhisperDB() {} std::string lookup(dev::h256 const& _key) const; void insert(dev::h256 const& _key, std::string const& _value); void insert(dev::h256 const& _key, bytes const& _value); void kill(dev::h256 const& _key); - void loadAllMessages(std::map& o_dst); - void save(dev::h256 const& _key, Envelope const& _e); - -private: - std::string getTypeSuffix(); +protected: leveldb::ReadOptions m_readOptions; leveldb::WriteOptions m_writeOptions; std::unique_ptr m_db; - DBType m_type; +}; - enum MetaInformation { StoreForeverFlag = 1, WatchedFlag = 2 }; +class WhisperMessagesDB: public WhisperDB +{ +public: + WhisperMessagesDB(): WhisperDB("messages") {} + virtual ~WhisperMessagesDB() {} + void loadAllMessages(std::map& o_dst); + void saveSingleMessage(dev::h256 const& _key, Envelope const& _e); +}; + +class WhisperFiltersDB: public WhisperDB +{ +public: + WhisperFiltersDB(): WhisperDB("filters") {} + virtual ~WhisperFiltersDB() {} + std::vector restoreTopicsFromDB(WhisperHost* _host, std::string const& _app); }; } diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 856d7be7c..b50698ed1 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -241,13 +241,13 @@ void WhisperHost::saveMessagesToBD() try { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; ReadGuard g(x_messages); unsigned now = (unsigned)time(0); for (auto const& m: m_messages) if (m.second.expiry() > now) if (isWatched(m.second)) - db.save(m.first, m.second); + db.saveSingleMessage(m.first, m.second); } catch(FailedToOpenLevelDB const& ex) { @@ -271,7 +271,7 @@ void WhisperHost::loadMessagesFromBD() try { map m; - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; db.loadAllMessages(m); WriteGuard g(x_messages); m_messages.swap(m); @@ -313,44 +313,11 @@ void WhisperHost::saveTopicsToDB(string const& _app, string const& _password) rlp.swapOut(plain); } + h256 s = sha3(_app); + h256 h = sha3(s); bytes encrypted; - h256 s = sha3(_password); encryptSym(s, &plain, encrypted); - h256 h = sha3(_app); - WhisperDB db(WhisperDB::Filters); + WhisperFiltersDB db; db.insert(h, encrypted); } - -vector WhisperHost::restoreTopicsFromDB(string const& _app, string const& _password) -{ - vector ret; - h256 h = sha3(_app); - WhisperDB db(WhisperDB::Filters); - string raw = db.lookup(h); - - bytes plain; - h256 s = sha3(_password); - decryptSym(s, raw, plain); - - RLP rlp(plain); - auto sz = rlp.itemCountStrict(); - - for (unsigned i = 0; i < sz; ++i) - { - RLP r = rlp[i]; - bytesConstRef ref(r.toBytesConstRef()); - Topics topics; - unsigned num = ref.size() / h256::size; - for (unsigned j = 0; j < num; ++j) - { - h256 topic(ref.data() + j * h256::size, h256::ConstructFromPointerType()); - topics.push_back(topic); - } - - unsigned w = installWatch(topics); - ret.push_back(w); - } - - return ret; -} diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index ab49b8392..6357043e9 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -64,7 +64,6 @@ public: virtual h256s watchMessages(unsigned _watchId) override; ///< returns IDs of messages, which match specific watch criteria virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } virtual void saveTopicsToDB(std::string const& _app, std::string const& _password); - virtual std::vector restoreTopicsFromDB(std::string const& _app, std::string const& _password); protected: virtual void doWork() override; diff --git a/test/libwhisper/whisperDB.cpp b/test/libwhisper/whisperDB.cpp index 902b9cf98..b6fabfa07 100644 --- a/test/libwhisper/whisperDB.cpp +++ b/test/libwhisper/whisperDB.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(basic) string const text2 = "ipsum"; h256 h1(0xBEEF); h256 h2(0xC0FFEE); - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; db.kill(h1); db.kill(h2); @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(persistence) h256 const h2(0xBADD00DE); { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; db.kill(h1); db.kill(h2); s = db.lookup(h1); @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(persistence) this_thread::sleep_for(chrono::milliseconds(20)); { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; db.insert(h1, text1); db.insert(h2, text2); } @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(persistence) this_thread::sleep_for(chrono::milliseconds(20)); { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; s = db.lookup(h2); BOOST_REQUIRE(!s.compare(text2)); s = db.lookup(h1); @@ -170,7 +170,7 @@ BOOST_AUTO_TEST_CASE(messages) } } - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; unsigned x = 0; for (auto i: m1) @@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(corruptedData) h256 x = h256::random(); { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; db.insert(x, "this is a test input, representing corrupt data"); } @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(corruptedData) } { - WhisperDB db(WhisperDB::Messages); + WhisperMessagesDB db; string s = db.lookup(x); BOOST_REQUIRE(s.empty()); } @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(filters) cnote << "Testing filters saving..."; VerbosityHolder setTemporaryLevel(2); string const app("test suite whisperDB/filters"); - string const password("some pseudorandom stuff"); + string const password("some pseudorandom stuff"); // todo: delete { p2p::Host h("Test"); @@ -235,7 +235,9 @@ BOOST_AUTO_TEST_CASE(filters) host1.setIdealPeerCount(1); auto whost1 = host1.registerCapability(new WhisperHost()); host1.start(); - auto ids = whost1->restoreTopicsFromDB(app, password); + //auto ids = whost1->restoreTopicsFromDB(app, password); // todo: delete + WhisperFiltersDB db; + auto ids = db.restoreTopicsFromDB(whost1.get(), app); std::thread listener([&]() {