@@ -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+
214240protocol_block_out_106::inventory protocol_block_out_106::create_inventory (
215241 const get_blocks& locator) const NOEXCEPT
216242{
0 commit comments