track opts when requesting blocks (not just if we requested them) (#3089)
This commit is contained in:
+26
-33
@@ -21,6 +21,8 @@ use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use lru_cache::LruCache;
|
||||
|
||||
use crate::chain;
|
||||
use crate::conn;
|
||||
use crate::core::core::hash::{Hash, Hashed};
|
||||
@@ -364,10 +366,11 @@ impl Peer {
|
||||
self.send(&h, msg::Type::GetTransaction)
|
||||
}
|
||||
|
||||
/// Sends a request for a specific block by hash
|
||||
pub fn send_block_request(&self, h: Hash) -> Result<(), Error> {
|
||||
/// Sends a request for a specific block by hash.
|
||||
/// Takes opts so we can track if this request was due to our node syncing or otherwise.
|
||||
pub fn send_block_request(&self, h: Hash, opts: chain::Options) -> Result<(), Error> {
|
||||
debug!("Requesting block {} from peer {}.", h, self.info.addr);
|
||||
self.tracking_adapter.push_req(h);
|
||||
self.tracking_adapter.push_req(h, opts);
|
||||
self.send(&h, msg::Type::GetBlock)
|
||||
}
|
||||
|
||||
@@ -429,51 +432,35 @@ impl Peer {
|
||||
#[derive(Clone)]
|
||||
struct TrackingAdapter {
|
||||
adapter: Arc<dyn NetAdapter>,
|
||||
known: Arc<RwLock<Vec<Hash>>>,
|
||||
requested: Arc<RwLock<Vec<Hash>>>,
|
||||
received: Arc<RwLock<LruCache<Hash, ()>>>,
|
||||
requested: Arc<RwLock<LruCache<Hash, chain::Options>>>,
|
||||
}
|
||||
|
||||
impl TrackingAdapter {
|
||||
fn new(adapter: Arc<dyn NetAdapter>) -> TrackingAdapter {
|
||||
TrackingAdapter {
|
||||
adapter: adapter,
|
||||
known: Arc::new(RwLock::new(Vec::with_capacity(MAX_TRACK_SIZE))),
|
||||
requested: Arc::new(RwLock::new(Vec::with_capacity(MAX_TRACK_SIZE))),
|
||||
received: Arc::new(RwLock::new(LruCache::new(MAX_TRACK_SIZE))),
|
||||
requested: Arc::new(RwLock::new(LruCache::new(MAX_TRACK_SIZE))),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
self.received.write().contains_key(&hash)
|
||||
}
|
||||
|
||||
fn push_recv(&self, hash: Hash) {
|
||||
let mut known = self.known.write();
|
||||
if known.len() > MAX_TRACK_SIZE {
|
||||
known.truncate(MAX_TRACK_SIZE);
|
||||
}
|
||||
if !known.contains(&hash) {
|
||||
known.insert(0, hash);
|
||||
}
|
||||
self.received.write().insert(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)
|
||||
/// Track a block or transaction hash requested by us.
|
||||
/// Track the opts alongside the hash so we know if this was due to us syncing or not.
|
||||
fn push_req(&self, hash: Hash, opts: chain::Options) {
|
||||
self.requested.write().insert(hash, opts);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
fn req_opts(&self, hash: Hash) -> Option<chain::Options> {
|
||||
self.requested.write().get_mut(&hash).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,11 +505,17 @@ impl ChainAdapter for TrackingAdapter {
|
||||
&self,
|
||||
b: core::Block,
|
||||
peer_info: &PeerInfo,
|
||||
_was_requested: bool,
|
||||
opts: chain::Options,
|
||||
) -> Result<bool, chain::Error> {
|
||||
let bh = b.hash();
|
||||
self.push_recv(bh);
|
||||
self.adapter.block_received(b, peer_info, self.has_req(bh))
|
||||
|
||||
// If we are currently tracking a request for this block then
|
||||
// use the opts specified when we made the request.
|
||||
// If we requested this block as part of sync then we want to
|
||||
// let our adapter know this when we receive it.
|
||||
let req_opts = self.req_opts(bh).unwrap_or(opts);
|
||||
self.adapter.block_received(b, peer_info, req_opts)
|
||||
}
|
||||
|
||||
fn compact_block_received(
|
||||
|
||||
+2
-2
@@ -577,10 +577,10 @@ impl ChainAdapter for Peers {
|
||||
&self,
|
||||
b: core::Block,
|
||||
peer_info: &PeerInfo,
|
||||
was_requested: bool,
|
||||
opts: chain::Options,
|
||||
) -> Result<bool, chain::Error> {
|
||||
let hash = b.hash();
|
||||
if !self.adapter.block_received(b, peer_info, was_requested)? {
|
||||
if !self.adapter.block_received(b, peer_info, opts)? {
|
||||
// if the peer sent us a block that's intrinsically bad
|
||||
// they are either mistaken or malevolent, both of which require a ban
|
||||
debug!(
|
||||
|
||||
+6
-3
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::chain;
|
||||
use crate::conn::{Message, MessageHandler, Tracker};
|
||||
use crate::core::core::{self, hash::Hash, hash::Hashed, CompactBlock};
|
||||
|
||||
@@ -162,9 +163,11 @@ impl MessageHandler for Protocol {
|
||||
);
|
||||
let b: core::Block = msg.body()?;
|
||||
|
||||
// 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.peer_info, false)?;
|
||||
// We default to NONE opts here as we do not know know yet why this block was
|
||||
// received.
|
||||
// If we requested this block from a peer due to our node syncing then
|
||||
// the peer adapter will override opts to reflect this.
|
||||
adapter.block_received(b, &self.peer_info, chain::Options::NONE)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -296,7 +296,12 @@ impl ChainAdapter for DummyAdapter {
|
||||
) -> Result<bool, chain::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
fn block_received(&self, _: core::Block, _: &PeerInfo, _: bool) -> Result<bool, chain::Error> {
|
||||
fn block_received(
|
||||
&self,
|
||||
_: core::Block,
|
||||
_: &PeerInfo,
|
||||
_: chain::Options,
|
||||
) -> Result<bool, chain::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
fn headers_received(
|
||||
|
||||
+1
-1
@@ -529,7 +529,7 @@ pub trait ChainAdapter: Sync + Send {
|
||||
&self,
|
||||
b: core::Block,
|
||||
peer_info: &PeerInfo,
|
||||
was_requested: bool,
|
||||
opts: chain::Options,
|
||||
) -> Result<bool, chain::Error>;
|
||||
|
||||
fn compact_block_received(
|
||||
|
||||
Reference in New Issue
Block a user