Skip to content

Commit 0e8291c

Browse files
authored
Merge pull request #711 from evoskuil/master
Implement outpoint notification differencing (fix).
2 parents c8ec1e0 + 1be0e57 commit 0e8291c

17 files changed

Lines changed: 280 additions & 182 deletions

Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ src_libbitcoin_server_la_SOURCES = \
5757
src/protocols/electrum/protocol_electrum_mempool.cpp \
5858
src/protocols/electrum/protocol_electrum_outpoints.cpp \
5959
src/protocols/electrum/protocol_electrum_scripthash.cpp \
60-
src/protocols/electrum/protocol_electrum_scripthash_subscribe.cpp \
6160
src/protocols/electrum/protocol_electrum_scriptpubkey.cpp \
6261
src/protocols/electrum/protocol_electrum_server.cpp \
62+
src/protocols/electrum/protocol_electrum_subscribe.cpp \
6363
src/protocols/electrum/protocol_electrum_transactions.cpp \
6464
src/protocols/electrum/protocol_electrum_version.cpp \
6565
src/protocols/native/protocol_native.cpp \
@@ -108,6 +108,7 @@ test_libbitcoin_server_test_SOURCES = \
108108
test/protocols/electrum/electrum_scripthash.cpp \
109109
test/protocols/electrum/electrum_scriptpubkey.cpp \
110110
test/protocols/electrum/electrum_server.cpp \
111+
test/protocols/electrum/electrum_subscribe.cpp \
111112
test/protocols/electrum/electrum_transactions.cpp \
112113
test/protocols/electrum/electrum_version.cpp \
113114
test/protocols/native/native.cpp \

builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_scripthash.cpp" />
149149
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_scriptpubkey.cpp" />
150150
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_server.cpp" />
151+
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_subscribe.cpp" />
151152
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_transactions.cpp" />
152153
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_version.cpp">
153154
<ObjectFileName>$(IntDir)test_protocols_electrum_electrum_version.obj</ObjectFileName>

builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@
9393
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_server.cpp">
9494
<Filter>src\protocols\electrum</Filter>
9595
</ClCompile>
96+
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_subscribe.cpp">
97+
<Filter>src\protocols\electrum</Filter>
98+
</ClCompile>
9699
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_transactions.cpp">
97100
<Filter>src\protocols\electrum</Filter>
98101
</ClCompile>

builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@
139139
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_mempool.cpp" />
140140
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_outpoints.cpp" />
141141
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash.cpp" />
142-
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash_subscribe.cpp" />
143142
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scriptpubkey.cpp" />
144143
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_server.cpp" />
144+
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_subscribe.cpp" />
145145
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_transactions.cpp" />
146146
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_version.cpp" />
147147
<ClCompile Include="..\..\..\..\src\protocols\native\protocol_native.cpp" />

builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@
117117
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash.cpp">
118118
<Filter>src\protocols\electrum</Filter>
119119
</ClCompile>
120-
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash_subscribe.cpp">
121-
<Filter>src\protocols\electrum</Filter>
122-
</ClCompile>
123120
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scriptpubkey.cpp">
124121
<Filter>src\protocols\electrum</Filter>
125122
</ClCompile>
126123
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_server.cpp">
127124
<Filter>src\protocols\electrum</Filter>
128125
</ClCompile>
126+
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_subscribe.cpp">
127+
<Filter>src\protocols\electrum</Filter>
128+
</ClCompile>
129129
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_transactions.cpp">
130130
<Filter>src\protocols\electrum</Filter>
131131
</ClCompile>

include/bitcoin/server/protocols/protocol_electrum.hpp

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
#include <map>
2323
#include <memory>
24-
#include <set>
2524
#include <bitcoin/server/channels/channels.hpp>
2625
#include <bitcoin/server/define.hpp>
2726
#include <bitcoin/server/interfaces/interfaces.hpp>
@@ -206,12 +205,40 @@ class BCS_API protocol_electrum
206205
rpc_interface::mempool_get_info) NOEXCEPT;
207206

208207
protected:
208+
using point = system::chain::point;
209+
using hash_digest = system::hash_digest;
210+
using history = database::history;
209211
using unspents = database::unspents;
210212
using histories = database::histories;
211-
using hash_digest = system::hash_digest;
212213
enum class notify_t { address, scripthash, scriptpubkey };
213-
typedef std::function<void(const code&, const hash_digest&,
214-
const hash_digest&)> status_handler;
214+
215+
// Status hash optimization (~200 bytes).
216+
struct midstate
217+
{
218+
hash_digest status{};
219+
system::stream::out::fast stream{ status };
220+
system::hash::sha256::fast writer{ stream };
221+
};
222+
223+
// Subscription to address/scripthash/scruptpubkey.
224+
struct address_subscription
225+
{
226+
notify_t type{};
227+
midstate state{};
228+
database::address_link cursor{};
229+
};
230+
231+
// Subscription to outpoint.
232+
struct outpoint_subscription
233+
{
234+
database::history outpoint{};
235+
database::histories spenders{};
236+
237+
bool operator==(const outpoint_subscription& other) const NOEXCEPT
238+
{
239+
return outpoint == other.outpoint && spenders == other.spenders;
240+
}
241+
};
215242

216243
/// Common implementation for block_header/s.
217244
void blockchain_block_headers(size_t starting, size_t quantity,
@@ -259,18 +286,22 @@ class BCS_API protocol_electrum
259286
void scripthash_notify(const hash_digest& status, const hash_digest& hash,
260287
notify_t type) NOEXCEPT;
261288

289+
code get_scripthash_history(hash_digest& status, address_subscription& sub,
290+
const hash_digest& hash, size_t limit=max_size_t) NOEXCEPT;
291+
262292
/// Outpoint.
263293
/// -----------------------------------------------------------------------
264294

265-
void do_outpoint_subscribe(const system::chain::point& prevout,
266-
const std::string& hint) NOEXCEPT;
295+
void do_outpoint_subscribe(const point& prevout) NOEXCEPT;
267296
void complete_outpoint_subscribe(const code& ec,
268-
const system::chain::point& prevout,
269-
const std::string& hint) NOEXCEPT;
270-
void do_outpoint_unsubscribe(const system::chain::point& prevout) NOEXCEPT;
297+
const outpoint_subscription& sub, const point& prevout) NOEXCEPT;
298+
void do_outpoint_unsubscribe(const point& prevout) NOEXCEPT;
271299
void complete_outpoint_unsubscribe(bool found) NOEXCEPT;
272300
void outpoint_notify(const std::unique_ptr<interface::object_t>& status,
273-
const system::chain::point& prevout) NOEXCEPT;
301+
const point& prevout) NOEXCEPT;
302+
303+
bool get_outpoint_history(outpoint_subscription& sub,
304+
const point& prevout) const NOEXCEPT;
274305

275306
/// Utilities.
276307
/// -----------------------------------------------------------------------
@@ -296,44 +327,28 @@ class BCS_API protocol_electrum
296327
BIND_SAFE(BIND_SHARED(method, args)));
297328
}
298329

299-
// Status hash optimization (~200 bytes).
300-
struct midstate
301-
{
302-
hash_digest status{};
303-
system::stream::out::fast stream{ status };
304-
system::hash::sha256::fast writer{ stream };
305-
};
306-
307-
// Subscription to address/scripthash/scruptpubkey.
308-
struct subscription
309-
{
310-
notify_t type{};
311-
midstate state{};
312-
database::address_link cursor{};
313-
};
314-
315330
// Aliases.
316331
using array_t = network::rpc::array_t;
317332
using object_t = network::rpc::object_t;
318333
using version_t = protocol_electrum_version;
319334
static constexpr electrum::version minimum = version_t::minimum;
320335
static constexpr electrum::version maximum = version_t::maximum;
321336

322-
// Status utilities.
323-
code get_scripthash_status(hash_digest& out, subscription& sub,
324-
const hash_digest& hash, size_t limit=max_size_t) NOEXCEPT;
325-
bool get_outpoint_statuses(std::vector<interface::object_t>& out,
326-
const system::chain::point& prevout) const NOEXCEPT;
327-
bool get_outpoint_status(interface::object_t& out,
328-
const system::chain::point& prevout) const NOEXCEPT;
329-
bool send_outpoint_status(const system::chain::point& prevout,
330-
const std::string& hint) NOEXCEPT;
331-
332337
// Transformations.
333338
static array_t transform(const unspents& unspents) NOEXCEPT;
334339
static array_t transform(const histories& histories) NOEXCEPT;
335340
static hash_digest to_status(const histories& histories) NOEXCEPT;
336341
static std::string to_method_name(notify_t type) NOEXCEPT;
342+
static bool is_valid_hint(const std::string& hint) NOEXCEPT;
343+
static object_t to_outpoint_status(size_t output_height) NOEXCEPT;
344+
static object_t to_outpoint_status(size_t output_height,
345+
const history& history) NOEXCEPT;
346+
static object_t to_outpoint_status(
347+
const outpoint_subscription& sub) NOEXCEPT;
348+
std::unique_ptr<object_t> make_status(
349+
size_t output_height) const NOEXCEPT;
350+
std::unique_ptr<object_t> make_status(size_t output_height,
351+
const history& history) const NOEXCEPT;
337352

338353
// Compute server.features.hosts value from config.
339354
object_t self_hosts() const NOEXCEPT;
@@ -367,8 +382,8 @@ class BCS_API protocol_electrum
367382
network::asio::strand notification_strand_;
368383

369384
// These are protected by notification strand.
370-
std::set<system::chain::point> outpoint_subscriptions_{};
371-
std::map<hash_digest, subscription> address_subscriptions_{};
385+
std::map<point, outpoint_subscription> outpoint_subscriptions_{};
386+
std::map<hash_digest, address_subscription> address_subscriptions_{};
372387
};
373388

374389
} // namespace server

src/protocols/electrum/protocol_electrum.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,9 @@ bool protocol_electrum::handle_event(const code&, node::chase event_,
136136
if (stopped())
137137
return false;
138138

139-
// TODO: collapse three atomics this into a single enumeration.
140139
switch (event_)
141140
{
142-
////case node::chase::transaction:
141+
case node::chase::transaction:
143142
case node::chase::organized:
144143
{
145144
if (subscribed_height_.load(relaxed))
@@ -185,6 +184,23 @@ bool protocol_electrum::handle_event(const code&, node::chase event_,
185184
return true;
186185
}
187186

187+
// reorganization
188+
// ----------------------------------------------------------------------------
189+
// outpoint subscriptions do not require modification.
190+
191+
// The chain has been reduced in height, clear all midstate cache and cursors.
192+
void protocol_electrum::do_reorganized(node::header_t) NOEXCEPT
193+
{
194+
BC_ASSERT(notification_strand_.running_in_this_thread());
195+
196+
for (auto& [key, sub]: address_subscriptions_)
197+
{
198+
// writer.flush resets hash accumulator, sub.type remains unchanged.
199+
sub.state.writer.flush();
200+
sub.cursor = {};
201+
}
202+
}
203+
188204
BC_POP_WARNING()
189205

190206
} // namespace server

0 commit comments

Comments
 (0)