diff --git a/include/bitcoin/node/chasers/chaser.hpp b/include/bitcoin/node/chasers/chaser.hpp
index ee14cfc4..c8815e7e 100644
--- a/include/bitcoin/node/chasers/chaser.hpp
+++ b/include/bitcoin/node/chasers/chaser.hpp
@@ -85,10 +85,13 @@ class BCN_API chaser
     /// Close the node.
     void close(const code& ec) NOEXCEPT;
 
+    /// The chaser's strand.
+    network::asio::strand& strand() NOEXCEPT;
+
     /// True if the current thread is on the chaser strand.
     bool stranded() const NOEXCEPT;
 
-    /// Subscribe to chaser events.
+    /// Subscribe to chaser events (must be non-virtual).
     code subscribe(event_handler&& handler) NOEXCEPT;
 
     /// Set chaser event (does not require network strand).
diff --git a/include/bitcoin/node/chasers/chaser_candidate.hpp b/include/bitcoin/node/chasers/chaser_candidate.hpp
index 8e8f2e43..3e857e49 100644
--- a/include/bitcoin/node/chasers/chaser_candidate.hpp
+++ b/include/bitcoin/node/chasers/chaser_candidate.hpp
@@ -29,14 +29,17 @@ namespace node {
 class full_node;
 
 /// Construct candidate blocks upon modification of the transaction DAG.
-/// Notify subscribers with "candidate" event.
 class BCN_API chaser_candidate
   : public chaser, protected network::tracker<chaser_candidate>
 {
 public:
-    typedef std::unique_ptr<chaser_candidate> ptr;
+    typedef std::unique_ptr<chaser_candidate> uptr;
 
     chaser_candidate(full_node& node) NOEXCEPT;
+
+private:
+    void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/chasers/chaser_check.hpp b/include/bitcoin/node/chasers/chaser_check.hpp
index c857cf15..ac39fa28 100644
--- a/include/bitcoin/node/chasers/chaser_check.hpp
+++ b/include/bitcoin/node/chasers/chaser_check.hpp
@@ -29,17 +29,17 @@ namespace node {
 class full_node;
 
 /// Chase down blocks for the candidate header chain.
-/// Notify subscribers with "block checked" event.
 class BCN_API chaser_check
   : public chaser, protected network::tracker<chaser_check>
 {
 public:
-    typedef std::unique_ptr<chaser_check> ptr;
+    typedef std::unique_ptr<chaser_check> uptr;
 
     chaser_check(full_node& node) NOEXCEPT;
 
 private:
     void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp
index 959cbcaf..42d95e87 100644
--- a/include/bitcoin/node/chasers/chaser_confirm.hpp
+++ b/include/bitcoin/node/chasers/chaser_confirm.hpp
@@ -29,14 +29,17 @@ namespace node {
 class full_node;
 
 /// Chase down valid blocks for confirmation.
-/// Notify subscribers with "block confirmed" event.
 class BCN_API chaser_confirm
   : public chaser, protected network::tracker<chaser_confirm>
 {
 public:
-    typedef std::unique_ptr<chaser_confirm> ptr;
+    typedef std::unique_ptr<chaser_confirm> uptr;
 
     chaser_confirm(full_node& node) NOEXCEPT;
+
+private:
+    void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/chasers/chaser_connect.hpp b/include/bitcoin/node/chasers/chaser_connect.hpp
index dc659974..8297ad8e 100644
--- a/include/bitcoin/node/chasers/chaser_connect.hpp
+++ b/include/bitcoin/node/chasers/chaser_connect.hpp
@@ -29,14 +29,17 @@ namespace node {
 class full_node;
 
 /// Chase down blocks in the the candidate header chain for validation.
-/// Notify subscribers with the "block connected" event.
 class BCN_API chaser_connect
   : public chaser, protected network::tracker<chaser_connect>
 {
 public:
-    typedef std::unique_ptr<chaser_connect> ptr;
+    typedef std::unique_ptr<chaser_connect> uptr;
 
     chaser_connect(full_node& node) NOEXCEPT;
+
+private:
+    void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/chasers/chaser_header.hpp b/include/bitcoin/node/chasers/chaser_header.hpp
index ca7b0048..27b58d41 100644
--- a/include/bitcoin/node/chasers/chaser_header.hpp
+++ b/include/bitcoin/node/chasers/chaser_header.hpp
@@ -29,14 +29,17 @@ namespace node {
 class full_node;
 
 /// Chase down stronger header branches for the candidate chain.
-/// Notify subscribers with "strong header" event.
 class BCN_API chaser_header
   : public chaser, protected network::tracker<chaser_header>
 {
 public:
-    typedef std::unique_ptr<chaser_header> ptr;
+    typedef std::unique_ptr<chaser_header> uptr;
 
     chaser_header(full_node& node) NOEXCEPT;
+
+private:
+    void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/chasers/chaser_transaction.hpp b/include/bitcoin/node/chasers/chaser_transaction.hpp
index 061d3022..31b49019 100644
--- a/include/bitcoin/node/chasers/chaser_transaction.hpp
+++ b/include/bitcoin/node/chasers/chaser_transaction.hpp
@@ -33,9 +33,13 @@ class BCN_API chaser_transaction
   : public chaser, protected network::tracker<chaser_transaction>
 {
 public:
-    typedef std::unique_ptr<chaser_transaction> ptr;
+    typedef std::unique_ptr<chaser_transaction> uptr;
 
     chaser_transaction(full_node& node) NOEXCEPT;
+
+private:
+    void handle_event(const code& ec, chase value) NOEXCEPT;
+    void do_handle_event(const code& ec, chase value) NOEXCEPT;
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/full_node.hpp b/include/bitcoin/node/full_node.hpp
index 0a79c0af..fe2a6b64 100644
--- a/include/bitcoin/node/full_node.hpp
+++ b/include/bitcoin/node/full_node.hpp
@@ -71,6 +71,7 @@ class BCN_API full_node
 protected:
     virtual code create_chasers() NOEXCEPT;
     virtual void stop_chasers() NOEXCEPT;
+    virtual void delete_chasers() NOEXCEPT;
 
     /// Session attachments.
     /// -----------------------------------------------------------------------
@@ -89,12 +90,12 @@ class BCN_API full_node
 
     // These are protected by strand.
     chaser::event_subscriber event_subscriber_;
-    chaser_header::ptr chaser_header_{};
-    chaser_check::ptr chaser_check_{};
-    chaser_connect::ptr chaser_connect_{};
-    chaser_confirm::ptr chaser_confirm_{};
-    chaser_transaction::ptr chaser_transaction_{};
-    chaser_candidate::ptr chaser_candidate_{};
+    chaser_header::uptr chaser_header_{};
+    chaser_check::uptr chaser_check_{};
+    chaser_connect::uptr chaser_connect_{};
+    chaser_confirm::uptr chaser_confirm_{};
+    chaser_transaction::uptr chaser_transaction_{};
+    chaser_candidate::uptr chaser_candidate_{};
 };
 
 } // namespace node
diff --git a/include/bitcoin/node/protocols/protocol_block_in.hpp b/include/bitcoin/node/protocols/protocol_block_in.hpp
index ab96b25c..838f286a 100644
--- a/include/bitcoin/node/protocols/protocol_block_in.hpp
+++ b/include/bitcoin/node/protocols/protocol_block_in.hpp
@@ -92,6 +92,9 @@ class BCN_API protocol_block_in
     network::messages::get_data create_get_data(
         const network::messages::inventory& message) const NOEXCEPT;
 
+
+    void do_handle_performance(const code& ec) NOEXCEPT;
+
     // Thread safe.
     const bool report_performance_;
     const network::messages::inventory::type_id block_type_;
diff --git a/src/chasers/chaser.cpp b/src/chasers/chaser.cpp
index f7bf9160..694af662 100644
--- a/src/chasers/chaser.cpp
+++ b/src/chasers/chaser.cpp
@@ -27,6 +27,8 @@
 namespace libbitcoin {
 namespace node {
 
+using namespace network;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser::chaser(full_node& node) NOEXCEPT
@@ -48,6 +50,11 @@ void chaser::close(const code& ec) NOEXCEPT
     node_.close();
 }
 
+asio::strand& chaser::strand() NOEXCEPT
+{
+    return strand_;
+}
+
 bool chaser::stranded() const NOEXCEPT
 {
     return strand_.running_in_this_thread();
diff --git a/src/chasers/chaser_candidate.cpp b/src/chasers/chaser_candidate.cpp
index 589abe4d..bef2ea71 100644
--- a/src/chasers/chaser_candidate.cpp
+++ b/src/chasers/chaser_candidate.cpp
@@ -18,19 +18,51 @@
  */
 #include <bitcoin/node/chasers/chaser_candidate.hpp>
 
+#include <functional>
 #include <bitcoin/network.hpp>
+#include <bitcoin/node/error.hpp>
 #include <bitcoin/node/full_node.hpp>
 #include <bitcoin/node/chasers/chaser.hpp>
 
 namespace libbitcoin {
 namespace node {
 
+using namespace std::placeholders;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser_candidate::chaser_candidate(full_node& node) NOEXCEPT
   : chaser(node),
     tracker<chaser_candidate>(node.log)
 {
+    subscribe(std::bind(&chaser_candidate::handle_event, this, _1, _2));
+}
+
+void chaser_candidate::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_candidate::do_handle_event, this, ec, value));
+}
+
+void chaser_candidate::do_handle_event(const code& ec, chase value) NOEXCEPT
+{
+    BC_ASSERT_MSG(stranded(), "chaser_candidate");
+
+    // The code should be error::service_stopped when error::stop is set.
+    if (ec)
+        return;
+
+    switch (value)
+    {
+        case chase::start:
+            // TODO: initialize.
+            break;
+        case chase::transaction:
+            // TODO: handle transaction graph change (may issue 'candidate').
+            break;
+        default:
+            return;
+    }
 }
 
 BC_POP_WARNING()
diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp
index 06492666..cc52c4f4 100644
--- a/src/chasers/chaser_check.cpp
+++ b/src/chasers/chaser_check.cpp
@@ -39,6 +39,12 @@ chaser_check::chaser_check(full_node& node) NOEXCEPT
 }
 
 void chaser_check::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_check::do_handle_event, this, ec, value));
+}
+
+void chaser_check::do_handle_event(const code& ec, chase value) NOEXCEPT
 {
     BC_ASSERT_MSG(stranded(), "chaser_check");
 
diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp
index 7ab99e2a..fc543e46 100644
--- a/src/chasers/chaser_confirm.cpp
+++ b/src/chasers/chaser_confirm.cpp
@@ -18,19 +18,51 @@
  */
 #include <bitcoin/node/chasers/chaser_confirm.hpp>
 
+#include <functional>
 #include <bitcoin/network.hpp>
+#include <bitcoin/node/error.hpp>
 #include <bitcoin/node/full_node.hpp>
 #include <bitcoin/node/chasers/chaser.hpp>
 
 namespace libbitcoin {
 namespace node {
 
+using namespace std::placeholders;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT
   : chaser(node),
     tracker<chaser_confirm>(node.log)
 {
+    subscribe(std::bind(&chaser_confirm::handle_event, this, _1, _2));
+}
+
+void chaser_confirm::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_confirm::do_handle_event, this, ec, value));
+}
+
+void chaser_confirm::do_handle_event(const code& ec, chase value) NOEXCEPT
+{
+    BC_ASSERT_MSG(stranded(), "chaser_confirm");
+
+    // The code should be error::service_stopped when error::stop is set.
+    if (ec)
+        return;
+
+    switch (value)
+    {
+        case chase::start:
+            // TODO: initialize.
+            break;
+        case chase::connected:
+            // TODO: handle new strong connected branch (may issue 'confirmed').
+            break;
+        default:
+            return;
+    }
 }
 
 BC_POP_WARNING()
diff --git a/src/chasers/chaser_connect.cpp b/src/chasers/chaser_connect.cpp
index f850b1ec..c3d7c5e4 100644
--- a/src/chasers/chaser_connect.cpp
+++ b/src/chasers/chaser_connect.cpp
@@ -18,19 +18,51 @@
  */
 #include <bitcoin/node/chasers/chaser_connect.hpp>
 
+#include <functional>
 #include <bitcoin/network.hpp>
+#include <bitcoin/node/error.hpp>
 #include <bitcoin/node/full_node.hpp>
 #include <bitcoin/node/chasers/chaser.hpp>
 
 namespace libbitcoin {
 namespace node {
 
+using namespace std::placeholders;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser_connect::chaser_connect(full_node& node) NOEXCEPT
   : chaser(node),
     tracker<chaser_connect>(node.log)
 {
+    subscribe(std::bind(&chaser_connect::handle_event, this, _1, _2));
+}
+
+void chaser_connect::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_connect::do_handle_event, this, ec, value));
+}
+
+void chaser_connect::do_handle_event(const code& ec, chase value) NOEXCEPT
+{
+    BC_ASSERT_MSG(stranded(), "chaser_connect");
+
+    // The code should be error::service_stopped when error::stop is set.
+    if (ec)
+        return;
+
+    switch (value)
+    {
+        case chase::start:
+            // TODO: initialize.
+            break;
+        case chase::checked:
+            // TODO: handle the new checked blocks (may issue 'connected').
+            break;
+        default:
+            return;
+    }
 }
 
 BC_POP_WARNING()
diff --git a/src/chasers/chaser_header.cpp b/src/chasers/chaser_header.cpp
index 4b898ef4..b02efe61 100644
--- a/src/chasers/chaser_header.cpp
+++ b/src/chasers/chaser_header.cpp
@@ -18,21 +18,52 @@
  */
 #include <bitcoin/node/chasers/chaser_header.hpp>
 
+#include <functional>
 #include <bitcoin/network.hpp>
+#include <bitcoin/node/error.hpp>
 #include <bitcoin/node/full_node.hpp>
 #include <bitcoin/node/chasers/chaser.hpp>
 
 namespace libbitcoin {
 namespace node {
 
+using namespace std::placeholders;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser_header::chaser_header(full_node& node) NOEXCEPT
   : chaser(node),
     tracker<chaser_header>(node.log)
 {
+    subscribe(std::bind(&chaser_header::handle_event, this, _1, _2));
+}
+
+void chaser_header::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_header::do_handle_event, this, ec, value));
+}
+
+void chaser_header::do_handle_event(const code& ec, chase value) NOEXCEPT
+{
+    BC_ASSERT_MSG(stranded(), "chaser_header");
+
+    // The code should be error::service_stopped when error::stop is set.
+    if (ec)
+        return;
+
+    switch (value)
+    {
+        case chase::start:
+            // TODO: initialize.
+            break;
+        default:
+            return;
+    }
 }
 
+// TODO: handle new headers (may issue 'header').
+
 BC_POP_WARNING()
 
 } // namespace database
diff --git a/src/chasers/chaser_transaction.cpp b/src/chasers/chaser_transaction.cpp
index ed3d4328..8f6c2de7 100644
--- a/src/chasers/chaser_transaction.cpp
+++ b/src/chasers/chaser_transaction.cpp
@@ -18,21 +18,55 @@
  */
 #include <bitcoin/node/chasers/chaser_transaction.hpp>
 
+#include <functional>
 #include <bitcoin/network.hpp>
+#include <bitcoin/node/error.hpp>
 #include <bitcoin/node/full_node.hpp>
 #include <bitcoin/node/chasers/chaser.hpp>
 
 namespace libbitcoin {
 namespace node {
 
+using namespace std::placeholders;
+
 BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
 
 chaser_transaction::chaser_transaction(full_node& node) NOEXCEPT
   : chaser(node),
     tracker<chaser_transaction>(node.log)
 {
+    subscribe(std::bind(&chaser_transaction::handle_event, this, _1, _2));
+}
+
+void chaser_transaction::handle_event(const code& ec, chase value) NOEXCEPT
+{
+    boost::asio::post(strand(),
+        std::bind(&chaser_transaction::do_handle_event, this, ec, value));
+}
+
+void chaser_transaction::do_handle_event(const code& ec, chase value) NOEXCEPT
+{
+    BC_ASSERT_MSG(stranded(), "chaser_transaction");
+
+    // The code should be error::service_stopped when error::stop is set.
+    if (ec)
+        return;
+
+    switch (value)
+    {
+        case chase::start:
+            // TODO: initialize.
+            break;
+        case chase::confirmed:
+            // TODO: handle the new confirmed blocks (may issue 'transaction').
+            break;
+        default:
+            return;
+    }
 }
 
+// TODO: handle the new unconfirmed transactions (may issue 'transaction').
+
 BC_POP_WARNING()
 
 } // namespace database
diff --git a/src/full_node.cpp b/src/full_node.cpp
index aa56e20e..495827ed 100644
--- a/src/full_node.cpp
+++ b/src/full_node.cpp
@@ -106,6 +106,7 @@ void full_node::do_close() NOEXCEPT
 
     stop_chasers();
     p2p::do_close();
+    delete_chasers();
 }
 
 // Chasers.
@@ -136,6 +137,19 @@ void full_node::stop_chasers() NOEXCEPT
         chaser::chase::stop);
 }
 
+// These should be reset upon destruct, which could only follow close(), which
+// ensures that the threadpool is coalesced. Yet without explicit delete, msvc
+// asserts on process termination.
+void full_node::delete_chasers() NOEXCEPT
+{
+    chaser_header_.reset();
+    chaser_check_.reset();
+    chaser_connect_.reset();
+    chaser_confirm_.reset();
+    chaser_transaction_.reset();
+    chaser_candidate_.reset();
+}
+
 // Properties.
 // ----------------------------------------------------------------------------
 
diff --git a/src/protocols/protocol_block_in.cpp b/src/protocols/protocol_block_in.cpp
index 9fee68e7..5ae4c1a6 100644
--- a/src/protocols/protocol_block_in.cpp
+++ b/src/protocols/protocol_block_in.cpp
@@ -54,7 +54,7 @@ BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
 
 void protocol_block_in::handle_performance_timer(const code& ec) NOEXCEPT
 {
-    BC_ASSERT_MSG(!stranded(), "expected channel strand");
+    BC_ASSERT_MSG(stranded(), "expected channel strand");
 
     if (stopped() || ec == network::error::operation_canceled)
         return;
@@ -76,12 +76,18 @@ void protocol_block_in::handle_performance_timer(const code& ec) NOEXCEPT
     start_ = now;
     log.fire(event_block, rate);
 
+    // Bounces to network strand, performs work, then calls handler.
     // Channel will continue to process blocks while this call excecutes on the
     // network strand. Timer will not be restarted until this call completes.
     performance(identifier(), rate, BIND1(handle_performance, ec));
 }
 
 void protocol_block_in::handle_performance(const code& ec) NOEXCEPT
+{
+    POST1(do_handle_performance, ec);
+}
+
+void protocol_block_in::do_handle_performance(const code& ec) NOEXCEPT
 {
     BC_ASSERT_MSG(stranded(), "expected network strand");
 
diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp
index bb5516a7..cea3f05c 100644
--- a/src/sessions/session.cpp
+++ b/src/sessions/session.cpp
@@ -39,7 +39,8 @@ session::~session() NOEXCEPT
 void session::performance(uint64_t, uint64_t,
     network::result_handler&& handler) NOEXCEPT
 {
-    handler(error::unknown);
+    // TODO: do work on network strand and then invoke handler.
+    boost::asio::post(node_.strand(), std::bind(handler, error::unknown));
 }
 
 const configuration& session::config() const NOEXCEPT