1919#ifndef LIBBITCOIN_SERVER_PROTOCOLS_PROTOCOL_ELECTRUM_HPP
2020#define LIBBITCOIN_SERVER_PROTOCOLS_PROTOCOL_ELECTRUM_HPP
2121
22+ #include < map>
2223#include < memory>
23- #include < unordered_set >
24+ #include < set >
2425#include < bitcoin/server/channels/channels.hpp>
2526#include < bitcoin/server/define.hpp>
2627#include < bitcoin/server/interfaces/interfaces.hpp>
@@ -52,6 +53,7 @@ class BCS_API protocol_electrum
5253 system::wallet::payment_address::mainnet_p2sh :
5354 system::wallet::payment_address::testnet_p2sh),
5455 channel_(std::dynamic_pointer_cast<channel_t >(channel)),
56+ notification_strand_(channel_->service ().get_executor()),
5557 network::tracker<protocol_electrum>(session->log)
5658 {
5759 }
@@ -227,48 +229,77 @@ class BCS_API protocol_electrum
227229 void do_get_history (const hash_digest& hash) NOEXCEPT;
228230 void do_get_mempool (const hash_digest& hash) NOEXCEPT;
229231 void do_list_unspent (const hash_digest& hash) NOEXCEPT;
230- void do_status (const hash_digest& hash,
231- const status_handler& sender) NOEXCEPT;
232-
233- void complete_get_balance (const code& ec, uint64_t confirmed,
234- int64_t unconfirmed) NOEXCEPT;
235- void complete_get_history (const code& ec,
236- const histories& histories) NOEXCEPT;
237- void complete_get_mempool (const code& ec,
238- const histories& histories) NOEXCEPT;
239- void complete_list_unspent (const code& ec,
240- const unspents& unspents) NOEXCEPT;
241- void complete_status (const code& ec, const hash_digest& hash,
242- const hash_digest& status, const status_handler& sender) NOEXCEPT;
243-
244- void send_status (const code& ec, const hash_digest& hash,
245- const hash_digest& status) NOEXCEPT;
246- void notify_status (const code& ec, const hash_digest& hash,
247- const hash_digest& status, notify_t type,
248- node::header_t link) NOEXCEPT;
249-
250- // / Notification senders and send handlers.
232+
233+ void complete_get_balance (const code& ec, uint64_t confirmed, int64_t unconfirmed) NOEXCEPT;
234+ void complete_get_history (const code& ec, const histories& histories) NOEXCEPT;
235+ void complete_get_mempool (const code& ec, const histories& histories) NOEXCEPT;
236+ void complete_list_unspent (const code& ec, const unspents& unspents) NOEXCEPT;
237+
238+ // / Notification event handlers.
251239 // / -----------------------------------------------------------------------
252240
253241 void do_height (node::header_t link) NOEXCEPT;
254242 void do_header (node::header_t link) NOEXCEPT;
255243 void do_outpoint (node::header_t link) NOEXCEPT;
256244 void do_scripthash (node::header_t link) NOEXCEPT;
245+ void do_regressed (node::header_t link) NOEXCEPT;
246+
247+ // / Address.
248+ // / -----------------------------------------------------------------------
249+
250+ // subscription.
251+ void scripthash_subscribe (const hash_digest& hash,
252+ notify_t type) NOEXCEPT;
253+ void do_scripthash_subscribe (const hash_digest& hash,
254+ notify_t type) NOEXCEPT;
255+ void complete_scripthash_subscribe (const code& ec,
256+ hash_digest& status, const hash_digest& hash) NOEXCEPT;
257+
258+ // unsubscription.
259+ void scripthash_unsubscribe (const hash_digest& hash) NOEXCEPT;
260+ void do_scripthash_unsubscribe (const hash_digest& hash) NOEXCEPT;
261+ void complete_scripthash_unsubscribe (bool found) NOEXCEPT;
262+
263+ // notification (do_scripthash()).
264+ void scripthash_notify (const hash_digest& status, const hash_digest& hash,
265+ notify_t type) NOEXCEPT;
266+
267+ // / Outpoint.
268+ // / -----------------------------------------------------------------------
269+
270+ // subscription (do_outpoint()).
271+ bool get_outpoint_status (interface::object_t & status,
272+ const system::chain::point& prevout) const NOEXCEPT;
273+ bool send_outpoint_status (const system::chain::point& prevout,
274+ const std::string& spk_hint) NOEXCEPT;
275+
276+ // unsubscription.
277+ // notification.
257278
258279 // / Utilities.
259280 // / -----------------------------------------------------------------------
260281
282+ // / The negotiated version is at least the specified level.
261283 inline bool at_least (server::electrum::version version) const NOEXCEPT
262284 {
263285 return channel_->version () >= version;
264286 }
265287
288+ // / Configuration options.
266289 inline const options_t & options () const NOEXCEPT
267290 {
268291 return options_;
269292 }
270293
271294private:
295+ // Post to notification strand.
296+ template <class Derived , typename Method, typename ... Args>
297+ inline auto notify (Method&& method, Args&&... args) NOEXCEPT
298+ {
299+ return boost::asio::post (notification_strand_,
300+ BIND_SAFE (BIND_SHARED (method, args)));
301+ }
302+
272303 // Status hash optimization (~200 bytes).
273304 struct midstate
274305 {
@@ -277,13 +308,25 @@ class BCS_API protocol_electrum
277308 system::hash::sha256::fast writer{ stream };
278309 };
279310
311+ // Subscription to address/scripthash/scruptpubkey.
312+ struct subscription
313+ {
314+ notify_t type{};
315+ midstate state{};
316+ database::address_link cursor{};
317+ };
318+
280319 // Aliases.
281320 using array_t = network::rpc::array_t ;
282321 using object_t = network::rpc::object_t ;
283322 using version_t = protocol_electrum_version;
284323 static constexpr electrum::version minimum = version_t ::minimum;
285324 static constexpr electrum::version maximum = version_t ::maximum;
286325
326+ // Scripthash status.
327+ code get_scripthash_status (hash_digest& out, subscription& sub,
328+ const hash_digest& hash) NOEXCEPT;
329+
287330 // Transformations.
288331 static std::string to_method_name (notify_t type) NOEXCEPT;
289332 static array_t transform (const unspents& unspents) NOEXCEPT;
@@ -304,14 +347,6 @@ class BCS_API protocol_electrum
304347 code validate_tx (const system::chain::transaction& tx) const NOEXCEPT;
305348 code broadcast_tx (const system::chain::transaction::cptr& tx) NOEXCEPT;
306349
307- // Shared send/get implementations.
308- void send_scripthash_unsubscribe (const hash_digest& hash) NOEXCEPT;
309- void send_scripthash_subscribe (const hash_digest& hash) NOEXCEPT;
310- bool send_outpoint_status (const system::chain::point& prevout,
311- const std::string& spk_hint) NOEXCEPT;
312- bool get_outpoint_status (object_t & status,
313- const system::chain::point& prevout) const NOEXCEPT;
314-
315350 // These are thread safe.
316351 const options_t & options_;
317352 const bool turbo_;
@@ -320,14 +355,18 @@ class BCS_API protocol_electrum
320355 std::atomic_bool stopping_{};
321356 std::atomic_bool subscribed_height_{};
322357 std::atomic_bool subscribed_header_{};
358+ std::atomic_bool subscribed_address_{};
323359 std::atomic_bool subscribed_outpoint_{};
324- std::atomic_bool subscribed_scripthash_{};
325360
326361 // This is mostly thread safe, and used in a thread safe manner.
327362 const channel_t ::ptr channel_;
328363
329- // This is protected by strand.
330- std::unordered_set<hash_digest> subscriptions_{};
364+ // This is thread safe, uses network threadpool.
365+ network::asio::strand notification_strand_;
366+
367+ // These are protected by notification strand.
368+ std::map<hash_digest, subscription> address_subscriptions_{};
369+ std::set<system::chain::point> outpoint_subscriptions_{};
331370};
332371
333372} // namespace server
0 commit comments