Skip to content

Commit d1ddc41

Browse files
authored
Merge pull request #752 from evoskuil/master
Refactor blockchain_block_headers().
2 parents b17be3b + 4bcb31b commit d1ddc41

3 files changed

Lines changed: 86 additions & 95 deletions

File tree

include/bitcoin/server/protocols/protocol_electrum.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ class BCS_API protocol_electrum
237237

238238
/// Common implementation for block_header/s.
239239
void blockchain_block_headers(size_t starting, size_t quantity,
240-
size_t waypoint, bool multiplicity) NOEXCEPT;
240+
size_t waypoint, bool single) NOEXCEPT;
241241

242242
/// Completion handlers (for long-running address queries).
243243
/// -----------------------------------------------------------------------

src/protocols/electrum/protocol_electrum_headers.cpp

Lines changed: 78 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void protocol_electrum::handle_blockchain_block_header(const code& ec,
160160
return;
161161
}
162162

163-
blockchain_block_headers(starting, one, waypoint, false);
163+
blockchain_block_headers(starting, one, waypoint, true);
164164
}
165165

166166
void protocol_electrum::handle_blockchain_block_headers(const code& ec,
@@ -194,12 +194,12 @@ void protocol_electrum::handle_blockchain_block_headers(const code& ec,
194194
return;
195195
}
196196

197-
blockchain_block_headers(starting, quantity, waypoint, true);
197+
blockchain_block_headers(starting, quantity, waypoint, false);
198198
}
199199

200200
// Common implementation for blockchain_block_header/s.
201201
void protocol_electrum::blockchain_block_headers(size_t starting,
202-
size_t quantity, size_t waypoint, bool multiplicity) NOEXCEPT
202+
size_t quantity, size_t waypoint, bool single) NOEXCEPT
203203
{
204204
const auto prove = !is_zero(quantity) && !is_zero(waypoint);
205205
const auto target = starting + sub1(quantity);
@@ -235,115 +235,108 @@ void protocol_electrum::blockchain_block_headers(size_t starting,
235235
const auto links = query.get_confirmed_headers(starting, count);
236236
auto size = two * chain::header::serialized_size() * links.size();
237237

238-
// Single header, no proof: spec requires a plain hex string result,
239-
// not a {"hex":…} or {"header":…} wrapper object.
240-
if (!multiplicity && !prove)
238+
if (single && !is_one(links.size()))
241239
{
242-
if (links.empty())
240+
send_code(error::server_error);
241+
return;
242+
}
243+
244+
value_t value{};
245+
246+
if (single && !prove)
247+
{
248+
const auto header = query.get_wire_header(links.front());
249+
if (header.empty())
243250
{
244251
send_code(error::server_error);
245252
return;
246253
}
254+
255+
value = encode_base16(header);
256+
}
257+
else
258+
{
259+
object_t result{};
260+
247261
if (at_least(electrum::version::v1_6))
248262
{
249-
const auto header = query.get_wire_header(links.front());
250-
if (header.empty())
263+
// Collect headers into array.
264+
array_t headers{};
265+
headers.reserve(links.size());
266+
for (const auto& link: links)
251267
{
252-
send_code(error::server_error);
253-
return;
268+
const auto header = query.get_wire_header(link);
269+
if (header.empty())
270+
{
271+
send_code(error::server_error);
272+
return;
273+
}
274+
275+
headers.push_back(encode_base16(header));
276+
}
277+
278+
if (single)
279+
{
280+
result["header"] = std::move(headers.front());
281+
}
282+
else
283+
{
284+
result["max"] = maximum_headers;
285+
result["count"] = links.size();
286+
result["headers"] = std::move(headers);
254287
}
255-
send_result(encode_base16(header), size + 42u);
256288
}
257289
else
258290
{
259-
std::string header(size, '\0');
260-
stream::out::fast sink{ header };
291+
// Stream headers into single buffer.
292+
std::string headers(size, '\0');
293+
stream::out::fast sink{ headers };
261294
write::base16::fast writer{ sink };
262-
if (!query.get_wire_header(writer, links.front()))
295+
for (const auto& link: links)
263296
{
264-
send_code(error::server_error);
265-
return;
297+
if (!query.get_wire_header(writer, link))
298+
{
299+
send_code(error::server_error);
300+
return;
301+
}
266302
}
267-
send_result(std::move(header), size + 42u);
268-
}
269-
return;
270-
}
271-
272-
value_t value{ object_t{} };
273-
auto& result = std::get<object_t>(value.value());
274-
if (multiplicity)
275-
{
276-
result["max"] = maximum_headers;
277-
result["count"] = links.size();
278-
}
279-
else if (links.empty())
280-
{
281-
send_code(error::server_error);
282-
return;
283-
}
284303

285-
if (at_least(electrum::version::v1_6))
286-
{
287-
array_t headers{};
288-
headers.reserve(links.size());
289-
for (const auto& link: links)
290-
{
291-
const auto header = query.get_wire_header(link);
292-
if (header.empty())
304+
if (single)
293305
{
294-
send_code(error::server_error);
295-
return;
306+
result["header"] = std::move(headers);
296307
}
308+
else
309+
{
310+
result["max"] = maximum_headers;
311+
result["count"] = links.size();
312+
result["hex"] = std::move(headers);
313+
}
314+
}
297315

298-
headers.push_back(encode_base16(header));
299-
};
300-
301-
if (multiplicity)
302-
result["headers"] = std::move(headers);
303-
else
304-
result["header"] = std::move(headers.front());
305-
}
306-
else
307-
{
308-
std::string headers(size, '\0');
309-
stream::out::fast sink{ headers };
310-
write::base16::fast writer{ sink };
311-
for (const auto& link: links)
316+
if (prove)
312317
{
313-
if (!query.get_wire_header(writer, link))
318+
// A very slim chance of inconsistency given an intervening reorg
319+
// because of get_merkle_root_and_proof() and height-based calcs.
320+
// This is acceptable as must be verified by caller in any case.
321+
hashes proof{};
322+
hash_digest root{};
323+
if (const auto code = query.get_merkle_root_and_proof(root, proof,
324+
target, waypoint))
314325
{
315-
send_code(error::server_error);
326+
send_code(code);
316327
return;
317328
}
318-
};
319329

320-
if (multiplicity)
321-
result["hex"] = std::move(headers);
322-
else
323-
result["header"] = std::move(headers);
324-
}
330+
array_t branch(proof.size());
331+
std::ranges::transform(proof, branch.begin(),
332+
[](const auto& hash) NOEXCEPT{ return encode_hash(hash); });
325333

326-
// There is a very slim chance of inconsistency given an intervening reorg
327-
// because of get_merkle_root_and_proof() use of height-based calculations.
328-
// This is acceptable as it must be verified by caller in any case.
329-
if (prove)
330-
{
331-
hashes proof{};
332-
hash_digest root{};
333-
if (const auto code = query.get_merkle_root_and_proof(root, proof,
334-
target, waypoint))
335-
{
336-
send_code(code);
337-
return;
334+
result["branch"] = std::move(branch);
335+
result["root"] = encode_hash(root);
336+
size += two * hash_size * add1(proof.size());
338337
}
339338

340-
array_t branch(proof.size());
341-
std::ranges::transform(proof, branch.begin(),
342-
[](const auto& hash) NOEXCEPT { return encode_hash(hash); });
343-
344-
result["branch"] = std::move(branch);
345-
result["root"] = encode_hash(root);
346-
size += two * hash_size * add1(proof.size());
339+
value = std::move(result);
347340
}
348341

349342
send_result(std::move(value), size + 42u);

src/protocols/electrum/protocol_electrum_server.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,6 @@ void protocol_electrum::handle_server_features(const code& ec,
118118
{ "pruning", null_t{} }
119119
};
120120

121-
if (!at_least(electrum::version::v1_7))
122-
{
123-
value["hash_function"] = string_t{ "sha256" };
124-
}
125-
126121
if (at_least(electrum::version::v1_7))
127122
{
128123
value["method_flavours"] = object_t
@@ -138,6 +133,10 @@ void protocol_electrum::handle_server_features(const code& ec,
138133
}
139134
};
140135
}
136+
else
137+
{
138+
value["hash_function"] = string_t{ "sha256" };
139+
}
141140

142141
send_result(std::move(value), 1024);
143142
}
@@ -187,20 +186,19 @@ void protocol_electrum::handle_server_ping(const code& ec,
187186
}
188187
else
189188
{
190-
size_t length{};
191189
data_chunk unused{};
192190

193191
// Base16 encoding validation expects whole octets (even char count).
194-
if (!to_integer(length, pong_len) || (length != data.length()) ||
192+
if (!to_integer(size, pong_len) || (size != data.length()) ||
195193
!decode_base16(unused, data))
196194
{
197195
send_code(error::invalid_argument);
198196
return;
199197
}
200198

201199
// Treat empty as default (args look the same, may not be correct).
202-
if (is_nonzero(length))
203-
value = string_t(length, '0');
200+
if (is_nonzero(size))
201+
value = string_t(size, '0');
204202
}
205203

206204
// Length is limited by maximum_request (DoS protection).

0 commit comments

Comments
 (0)