Skip to content

Commit 30b0892

Browse files
committed
Update block-out to allow overlapped block requests.
1 parent 5c40bbd commit 30b0892

File tree

2 files changed

+49
-20
lines changed

2 files changed

+49
-20
lines changed

include/bitcoin/node/protocols/protocol_block_out_106.hpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_OUT_106_HPP
2020
#define LIBBITCOIN_NODE_PROTOCOLS_PROTOCOL_BLOCK_OUT_106_HPP
2121

22+
#include <deque>
2223
#include <bitcoin/node/define.hpp>
2324
#include <bitcoin/node/protocols/protocol_peer.hpp>
2425

@@ -36,6 +37,7 @@ class BCN_API protocol_block_out_106
3637
const network::channel::ptr& channel) NOEXCEPT
3738
: node::protocol_peer(session, channel),
3839
node_witness_(session->network_settings().witness_node()),
40+
allow_overlapped_(session->node_settings().allow_overlapped),
3941
network::tracker<protocol_block_out_106>(session->log)
4042
{
4143
}
@@ -49,9 +51,6 @@ class BCN_API protocol_block_out_106
4951
protected:
5052
using get_data = network::messages::peer::get_data;
5153
using get_blocks = network::messages::peer::get_blocks;
52-
using inventory = network::messages::peer::inventory;
53-
using inventory_items = network::messages::peer::inventory_items;
54-
using inventory_items_ptr = std::shared_ptr<inventory_items>;
5554

5655
/// Block announcements are superseded by send_headers.
5756
virtual bool superseded() const NOEXCEPT;
@@ -67,18 +66,22 @@ class BCN_API protocol_block_out_106
6766
const get_blocks::cptr& message) NOEXCEPT;
6867
virtual bool handle_receive_get_data(const code& ec,
6968
const get_data::cptr& message) NOEXCEPT;
70-
virtual void send_block(const code& ec,
71-
const inventory_items_ptr& items) NOEXCEPT;
69+
virtual void send_block(const code& ec) NOEXCEPT;
7270

7371
private:
72+
using inventory = network::messages::peer::inventory;
73+
using inventory_item = network::messages::peer::inventory_item;
74+
using inventory_items = network::messages::peer::inventory_items;
75+
7476
inventory create_inventory(const get_blocks& locator) const NOEXCEPT;
77+
void merge_inventory(const inventory_items& items) NOEXCEPT;
7578

76-
private:
77-
// This is thread safe.
79+
// These are thread safe.
7880
const bool node_witness_;
81+
const bool allow_overlapped_;
7982

8083
// This is protected by strand.
81-
bool busy_{};
84+
std::deque<inventory_item> backlog_{};
8285
};
8386

8487
} // namespace node

src/protocols/protocol_block_out_106.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,35 +153,53 @@ bool protocol_block_out_106::handle_receive_get_data(const code& ec,
153153
return false;
154154
}
155155

156-
constexpr auto only = get_data::selector::blocks;
157-
const auto blocks = emplace_shared<inventory_items>(message->select(only));
158-
if (blocks->empty())
156+
const auto size = message->count(get_data::selector::blocks);
157+
if (is_zero(size))
159158
return true;
160159

161-
if (busy_)
160+
const auto total = ceilinged_add(backlog_.size(), size);
161+
if (total > messages::peer::max_inventory)
162+
{
163+
LOGR("Blocks requested (" << total << ") exceeds inv limit ["
164+
<< opposite() << "].");
165+
stop(network::error::protocol_violation);
166+
return false;
167+
}
168+
169+
// Satoshi sends overlapping get_data requests, but assumes that the
170+
// recipient is blocking *all traffic* until the previous is completed.
171+
// So to prevent frequent drops of satoshi peers, and not let one protocol
172+
// block all others, we must accumulate the requests into a backlog. If the
173+
// backlog exceeds the *individual* message limit we drop the peer.
174+
const auto idle = backlog_.empty();
175+
if (!allow_overlapped_ && !idle)
162176
{
163177
LOGR("Overlapping block requests [" << opposite() << "].");
164178
stop(network::error::protocol_violation);
165179
return false;
166180
}
167181

168-
busy_ = true;
169-
send_block(error::success, blocks);
182+
// Append the new inventory the request queue.
183+
merge_inventory(message->items);
184+
185+
// Bump the idle async send loop if no pending send.
186+
if (idle)
187+
send_block(error::success);
188+
170189
return true;
171190
}
172191

173192
// Outbound (block).
174193
// ----------------------------------------------------------------------------
175194

176-
void protocol_block_out_106::send_block(const code& ec,
177-
const inventory_items_ptr& items) NOEXCEPT
195+
void protocol_block_out_106::send_block(const code& ec) NOEXCEPT
178196
{
179197
BC_ASSERT(stranded());
180198
if (stopped(ec))
181199
return;
182200

183-
if (items->empty()) return;
184-
const auto item = pop(*items);
201+
if (backlog_.empty()) return;
202+
const auto& item = backlog_.front();
185203
const auto witness = item.is_witness_type();
186204
if (!node_witness_ && witness)
187205
{
@@ -203,14 +221,22 @@ void protocol_block_out_106::send_block(const code& ec,
203221
return;
204222
}
205223

224+
backlog_.pop_front();
206225
span<microseconds>(events::block_usecs, start);
207-
if (items->empty()) busy_ = false;
208-
SEND(messages::peer::block{ ptr }, send_block, _1, items);
226+
SEND(messages::peer::block{ ptr }, send_block, _1);
209227
}
210228

211229
// utilities
212230
// ----------------------------------------------------------------------------
213231

232+
void protocol_block_out_106::merge_inventory(
233+
const inventory_items& items) NOEXCEPT
234+
{
235+
for (const auto& item: items)
236+
if (item.is_block())
237+
backlog_.push_back(item);
238+
}
239+
214240
protocol_block_out_106::inventory protocol_block_out_106::create_inventory(
215241
const get_blocks& locator) const NOEXCEPT
216242
{

0 commit comments

Comments
 (0)