Skip to content

Commit 40547b0

Browse files
authored
Merge pull request #694 from evoskuil/master
Adapt to db changes, impl most of electrum send_get_status().
2 parents 56f2f1c + 8351ed6 commit 40547b0

6 files changed

Lines changed: 100 additions & 83 deletions

File tree

include/bitcoin/server/protocols/protocol_electrum.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ class BCS_API protocol_electrum
279279
array_t transform(const database::histories& histories) NOEXCEPT;
280280
array_t transform(const database::unspents& unspents) NOEXCEPT;
281281

282+
// Shared get_status implementation.
283+
bool send_get_status(const std::string& tx_hash, double txout_idx,
284+
const std::string& spk_hint) NOEXCEPT;
285+
282286
// These are thread safe.
283287
const options_t& options_;
284288
const bool turbo_;

src/protocols/electrum/protocol_electrum.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ using namespace system;
3333
using namespace network::rpc;
3434
using namespace std::placeholders;
3535

36+
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
37+
3638
// Electrum could be factored into protocols by version, with version-dependent
3739
// protocol attachment and with protocol derivations (see p2p). Currently all
3840
// methods apart from version are in one protocol class.
@@ -310,5 +312,7 @@ void protocol_electrum::do_scriptpubkey(node::address_t) NOEXCEPT
310312
}, 128, BIND(handle_send, _1));
311313
}
312314

315+
BC_POP_WARNING()
316+
313317
} // namespace server
314318
} // namespace libbitcoin

src/protocols/electrum/protocol_electrum_mempool.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ void protocol_electrum::handle_mempool_get_fee_histogram(const code& ec,
4545
}
4646

4747
// TODO: Empty array (of tuples), could be simulated with block fees.
48-
send_result(array_t{}, 42, BIND(complete, _1));
48+
////send_result(array_t{}, 42, BIND(complete, _1));
49+
send_code(error::not_implemented);
4950
}
5051

5152
void protocol_electrum::handle_mempool_get_info(const code& ec,

src/protocols/electrum/protocol_electrum_outputs.cpp

Lines changed: 78 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
#include <bitcoin/server/protocols/protocol_electrum.hpp>
2020

21+
#include <utility>
2122
#include <bitcoin/server/define.hpp>
2223

2324
namespace libbitcoin {
@@ -29,6 +30,8 @@ using namespace system;
2930
using namespace network::rpc;
3031
using namespace std::placeholders;
3132

33+
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
34+
3235
void protocol_electrum::handle_blockchain_utxo_get_address(const code& ec,
3336
rpc_interface::blockchain_utxo_get_address, const std::string& tx_hash,
3437
double index) NOEXCEPT
@@ -91,48 +94,32 @@ void protocol_electrum::handle_blockchain_outpoint_get_status(const code& ec,
9194
return;
9295
}
9396

94-
uint32_t index{};
95-
hash_digest hash{};
96-
if (!to_integer(index, txout_idx) ||
97-
!decode_hash(hash, tx_hash))
98-
{
99-
send_code(error::invalid_argument);
97+
send_get_status(tx_hash, txout_idx, spk_hint);
98+
}
99+
100+
void protocol_electrum::handle_blockchain_outpoint_subscribe(const code& ec,
101+
rpc_interface::blockchain_outpoint_subscribe, const std::string& tx_hash,
102+
double txout_idx, const std::string& spk_hint) NOEXCEPT
103+
{
104+
if (stopped(ec))
100105
return;
101-
}
102106

103-
// script is advisory, and should match prevout script.
104-
if (!spk_hint.empty())
107+
if (!at_least(electrum::version::v1_7))
105108
{
106-
data_chunk bytes{};
107-
if (!decode_base16(bytes, spk_hint))
108-
{
109-
send_code(error::invalid_argument);
110-
return;
111-
}
112-
113-
chain::script script{ std::move(bytes), false };
114-
if (!script.is_valid())
115-
{
116-
send_code(error::invalid_argument);
117-
return;
118-
}
109+
send_code(error::wrong_version);
110+
return;
119111
}
120112

121-
// TODO: implement outpoint status query.
122-
chain::point prevout{ hash, index };
123-
send_result(object_t
124-
{
125-
{ "height", 24 },
126-
{ "spender_txhash", "<hash>" },
127-
{ "spender_height", 42 }
113+
if (!send_get_status(tx_hash, txout_idx, spk_hint))
114+
return;
128115

129-
}, 16, BIND(complete, _1));
116+
// TODO: collect the outpoint into a limited notification set.
117+
subscribed_outpoint_.store(false, std::memory_order_relaxed);
130118
}
131119

132-
// TODO: implement.
133-
void protocol_electrum::handle_blockchain_outpoint_subscribe(const code& ec,
134-
rpc_interface::blockchain_outpoint_subscribe, const std::string& tx_hash,
135-
double txout_idx, const std::string& spk_hint) NOEXCEPT
120+
void protocol_electrum::handle_blockchain_outpoint_unsubscribe(const code& ec,
121+
rpc_interface::blockchain_outpoint_unsubscribe, const std::string& tx_hash,
122+
double txout_idx) NOEXCEPT
136123
{
137124
if (stopped(ec))
138125
return;
@@ -152,67 +139,87 @@ void protocol_electrum::handle_blockchain_outpoint_subscribe(const code& ec,
152139
return;
153140
}
154141

155-
// script is advisory, but should match prevout script.
142+
// TODO: remove outpoint subscription from notification set.
143+
chain::point prevout{ hash, index };
144+
const auto previous = subscribed_scriptpubkey_.load(
145+
std::memory_order_relaxed);
146+
147+
send_result(previous, 16, BIND(complete, _1));
148+
}
149+
150+
// utility.
151+
// ----------------------------------------------------------------------------
152+
153+
bool protocol_electrum::send_get_status(const std::string& tx_hash,
154+
double txout_idx, const std::string& spk_hint) NOEXCEPT
155+
{
156+
uint32_t index{};
157+
hash_digest hash{};
158+
if (!to_integer(index, txout_idx) || !decode_hash(hash, tx_hash))
159+
{
160+
send_code(error::invalid_argument);
161+
return false;
162+
}
163+
164+
// This is parsed for correctness but is not used.
165+
// Script is advisory, and should match output script.
156166
if (!spk_hint.empty())
157167
{
158168
data_chunk bytes{};
159169
if (!decode_base16(bytes, spk_hint))
160170
{
161171
send_code(error::invalid_argument);
162-
return;
172+
return false;
163173
}
164174

165175
chain::script script{ std::move(bytes), false };
166176
if (!script.is_valid())
167177
{
168178
send_code(error::invalid_argument);
169-
return;
179+
return false;
170180
}
171181
}
172182

173-
// TODO: collect the outpoint into a limited notification set.
174-
subscribed_outpoint_.store(false, std::memory_order_relaxed);
175-
176-
// TODO: implement outpoint status query.
177-
chain::point prevout{ hash, index };
178-
send_result(object_t
183+
const auto& query = archive();
184+
const auto tx = query.to_tx(hash);
185+
const auto output = query.to_output(tx, index);
186+
if (output.is_terminal())
179187
{
180-
{ "height", 24 },
181-
{ "spender_txhash", "<hash>" },
182-
{ "spender_height", 42 }
183-
184-
}, 16, BIND(complete, _1));
185-
}
186-
187-
void protocol_electrum::handle_blockchain_outpoint_unsubscribe(const code& ec,
188-
rpc_interface::blockchain_outpoint_unsubscribe, const std::string& tx_hash,
189-
double txout_idx) NOEXCEPT
190-
{
191-
if (stopped(ec))
192-
return;
188+
send_code(error::not_found);
189+
return false;
190+
}
193191

194-
if (!at_least(electrum::version::v1_7))
192+
// TODO: database query.///////////////////////////////////////////////////
193+
size_t height{ database::history::rooted_height };
194+
if (const auto block = query.find_confirmed_block(tx); block.is_terminal())
195195
{
196-
send_code(error::wrong_version);
197-
return;
196+
if (!query.is_confirmed_all_prevouts(tx))
197+
height = database::history::unrooted_height;
198198
}
199-
200-
uint32_t index{};
201-
hash_digest hash{};
202-
if (!to_integer(index, txout_idx) ||
203-
!decode_hash(hash, tx_hash))
199+
else if (!query.get_height(height, block))
204200
{
205-
send_code(error::invalid_argument);
206-
return;
201+
send_code(error::server_error);
202+
return false;
207203
}
204+
///////////////////////////////////////////////////////////////////////////
208205

209-
// TODO: remove outpoint subscription from notification set.
210-
chain::point prevout{ hash, index };
211-
const auto previous = subscribed_scriptpubkey_.load(
212-
std::memory_order_relaxed);
206+
// TODO: query tx spenders sorted history./////////////////////////////////
207+
const database::histories spenders{};
208+
///////////////////////////////////////////////////////////////////////////
213209

214-
send_result(previous, 16, BIND(complete, _1));
210+
auto result = object_t{ { "height", to_unsigned(height) } };
211+
if (!spenders.empty())
212+
{
213+
const auto& spender = spenders.front().tx;
214+
result["spender_txhash"] = encode_hash(spender.hash());
215+
result["spender_height"] = to_unsigned(spender.height());
216+
}
217+
218+
send_result(std::move(result), 128, BIND(complete, _1));
219+
return true;
215220
}
216221

222+
BC_POP_WARNING()
223+
217224
} // namespace server
218225
} // namespace libbitcoin

src/protocols/electrum/protocol_electrum_scripthash.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -364,21 +364,19 @@ void protocol_electrum::handle_blockchain_scripthash_unsubscribe(const code& ec,
364364
array_t protocol_electrum::transform(const database::histories& ins) NOEXCEPT
365365
{
366366
// Height is set to zero or max_size_t for unconfirmed history.
367+
// to_signed() conversion is simple but sacrifices top height bit (ok).
367368
static_assert(to_signed(max_size_t) == -1 && is_max(max_size_t));
368369

369370
array_t out(ins.size());
370371
std::ranges::transform(ins, out.begin(), [](const auto& in) NOEXCEPT
371372
{
372-
const auto height = in.tx.height();
373-
const bool unconfirmed = is_min(height) || is_max(height);
374-
375373
object_t object
376374
{
377-
{ "height", to_signed(height) },
375+
{ "height", to_signed(in.tx.height()) },
378376
{ "tx_hash", encode_hash(in.tx.hash()) }
379377
};
380378

381-
if (unconfirmed)
379+
if (!in.confirmed())
382380
{
383381
// A fee of max_uint64 implies missing prevout(s). This will happen
384382
// for a block-downloaded tx queried during parallel block download
@@ -400,13 +398,13 @@ array_t protocol_electrum::transform(const database::unspents& ins) NOEXCEPT
400398
array_t out(ins.size());
401399
std::ranges::transform(ins, out.begin(), [](const auto& in) NOEXCEPT
402400
{
403-
const auto& tx = in.tx;
401+
const auto& out = in.out;
404402
return object_t
405403
{
406-
{ "tx_hash", encode_hash(tx.point().hash()) },
407-
{ "tx_pos", tx.point().index() },
404+
{ "tx_hash", encode_hash(out.point().hash()) },
405+
{ "tx_pos", out.point().index() },
408406
{ "height", in.height },
409-
{ "value", tx.value() }
407+
{ "value", out.value() }
410408
};
411409
});
412410

test/protocols/electrum/electrum_mempool.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(electrum_tests, electrum_setup_fixture)
2323

2424
using namespace system;
2525
static const code wrong_version{ server::error::wrong_version };
26+
static const code not_implemented{ server::error::not_implemented };
2627

2728
// mempool.get_fee_histogram
2829

@@ -51,12 +52,14 @@ BOOST_AUTO_TEST_CASE(electrum__mempool_get_fee_histogram__extra_param__dropped)
5152
REQUIRE_NO_THROW_TRUE(response.at("dropped").as_bool());
5253
}
5354

54-
BOOST_AUTO_TEST_CASE(electrum__mempool_get_fee_histogram__empty_params__empty_array)
55+
BOOST_AUTO_TEST_CASE(electrum__mempool_get_fee_histogram__empty_params__not_implemented)
5556
{
5657
BOOST_REQUIRE(handshake(electrum::version::v1_2));
5758

5859
const auto response = get(R"({"id":603,"method":"mempool.get_fee_histogram","params":[]})" "\n");
59-
REQUIRE_NO_THROW_TRUE(response.at("result").as_array().empty());
60+
REQUIRE_NO_THROW_TRUE(response.at("error").as_object().at("code").is_int64());
61+
BOOST_REQUIRE_EQUAL(response.at("error").as_object().at("code").as_int64(), not_implemented.value());
62+
///REQUIRE_NO_THROW_TRUE(response.at("result").as_array().empty());
6063
}
6164

6265
// mempool.get_info

0 commit comments

Comments
 (0)