Skip to content

Commit c164dee

Browse files
authored
Merge pull request #1022 from evoskuil/master
Implement witness pruning.
2 parents 9eb864d + 1e9a605 commit c164dee

4 files changed

Lines changed: 70 additions & 12 deletions

File tree

include/bitcoin/node/protocols/protocol_block_in_31800.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class BCN_API protocol_block_in_31800
4141
session->system_settings().top_checkpoint().height()),
4242
block_type_(session->network_settings().witness_node() ?
4343
type_id::witness_block : type_id::block),
44+
node_pruned_(session->network_settings().pruned_node()),
4445
map_(chaser_check::empty_map()),
4546
network::tracker<protocol_block_in_31800>(session->log)
4647
{
@@ -84,13 +85,15 @@ class BCN_API protocol_block_in_31800
8485

8586
void restore(const map_ptr& map) NOEXCEPT;
8687
bool is_under_checkpoint(size_t height) const NOEXCEPT;
88+
type_id to_block_type(const database::association& item) const NOEXCEPT;
8789
void handle_put_hashes(const code& ec, size_t count) NOEXCEPT;
8890
void handle_get_hashes(const code& ec, const map_ptr& map,
8991
const job::ptr& job) NOEXCEPT;
9092

9193
// These are thread safe.
9294
const size_t top_checkpoint_height_;
9395
const type_id block_type_;
96+
const bool node_pruned_;
9497

9598
// These are protected by strand.
9699
map_ptr map_;

include/bitcoin/node/protocols/protocol_block_out_106.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class BCN_API protocol_block_out_106
3636
protocol_block_out_106(const auto& session,
3737
const network::channel::ptr& channel) NOEXCEPT
3838
: node::protocol_peer(session, channel),
39+
top_checkpoint_height_(
40+
session->system_settings().top_checkpoint().height()),
41+
node_pruned_(session->network_settings().pruned_node()),
3942
node_witness_(session->network_settings().witness_node()),
4043
allow_overlapped_(session->node_settings().allow_overlapped),
4144
network::tracker<protocol_block_out_106>(session->log)
@@ -73,10 +76,13 @@ class BCN_API protocol_block_out_106
7376
using inventory_item = network::messages::peer::inventory_item;
7477
using inventory_items = network::messages::peer::inventory_items;
7578

79+
bool is_under_checkpoint(const database::header_link& link) NOEXCEPT;
7680
inventory create_inventory(const get_blocks& locator) const NOEXCEPT;
7781
void merge_inventory(const inventory_items& items) NOEXCEPT;
7882

7983
// These are thread safe.
84+
const size_t top_checkpoint_height_;
85+
const bool node_pruned_;
8086
const bool node_witness_;
8187
const bool allow_overlapped_;
8288

src/protocols/protocol_block_in_31800.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ get_data protocol_block_in_31800::create_get_data(
254254
// bip144: get_data uses witness type_id but inv does not.
255255
std::for_each(map.pos_begin(), map.pos_end(), [&](const auto& item) NOEXCEPT
256256
{
257-
data.items.emplace_back(block_type_, item.hash);
257+
data.items.emplace_back(to_block_type(item), item.hash);
258258
});
259259

260260
return data;
@@ -277,8 +277,6 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
277277
const auto& block = message->block;
278278
const auto hash = block.hash();
279279
const auto it = map_->find(hash);
280-
auto& query = archive();
281-
282280
if (it == map_->end())
283281
{
284282
// Allow unrequested block, not counted toward performance.
@@ -287,15 +285,21 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
287285
return true;
288286
}
289287

288+
auto& query = archive();
290289
const auto link = it->link;
291290
const auto height = it->context.height;
291+
const auto checked = is_under_checkpoint(height);
292+
const auto bypass = checked || query.is_milestone(link);
293+
if (bypass && node_pruned_ && block.is_segregated())
294+
{
295+
LOGR("Unexpected witness from [" << opposite() << "].");
296+
stop(system::error::unexpected_witness);
297+
return false;
298+
}
292299

293300
// Identify block.
294301
// ........................................................................
295302

296-
const auto checked = is_under_checkpoint(height);
297-
const auto bypass = checked || query.is_milestone(link);
298-
299303
// Tx commitments and malleation are checked under bypass. Invalidity is
300304
// only stored when a strong header has been stored, later to be found out
301305
// as invalid and not malleable. Stored invalidity prevents repeat
@@ -363,11 +367,16 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
363367
// While check could be called here, it's more optimal to defer to validate, as
364368
// requiring only identity here allows the use of the simplified block_view.
365369
code protocol_block_in_31800::identify(const chain::block_view& block,
366-
const chain::context& ctx, bool) const NOEXCEPT
370+
const chain::context& ctx, bool bypass) const NOEXCEPT
367371
{
368-
code ec{};
372+
if (const auto ec = block.identify())
373+
return ec;
374+
375+
// Bypass witness commitment check for stripped blocks.
376+
if (bypass && node_pruned_)
377+
return error::success;
369378

370-
if (((ec = block.identify())) || ((ec = block.identify(ctx))))
379+
if (const auto ec = block.identify(ctx))
371380
return ec;
372381

373382
return error::success;
@@ -420,14 +429,24 @@ void protocol_block_in_31800::handle_get_hashes(const code& ec,
420429
POST(send_get_data, map, job);
421430
}
422431

423-
// checkpoint
432+
// utility
424433
// ----------------------------------------------------------------------------
425434

426435
bool protocol_block_in_31800::is_under_checkpoint(size_t height) const NOEXCEPT
427436
{
428437
return height <= top_checkpoint_height_;
429438
}
430439

440+
type_id protocol_block_in_31800::to_block_type(
441+
const association& item) const NOEXCEPT
442+
{
443+
const auto stripped = node_pruned_ &&
444+
(is_under_checkpoint(item.context.height) ||
445+
archive().is_milestone(item.link));
446+
447+
return stripped ? type_id::block : block_type_;
448+
}
449+
431450
BC_POP_WARNING()
432451
BC_POP_WARNING()
433452
BC_POP_WARNING()

src/protocols/protocol_block_out_106.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ using namespace network;
3232
using namespace std::chrono;
3333
using namespace std::placeholders;
3434

35+
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
3536
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
3637
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
3738

39+
// This protocol provides witness support despite 106 being much older than
40+
// bip144. This is because protocols are splot on the version negotiated in the
41+
// p2p handshake. Witness is enabled via a service bit. Protocols should also
42+
// be factored based on relevant service bits but that is not yet implemented.
43+
3844
// start/stop
3945
// ----------------------------------------------------------------------------
4046

@@ -202,17 +208,27 @@ void protocol_block_out_106::send_block(const code& ec) NOEXCEPT
202208
if (backlog_.empty()) return;
203209
const auto& item = backlog_.front();
204210
const auto witness = item.is_witness_type();
205-
if (!node_witness_ && witness)
211+
if (witness && !node_witness_)
206212
{
207213
LOGR("Unsupported witness get_data from [" << opposite() << "].");
208214
stop(network::error::protocol_violation);
209215
return;
210216
}
211217

212218
const auto& query = archive();
213-
const auto start = logger::now();
214219
const auto link = query.to_header(item.hash);
220+
if (witness && node_witness_ && node_pruned_ &&
221+
(is_under_checkpoint(link) || query.is_milestone(link)))
222+
{
223+
LOGR("Request of witness for stripped block "
224+
<< encode_hash(item.hash) << " from [" << opposite() << "].");
225+
226+
// The peer should not be asking for this block with witness.
227+
stop(system::error::not_found);
228+
return;
229+
}
215230

231+
const auto start = logger::now();
216232
node::messages::block out{ query.get_wire_block(link, witness), witness };
217233
if (out.block_data.empty())
218234
{
@@ -255,6 +271,20 @@ protocol_block_out_106::inventory protocol_block_out_106::create_inventory(
255271
);
256272
}
257273

274+
bool protocol_block_out_106::is_under_checkpoint(
275+
const database::header_link& link) NOEXCEPT
276+
{
277+
const auto height = archive().get_height(link);
278+
if (height.is_terminal())
279+
{
280+
fault(database::error::integrity);
281+
return false;
282+
}
283+
284+
return height <= top_checkpoint_height_;
285+
}
286+
287+
BC_POP_WARNING()
258288
BC_POP_WARNING()
259289
BC_POP_WARNING()
260290

0 commit comments

Comments
 (0)