Track blocks we requested, always broadcast otherwise (#2349)

This commit is contained in:
Ignotus Peverell
2019-01-12 09:28:03 -08:00
committed by GitHub
parent cf8f9d609a
commit f9a20aef0d
6 changed files with 69 additions and 46 deletions
+38 -16
View File
@@ -261,7 +261,7 @@ impl Peer {
/// Sends the provided block to the remote peer. The request may be dropped
/// if the remote peer is known to already have the block.
pub fn send_block(&self, b: &core::Block) -> Result<bool, Error> {
if !self.tracking_adapter.has(b.hash()) {
if !self.tracking_adapter.has_recv(b.hash()) {
trace!("Send block {} to {}", b.hash(), self.info.addr);
self.connection
.as_ref()
@@ -280,7 +280,7 @@ impl Peer {
}
pub fn send_compact_block(&self, b: &core::CompactBlock) -> Result<bool, Error> {
if !self.tracking_adapter.has(b.hash()) {
if !self.tracking_adapter.has_recv(b.hash()) {
trace!("Send compact block {} to {}", b.hash(), self.info.addr);
self.connection
.as_ref()
@@ -299,7 +299,7 @@ impl Peer {
}
pub fn send_header(&self, bh: &core::BlockHeader) -> Result<bool, Error> {
if !self.tracking_adapter.has(bh.hash()) {
if !self.tracking_adapter.has_recv(bh.hash()) {
debug!("Send header {} to {}", bh.hash(), self.info.addr);
self.connection
.as_ref()
@@ -318,7 +318,7 @@ impl Peer {
}
pub fn send_tx_kernel_hash(&self, h: Hash) -> Result<bool, Error> {
if !self.tracking_adapter.has(h) {
if !self.tracking_adapter.has_recv(h) {
debug!("Send tx kernel hash {} to {}", h, self.info.addr);
self.connection
.as_ref()
@@ -350,7 +350,7 @@ impl Peer {
return self.send_tx_kernel_hash(kernel.hash());
}
if !self.tracking_adapter.has(kernel.hash()) {
if !self.tracking_adapter.has_recv(kernel.hash()) {
debug!("Send full tx {} to {}", tx.hash(), self.info.addr);
self.connection
.as_ref()
@@ -405,6 +405,7 @@ impl Peer {
/// Sends a request for a specific block by hash
pub fn send_block_request(&self, h: Hash) -> Result<(), Error> {
debug!("Requesting block {} from peer {}.", h, self.info.addr);
self.tracking_adapter.push_req(h);
self.connection
.as_ref()
.unwrap()
@@ -499,29 +500,32 @@ fn stop_with_connection(connection: &conn::Tracker) {
}
/// Adapter implementation that forwards everything to an underlying adapter
/// but keeps track of the block and transaction hashes that were received.
/// but keeps track of the block and transaction hashes that were requested or
/// received.
#[derive(Clone)]
struct TrackingAdapter {
adapter: Arc<dyn NetAdapter>,
known: Arc<RwLock<Vec<Hash>>>,
requested: Arc<RwLock<Vec<Hash>>>,
}
impl TrackingAdapter {
fn new(adapter: Arc<dyn NetAdapter>) -> TrackingAdapter {
TrackingAdapter {
adapter: adapter,
known: Arc::new(RwLock::new(vec![])),
known: Arc::new(RwLock::new(Vec::with_capacity(MAX_TRACK_SIZE))),
requested: Arc::new(RwLock::new(Vec::with_capacity(MAX_TRACK_SIZE))),
}
}
fn has(&self, hash: Hash) -> bool {
fn has_recv(&self, hash: Hash) -> bool {
let known = self.known.read();
// may become too slow, an ordered set (by timestamp for eviction) may
// end up being a better choice
known.contains(&hash)
}
fn push(&self, hash: Hash) {
fn push_recv(&self, hash: Hash) {
let mut known = self.known.write();
if known.len() > MAX_TRACK_SIZE {
known.truncate(MAX_TRACK_SIZE);
@@ -530,6 +534,23 @@ impl TrackingAdapter {
known.insert(0, hash);
}
}
fn has_req(&self, hash: Hash) -> bool {
let requested = self.requested.read();
// may become too slow, an ordered set (by timestamp for eviction) may
// end up being a better choice
requested.contains(&hash)
}
fn push_req(&self, hash: Hash) {
let mut requested = self.requested.write();
if requested.len() > MAX_TRACK_SIZE {
requested.truncate(MAX_TRACK_SIZE);
}
if !requested.contains(&hash) {
requested.insert(0, hash);
}
}
}
impl ChainAdapter for TrackingAdapter {
@@ -546,7 +567,7 @@ impl ChainAdapter for TrackingAdapter {
}
fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr) {
self.push(kernel_hash);
self.push_recv(kernel_hash);
self.adapter.tx_kernel_received(kernel_hash, addr)
}
@@ -556,23 +577,24 @@ impl ChainAdapter for TrackingAdapter {
// correctly.
if !stem {
let kernel = &tx.kernels()[0];
self.push(kernel.hash());
self.push_recv(kernel.hash());
}
self.adapter.transaction_received(tx, stem)
}
fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool {
self.push(b.hash());
self.adapter.block_received(b, addr)
fn block_received(&self, b: core::Block, addr: SocketAddr, _was_requested: bool) -> bool {
let bh = b.hash();
self.push_recv(bh);
self.adapter.block_received(b, addr, self.has_req(bh))
}
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool {
self.push(cb.hash());
self.push_recv(cb.hash());
self.adapter.compact_block_received(cb, addr)
}
fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool {
self.push(bh.hash());
self.push_recv(bh.hash());
self.adapter.header_received(bh, addr)
}
+2 -2
View File
@@ -554,9 +554,9 @@ impl ChainAdapter for Peers {
self.adapter.transaction_received(tx, stem)
}
fn block_received(&self, b: core::Block, peer_addr: SocketAddr) -> bool {
fn block_received(&self, b: core::Block, peer_addr: SocketAddr, was_requested: bool) -> bool {
let hash = b.hash();
if !self.adapter.block_received(b, peer_addr) {
if !self.adapter.block_received(b, peer_addr, was_requested) {
// if the peer sent us a block that's intrinsically bad
// they are either mistaken or malevolent, both of which require a ban
debug!(
+3 -1
View File
@@ -154,7 +154,9 @@ impl MessageHandler for Protocol {
);
let b: core::Block = msg.body()?;
adapter.block_received(b, self.addr);
// we can't know at this level whether we requested the block or not,
// the boolean should be properly set in higher level adapter
adapter.block_received(b, self.addr, false);
Ok(None)
}
+1 -1
View File
@@ -242,7 +242,7 @@ impl ChainAdapter for DummyAdapter {
fn header_received(&self, _bh: core::BlockHeader, _addr: SocketAddr) -> bool {
true
}
fn block_received(&self, _: core::Block, _: SocketAddr) -> bool {
fn block_received(&self, _: core::Block, _: SocketAddr, _: bool) -> bool {
true
}
fn headers_received(&self, _: &[core::BlockHeader], _: SocketAddr) -> bool {
+1 -1
View File
@@ -355,7 +355,7 @@ pub trait ChainAdapter: Sync + Send {
/// block could be handled properly and is not deemed defective by the
/// chain. Returning false means the block will never be valid and
/// may result in the peer being banned.
fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool;
fn block_received(&self, b: core::Block, addr: SocketAddr, was_requested: bool) -> bool;
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool;