Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ src_libbitcoin_server_la_SOURCES = \
src/protocols/electrum/protocol_electrum_mempool.cpp \
src/protocols/electrum/protocol_electrum_outpoints.cpp \
src/protocols/electrum/protocol_electrum_scripthash.cpp \
src/protocols/electrum/protocol_electrum_scripthash_subscribe.cpp \
src/protocols/electrum/protocol_electrum_scriptpubkey.cpp \
src/protocols/electrum/protocol_electrum_server.cpp \
src/protocols/electrum/protocol_electrum_subscribe.cpp \
src/protocols/electrum/protocol_electrum_transactions.cpp \
src/protocols/electrum/protocol_electrum_version.cpp \
src/protocols/native/protocol_native.cpp \
Expand Down Expand Up @@ -108,6 +108,7 @@ test_libbitcoin_server_test_SOURCES = \
test/protocols/electrum/electrum_scripthash.cpp \
test/protocols/electrum/electrum_scriptpubkey.cpp \
test/protocols/electrum/electrum_server.cpp \
test/protocols/electrum/electrum_subscribe.cpp \
test/protocols/electrum/electrum_transactions.cpp \
test/protocols/electrum/electrum_version.cpp \
test/protocols/native/native.cpp \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_scripthash.cpp" />
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_scriptpubkey.cpp" />
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_server.cpp" />
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_subscribe.cpp" />
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_transactions.cpp" />
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_version.cpp">
<ObjectFileName>$(IntDir)test_protocols_electrum_electrum_version.obj</ObjectFileName>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_server.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_subscribe.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\protocols\electrum\electrum_transactions.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_mempool.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_outpoints.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash_subscribe.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scriptpubkey.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_server.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_subscribe.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_transactions.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_version.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\native\protocol_native.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scripthash_subscribe.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_scriptpubkey.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_server.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_subscribe.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\protocols\electrum\protocol_electrum_transactions.cpp">
<Filter>src\protocols\electrum</Filter>
</ClCompile>
Expand Down
91 changes: 53 additions & 38 deletions include/bitcoin/server/protocols/protocol_electrum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include <map>
#include <memory>
#include <set>
#include <bitcoin/server/channels/channels.hpp>
#include <bitcoin/server/define.hpp>
#include <bitcoin/server/interfaces/interfaces.hpp>
Expand Down Expand Up @@ -206,12 +205,40 @@ class BCS_API protocol_electrum
rpc_interface::mempool_get_info) NOEXCEPT;

protected:
using point = system::chain::point;
using hash_digest = system::hash_digest;
using history = database::history;
using unspents = database::unspents;
using histories = database::histories;
using hash_digest = system::hash_digest;
enum class notify_t { address, scripthash, scriptpubkey };
typedef std::function<void(const code&, const hash_digest&,
const hash_digest&)> status_handler;

// Status hash optimization (~200 bytes).
struct midstate
{
hash_digest status{};
system::stream::out::fast stream{ status };
system::hash::sha256::fast writer{ stream };
};

// Subscription to address/scripthash/scruptpubkey.
struct address_subscription
{
notify_t type{};
midstate state{};
database::address_link cursor{};
};

// Subscription to outpoint.
struct outpoint_subscription
{
database::history outpoint{};
database::histories spenders{};

bool operator==(const outpoint_subscription& other) const NOEXCEPT
{
return outpoint == other.outpoint && spenders == other.spenders;
}
};

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

code get_scripthash_history(hash_digest& status, address_subscription& sub,
const hash_digest& hash, size_t limit=max_size_t) NOEXCEPT;

/// Outpoint.
/// -----------------------------------------------------------------------

void do_outpoint_subscribe(const system::chain::point& prevout,
const std::string& hint) NOEXCEPT;
void do_outpoint_subscribe(const point& prevout) NOEXCEPT;
void complete_outpoint_subscribe(const code& ec,
const system::chain::point& prevout,
const std::string& hint) NOEXCEPT;
void do_outpoint_unsubscribe(const system::chain::point& prevout) NOEXCEPT;
const outpoint_subscription& sub, const point& prevout) NOEXCEPT;
void do_outpoint_unsubscribe(const point& prevout) NOEXCEPT;
void complete_outpoint_unsubscribe(bool found) NOEXCEPT;
void outpoint_notify(const std::unique_ptr<interface::object_t>& status,
const system::chain::point& prevout) NOEXCEPT;
const point& prevout) NOEXCEPT;

bool get_outpoint_history(outpoint_subscription& sub,
const point& prevout) const NOEXCEPT;

/// Utilities.
/// -----------------------------------------------------------------------
Expand All @@ -296,44 +327,28 @@ class BCS_API protocol_electrum
BIND_SAFE(BIND_SHARED(method, args)));
}

// Status hash optimization (~200 bytes).
struct midstate
{
hash_digest status{};
system::stream::out::fast stream{ status };
system::hash::sha256::fast writer{ stream };
};

// Subscription to address/scripthash/scruptpubkey.
struct subscription
{
notify_t type{};
midstate state{};
database::address_link cursor{};
};

// Aliases.
using array_t = network::rpc::array_t;
using object_t = network::rpc::object_t;
using version_t = protocol_electrum_version;
static constexpr electrum::version minimum = version_t::minimum;
static constexpr electrum::version maximum = version_t::maximum;

// Status utilities.
code get_scripthash_status(hash_digest& out, subscription& sub,
const hash_digest& hash, size_t limit=max_size_t) NOEXCEPT;
bool get_outpoint_statuses(std::vector<interface::object_t>& out,
const system::chain::point& prevout) const NOEXCEPT;
bool get_outpoint_status(interface::object_t& out,
const system::chain::point& prevout) const NOEXCEPT;
bool send_outpoint_status(const system::chain::point& prevout,
const std::string& hint) NOEXCEPT;

// Transformations.
static array_t transform(const unspents& unspents) NOEXCEPT;
static array_t transform(const histories& histories) NOEXCEPT;
static hash_digest to_status(const histories& histories) NOEXCEPT;
static std::string to_method_name(notify_t type) NOEXCEPT;
static bool is_valid_hint(const std::string& hint) NOEXCEPT;
static object_t to_outpoint_status(size_t output_height) NOEXCEPT;
static object_t to_outpoint_status(size_t output_height,
const history& history) NOEXCEPT;
static object_t to_outpoint_status(
const outpoint_subscription& sub) NOEXCEPT;
std::unique_ptr<object_t> make_status(
size_t output_height) const NOEXCEPT;
std::unique_ptr<object_t> make_status(size_t output_height,
const history& history) const NOEXCEPT;

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

// These are protected by notification strand.
std::set<system::chain::point> outpoint_subscriptions_{};
std::map<hash_digest, subscription> address_subscriptions_{};
std::map<point, outpoint_subscription> outpoint_subscriptions_{};
std::map<hash_digest, address_subscription> address_subscriptions_{};
};

} // namespace server
Expand Down
20 changes: 18 additions & 2 deletions src/protocols/electrum/protocol_electrum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,9 @@ bool protocol_electrum::handle_event(const code&, node::chase event_,
if (stopped())
return false;

// TODO: collapse three atomics this into a single enumeration.
switch (event_)
{
////case node::chase::transaction:
case node::chase::transaction:
case node::chase::organized:
{
if (subscribed_height_.load(relaxed))
Expand Down Expand Up @@ -185,6 +184,23 @@ bool protocol_electrum::handle_event(const code&, node::chase event_,
return true;
}

// reorganization
// ----------------------------------------------------------------------------
// outpoint subscriptions do not require modification.

// The chain has been reduced in height, clear all midstate cache and cursors.
void protocol_electrum::do_reorganized(node::header_t) NOEXCEPT
{
BC_ASSERT(notification_strand_.running_in_this_thread());

for (auto& [key, sub]: address_subscriptions_)
{
// writer.flush resets hash accumulator, sub.type remains unchanged.
sub.state.writer.flush();
sub.cursor = {};
}
}

BC_POP_WARNING()

} // namespace server
Expand Down
Loading
Loading