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
26 changes: 15 additions & 11 deletions include/bitcoin/server/interfaces/electrum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct electrum_methods
method<"blockchain.transaction.get", string_t, optional<false>>{ "tx_hash", "verbose" },
method<"blockchain.transaction.get_merkle", string_t, number_t>{ "tx_hash", "height" },
method<"blockchain.transaction.id_from_pos", number_t, number_t, optional<false>>{ "height", "tx_pos", "merkle" },
method<"blockchain.transaction.testmempoolaccept", value_t>{ "raw_txs" },

/// Server methods.
method<"server.add_peer", object_t>{ "features" },
Expand All @@ -84,7 +85,8 @@ struct electrum_methods

/// Mempool methods.
method<"mempool.get_fee_histogram">{},
method<"mempool.get_info">{}
method<"mempool.get_info">{},
method<"mempool.recent">{}
};

template <typename... Args>
Expand Down Expand Up @@ -133,16 +135,18 @@ struct electrum_methods
using blockchain_transaction_get = at<31>;
using blockchain_transaction_get_merkle = at<32>;
using blockchain_transaction_id_from_position = at<33>;

using server_add_peer = at<34>;
using server_banner = at<35>;
using server_donation_address = at<36>;
using server_features = at<37>;
using server_peers_subscribe = at<38>;
using server_ping = at<39>;

using mempool_get_fee_histogram = at<40>;
using mempool_get_info = at<41>;
using blockchain_transaction_testmempoolaccept = at<34>;

using server_add_peer = at<35>;
using server_banner = at<36>;
using server_donation_address = at<37>;
using server_features = at<38>;
using server_peers_subscribe = at<39>;
using server_ping = at<40>;

using mempool_get_fee_histogram = at<41>;
using mempool_get_info = at<42>;
using mempool_recent = at<43>;
};

/// The electrum handshake, published separately as it is served by its own
Expand Down
6 changes: 4 additions & 2 deletions include/bitcoin/server/parsers/bitcoind_scan.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ namespace server {
/// Expand a scan object, a descriptor string or { "desc", "range" } object,
/// to its derived output scripts (false if malformed or underivable).
BCS_API bool expand_scan_object(system::chain::scripts& out,
const network::rpc::value_t& item) NOEXCEPT;
const network::rpc::value_t& item,
const system::wallet::context& context) NOEXCEPT;

/// As expand_scan_object, retaining embedded scripts and key origins.
BCS_API bool expand_scan_signings(
system::wallet::descriptor::signing::list& out,
const network::rpc::value_t& item) NOEXCEPT;
const network::rpc::value_t& item,
const system::wallet::context& context) NOEXCEPT;

/// Parse a derivation range, an end index or a [begin, end] pair.
BCS_API bool parse_scan_range(uint32_t& begin, uint32_t& end,
Expand Down
4 changes: 3 additions & 1 deletion include/bitcoin/server/protocols/protocol_bitcoind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class BCS_API protocol_bitcoind
p2kh_(session->server_settings().wallet.p2kh_prefix),
p2sh_(session->server_settings().wallet.p2sh_prefix),
flags_(session->system_settings().flags()),
witness_(session->server_settings().wallet.witness_prefix)
witness_(session->server_settings().wallet.witness_prefix),
context_(session->server_settings().wallet.to_context())
{
}

Expand Down Expand Up @@ -130,6 +131,7 @@ class BCS_API protocol_bitcoind
const uint8_t p2sh_;
const uint32_t flags_;
const std::string witness_;
const system::wallet::context context_;
};

} // namespace server
Expand Down
11 changes: 11 additions & 0 deletions include/bitcoin/server/protocols/protocol_electrum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class BCS_API protocol_electrum
witness_(session->server_settings().wallet.witness_prefix),
channel_(std::dynamic_pointer_cast<channel_t>(channel)),
notification_strand_(channel_->service().get_executor()),
ping_timer_(std::make_shared<network::deadline>(session->log,
channel->strand())),
network::tracker<protocol_electrum>(session->log)
{
}
Expand All @@ -61,6 +63,9 @@ class BCS_API protocol_electrum
void stopping(const code& ec) NOEXCEPT override;

protected:
void start_ping() NOEXCEPT;
void handle_ping(const code& ec) NOEXCEPT;

/// Terminal responder (attached last) for unclaimed methods.
void handle_unclaimed(
const network::rpc::request_t& request) NOEXCEPT override;
Expand Down Expand Up @@ -182,6 +187,9 @@ class BCS_API protocol_electrum
void handle_blockchain_transaction_get_merkle(const code& ec,
rpc_interface::blockchain_transaction_get_merkle,
const std::string& tx_hash, double height) NOEXCEPT;
void handle_blockchain_transaction_testmempoolaccept(const code& ec,
rpc_interface::blockchain_transaction_testmempoolaccept,
const interface::value_t& raw_txs) NOEXCEPT;
void handle_blockchain_transaction_id_from_position(const code& ec,
rpc_interface::blockchain_transaction_id_from_position, double height,
double tx_pos, bool merkle) NOEXCEPT;
Expand All @@ -205,6 +213,8 @@ class BCS_API protocol_electrum
/// Handlers (mempool).
void handle_mempool_get_fee_histogram(const code& ec,
rpc_interface::mempool_get_fee_histogram) NOEXCEPT;
void handle_mempool_recent(const code& ec,
rpc_interface::mempool_recent) NOEXCEPT;
void handle_mempool_get_info(const code& ec,
rpc_interface::mempool_get_info) NOEXCEPT;

Expand Down Expand Up @@ -385,6 +395,7 @@ class BCS_API protocol_electrum
const uint8_t p2sh_;
const uint32_t flags_;
const std::string witness_;
network::deadline::ptr ping_timer_;
std::atomic_bool stopping_{};
std::atomic_bool subscribed_height_{};
std::atomic_bool subscribed_header_{};
Expand Down
12 changes: 12 additions & 0 deletions include/bitcoin/server/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ class BCS_API settings
/// Maximum cumulative number of address subscriptions per channel.
uint32_t maximum_subscriptions{ 1'000'000 };

/// Interval between unrequested pings, zero disables (1.7, not http).
uint32_t ping_interval_seconds{ 0 };

/// Number of hex characters of data carried by an unrequested ping.
uint32_t ping_size{ 0 };

/// Minimum protocol version.
system::config::version protocol_minimum{ 1, 0, 0, 0 };

Expand Down Expand Up @@ -176,7 +182,13 @@ class BCS_API settings

system::config::byte p2kh_prefix;
system::config::byte p2sh_prefix;
system::config::byte wif_prefix;
std::string witness_prefix;
uint32_t hd_private_prefix;
uint32_t hd_public_prefix;

/// The configured prefixes as a wallet context.
system::wallet::context to_context() const NOEXCEPT;
};

struct bitcoind_server
Expand Down
35 changes: 35 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,26 @@ options_metadata parser::load_settings() THROWS
value<config::byte>(&configured.server.wallet.p2sh_prefix),
"The pay-to-script-hash address prefix, defaults to '5' (use '196' for testnet)."
)
(
"wallet.wif_prefix",
value<config::byte>(&configured.server.wallet.wif_prefix),
"The wallet import format prefix, defaults to '128' (use '239' for testnet)."
)
(
"wallet.witness_prefix",
value<std::string>(&configured.server.wallet.witness_prefix),
"The witness address prefix, defaults to 'bc' (use 'tb' for testnet)."
)
(
"wallet.hd_private_prefix",
value<uint32_t>(&configured.server.wallet.hd_private_prefix),
"The extended private key prefix, defaults to '76066276' (use '70615956' for testnet)."
)
(
"wallet.hd_public_prefix",
value<uint32_t>(&configured.server.wallet.hd_public_prefix),
"The extended public key prefix, defaults to '76067358' (use '71979618' for testnet)."
)

/* [admin] */
(
Expand Down Expand Up @@ -1358,6 +1373,16 @@ options_metadata parser::load_settings() THROWS
value<uint32_t>(&configured.server.electrum.maximum_subscriptions),
"The maximum allowed address subscriptions per channel, defaults to '1000000'."
)
(
"electrum.ping_interval_seconds",
value<uint32_t>(&configured.server.electrum.ping_interval_seconds),
"The seconds between unrequested pings, defaults to '0' (disabled)."
)
(
"electrum.ping_size",
value<uint32_t>(&configured.server.electrum.ping_size),
"The hex characters of unrequested ping data, defaults to '0'."
)
(
"electrum.protocol_minimum",
value<version>(&configured.server.electrum.protocol_minimum),
Expand Down Expand Up @@ -1470,6 +1495,16 @@ options_metadata parser::load_settings() THROWS
value<uint32_t>(&configured.server.sparrow.maximum_subscriptions),
"The maximum allowed address subscriptions per channel, defaults to '1000000'."
)
(
"sparrow.ping_interval_seconds",
value<uint32_t>(&configured.server.sparrow.ping_interval_seconds),
"The seconds between unrequested pings, defaults to '0' (disabled)."
)
(
"sparrow.ping_size",
value<uint32_t>(&configured.server.sparrow.ping_size),
"The hex characters of unrequested ping data, defaults to '0'."
)
(
"sparrow.protocol_minimum",
value<version>(&configured.server.sparrow.protocol_minimum),
Expand Down
9 changes: 5 additions & 4 deletions src/parsers/bitcoind_scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ using namespace network::rpc;
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)

// A scan object is a descriptor string or { "desc", "range" } object.
bool expand_scan_object(chain::scripts& out, const value_t& item) NOEXCEPT
bool expand_scan_object(chain::scripts& out, const value_t& item,
const wallet::context& context) NOEXCEPT
{
wallet::descriptor::signing::list signings{};
if (!expand_scan_signings(signings, item))
if (!expand_scan_signings(signings, item, context))
return false;

out.reserve(out.size() + signings.size());
Expand All @@ -43,7 +44,7 @@ bool expand_scan_object(chain::scripts& out, const value_t& item) NOEXCEPT
}

bool expand_scan_signings(wallet::descriptor::signing::list& out,
const value_t& item) NOEXCEPT
const value_t& item, const wallet::context& context) NOEXCEPT
{
std::string expression{};
uint32_t begin{};
Expand Down Expand Up @@ -78,7 +79,7 @@ bool expand_scan_signings(wallet::descriptor::signing::list& out,
return false;
}

const wallet::descriptor parsed{ expression };
const wallet::descriptor parsed{ expression, context };
if (!parsed || to_bool(shift_right(end, 31u)) ||
floored_subtract(end, begin) >= maximum_range)
return false;
Expand Down
6 changes: 3 additions & 3 deletions src/protocols/bitcoind/protocol_bitcoind_blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ void protocol_bitcoind_blockchain::do_scan_tx_out_set(
chain::scripts scripts{};
for (const auto& item: *objects)
{
if (!expand_scan_object(scripts, item))
if (!expand_scan_object(scripts, item, context_))
{
POST(complete_scan, error::bitcoind::invalid_address_or_key,
std::move(result), zero);
Expand Down Expand Up @@ -1277,7 +1277,7 @@ bool protocol_bitcoind_blockchain::handle_get_descriptor_activity(
chain::scripts derived{};
for (const auto& item: scanobjects)
{
if (!expand_scan_object(derived, item))
if (!expand_scan_object(derived, item, context_))
{
send_error(error::bitcoind::invalid_address_or_key);
return true;
Expand Down Expand Up @@ -1446,7 +1446,7 @@ bool protocol_bitcoind_blockchain::handle_scan_blocks(const code& ec,
chain::scripts scripts{};
for (const auto& item: scanobjects)
{
if (!expand_scan_object(scripts, item))
if (!expand_scan_object(scripts, item, context_))
{
send_error(error::bitcoind::invalid_address_or_key);
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/bitcoind/protocol_bitcoind_transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ bool protocol_bitcoind_transaction::handle_utxo_update_psbt(const code& ec,
descriptor::signing::list signings{};
for (const auto& item: descriptors)
{
if (!expand_scan_signings(signings, item))
if (!expand_scan_signings(signings, item, context_))
{
send_error(error::bitcoind::invalid_address_or_key);
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/protocols/bitcoind/protocol_bitcoind_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ bool protocol_bitcoind_utility::handle_derive_addresses(const code& ec,
if (stopped(ec))
return false;

const wallet::descriptor parsed{ expression };
const wallet::descriptor parsed{ expression, context_ };
if (!parsed)
{
send_error(error::bitcoind::invalid_address_or_key);
Expand Down Expand Up @@ -277,7 +277,7 @@ bool protocol_bitcoind_utility::handle_get_descriptor_info(const code& ec,
if (stopped(ec))
return false;

const wallet::descriptor parsed{ expression };
const wallet::descriptor parsed{ expression, context_ };
if (!parsed)
{
send_error(error::bitcoind::invalid_address_or_key);
Expand Down
5 changes: 5 additions & 0 deletions src/protocols/electrum/protocol_electrum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ void protocol_electrum::start() NOEXCEPT
SUBSCRIBE_RPC(handle_blockchain_transaction_get, _1, _2, _3, _4);
SUBSCRIBE_RPC(handle_blockchain_transaction_get_merkle, _1, _2, _3, _4);
SUBSCRIBE_RPC(handle_blockchain_transaction_id_from_position, _1, _2, _3, _4, _5);
SUBSCRIBE_RPC(handle_blockchain_transaction_testmempoolaccept, _1, _2, _3);

// Server methods.
SUBSCRIBE_RPC(handle_server_add_peer, _1, _2, _3);
Expand All @@ -112,6 +113,9 @@ void protocol_electrum::start() NOEXCEPT
// Mempool methods.
SUBSCRIBE_RPC(handle_mempool_get_fee_histogram, _1, _2);
SUBSCRIBE_RPC(handle_mempool_get_info, _1, _2);
SUBSCRIBE_RPC(handle_mempool_recent, _1, _2);

start_ping();
protocol_rpc<interface::electrum>::start();
}

Expand All @@ -121,6 +125,7 @@ void protocol_electrum::stopping(const code& ec) NOEXCEPT
BC_ASSERT(stranded());
stopping_.store(true);
unsubscribe_chase();
ping_timer_->stop();
protocol_rpc<interface::electrum>::stopping(ec);
}

Expand Down
16 changes: 16 additions & 0 deletions src/protocols/electrum/protocol_electrum_mempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ void protocol_electrum::handle_mempool_get_fee_histogram(const code& ec,
////send_code(error::not_implemented);
}

void protocol_electrum::handle_mempool_recent(const code& ec,
rpc_interface::mempool_recent) NOEXCEPT
{
if (stopped(ec))
return;

if (!at_least(electrum::version::v1_7))
{
send_code(error::electrum::bad_request);
return;
}

// There is no tx pool.
send_result(array_t{}, 42);
}

void protocol_electrum::handle_mempool_get_info(const code& ec,
rpc_interface::mempool_get_info) NOEXCEPT
{
Expand Down
34 changes: 33 additions & 1 deletion src/protocols/electrum/protocol_electrum_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,39 @@ void protocol_electrum::handle_server_peers_subscribe(const code& ec,
send_result(more_hosts(), 1024);
}

// Server does not send ping notifications (or perform other traffic shaping).
// An unrequested ping is a notification, which http cannot carry.
void protocol_electrum::start_ping() NOEXCEPT
{
BC_ASSERT(stranded());

const auto span = options().ping_interval_seconds;
if (stopped() || is_zero(span) || !at_least(electrum::version::v1_7) ||
!(websocket() || downgraded()))
return;

ping_timer_->start(BIND(handle_ping, _1), network::seconds(span));
}

void protocol_electrum::handle_ping(const code& ec) NOEXCEPT
{
BC_ASSERT(stranded());

if (stopped() || ec == network::error::operation_canceled)
return;

if (ec)
{
stop(ec);
return;
}

const auto size = options().ping_size;
send_notification("server.ping", array_t{ string_t(size, '0') },
add1(size));

start_ping();
}

void protocol_electrum::handle_server_ping(const code& ec,
rpc_interface::server_ping, double pong_len,
const std::string& data) NOEXCEPT
Expand Down
Loading
Loading