Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix syncer download order and add sync tests #3168

Merged
merged 20 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0c4210b
Refactor so that RetryLimit::Future is std::marker::Sync
teor2345 Dec 31, 2021
8282985
Make the syncer future std::marker::Send by spawning tips futures
teor2345 Dec 31, 2021
12730d3
Download synced blocks in chain order, not HashSet order
teor2345 Jan 2, 2022
629c1d9
Improve MockService failure messages
teor2345 Dec 31, 2021
214fa3e
Add closure-based responses to the MockService API
teor2345 Jan 2, 2022
aa74132
Move MockChainTip to zebra-chain
teor2345 Dec 31, 2021
706e73d
Add a MockChainTipSender type alias
teor2345 Dec 31, 2021
3eeb1ee
Support MockChainTip in ChainSync and its downloader
teor2345 Dec 31, 2021
bd6bae0
Add syncer tests for obtain tips, extend tips, and wrong block hashes
teor2345 Dec 7, 2021
5c92fb5
Add block too high tests for obtain tips and extend tips
teor2345 Jan 3, 2022
ea92fe1
Add syncer tests for duplicate FindBlocks response hashes
teor2345 Jan 3, 2022
b480ce2
Allow longer request delays for mocked services in syncer tests
teor2345 Jan 3, 2022
19e7caa
Increase the lookahead height, because in-order syncs are more efficient
teor2345 Jan 4, 2022
4ccc53a
Spawn the syncer into its own task
teor2345 Jan 4, 2022
2018fbf
Merge branch 'main' into sync-height-limit-test
teor2345 Jan 4, 2022
a933eda
Merge branch 'main' into sync-height-limit-test
teor2345 Jan 5, 2022
731ffb4
Merge branch 'main' into sync-height-limit-test
teor2345 Jan 6, 2022
f4d6d4f
Merge branch 'main' into sync-height-limit-test
teor2345 Jan 6, 2022
a227db6
Fix unreachable message
teor2345 Jan 6, 2022
508b3ea
Merge branch 'main' into sync-height-limit-test
mergify[bot] Jan 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion zebra-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"

[features]
default = []
proptest-impl = ["proptest", "proptest-derive", "zebra-test", "rand", "rand_chacha"]
proptest-impl = ["proptest", "proptest-derive", "zebra-test", "rand", "rand_chacha", "tokio"]
bench = ["zebra-test"]

[dependencies]
Expand Down Expand Up @@ -60,6 +60,7 @@ proptest-derive = { version = "0.3.0", optional = true }

rand = { version = "0.8", optional = true }
rand_chacha = { version = "0.3", optional = true }
tokio = { version = "1.15.0", optional = true }

# ZF deps
ed25519-zebra = "3.0.0"
Expand Down
3 changes: 3 additions & 0 deletions zebra-chain/src/chain_tip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use std::sync::Arc;

use crate::{block, transaction};

#[cfg(any(test, feature = "proptest-impl"))]
pub mod mock;

/// An interface for querying the chain tip.
///
/// This trait helps avoid dependencies between:
Expand Down
48 changes: 48 additions & 0 deletions zebra-chain/src/chain_tip/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Mock [`ChainTip`]s for use in tests.

use std::sync::Arc;

use tokio::sync::watch;

use crate::{block, chain_tip::ChainTip, transaction};

/// A sender that sets the `best_tip_height` of a [`MockChainTip`].]
pub type MockChainTipSender = watch::Sender<Option<block::Height>>;

/// A mock [`ChainTip`] implementation that allows setting the `best_tip_height` externally.
#[derive(Clone, Debug)]
pub struct MockChainTip {
best_tip_height: watch::Receiver<Option<block::Height>>,
}

impl MockChainTip {
/// Create a new [`MockChainTip`].
///
/// Returns the [`MockChainTip`] instance and the endpoint to modiy the current best tip
/// height.
///
/// Initially, the best tip height is [`None`].
pub fn new() -> (Self, MockChainTipSender) {
let (sender, receiver) = watch::channel(None);

let mock_chain_tip = MockChainTip {
best_tip_height: receiver,
};

(mock_chain_tip, sender)
}
}

impl ChainTip for MockChainTip {
fn best_tip_height(&self) -> Option<block::Height> {
*self.best_tip_height.borrow()
}

fn best_tip_hash(&self) -> Option<block::Hash> {
unreachable!("Method not used in tests");
}

fn best_tip_mined_transaction_ids(&self) -> Arc<[transaction::Hash]> {
unreachable!("Method not used in tests");
}
}
49 changes: 6 additions & 43 deletions zebra-network/src/peer/minimum_peer_version/tests.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,17 @@
use std::sync::Arc;
//! Test utilities and tests for minimum network peer version requirements.

use tokio::sync::watch;

use zebra_chain::{block, chain_tip::ChainTip, parameters::Network, transaction};
use zebra_chain::{
chain_tip::mock::{MockChainTip, MockChainTipSender},
parameters::Network,
};

use super::MinimumPeerVersion;

#[cfg(test)]
mod prop;

/// A mock [`ChainTip`] implementation that allows setting the `best_tip_height` externally.
#[derive(Clone)]
pub struct MockChainTip {
best_tip_height: watch::Receiver<Option<block::Height>>,
}

impl MockChainTip {
/// Create a new [`MockChainTip`].
///
/// Returns the [`MockChainTip`] instance and the endpoint to modiy the current best tip
/// height.
///
/// Initially, the best tip height is [`None`].
pub fn new() -> (Self, watch::Sender<Option<block::Height>>) {
let (sender, receiver) = watch::channel(None);

let mock_chain_tip = MockChainTip {
best_tip_height: receiver,
};

(mock_chain_tip, sender)
}
}

impl ChainTip for MockChainTip {
fn best_tip_height(&self) -> Option<block::Height> {
*self.best_tip_height.borrow()
}

fn best_tip_hash(&self) -> Option<block::Hash> {
unreachable!("Method not used in `MinimumPeerVersion` tests");
}

fn best_tip_mined_transaction_ids(&self) -> Arc<[transaction::Hash]> {
unreachable!("Method not used in `MinimumPeerVersion` tests");
}
}

impl MinimumPeerVersion<MockChainTip> {
pub fn with_mock_chain_tip(network: Network) -> (Self, watch::Sender<Option<block::Height>>) {
pub fn with_mock_chain_tip(network: Network) -> (Self, MockChainTipSender) {
let (chain_tip, best_tip_height) = MockChainTip::new();
let minimum_peer_version = MinimumPeerVersion::new(chain_tip, network);

Expand Down
22 changes: 10 additions & 12 deletions zebra-network/src/policies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use tower::retry::Policy;
/// A very basic retry policy with a limited number of retry attempts.
///
/// XXX Remove this when https://github.com/tower-rs/tower/pull/414 lands.
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct RetryLimit {
remaining_tries: usize,
}
Expand All @@ -21,25 +21,23 @@ impl RetryLimit {
}

impl<Req: Clone + std::fmt::Debug, Res, E: std::fmt::Debug> Policy<Req, Res, E> for RetryLimit {
type Future = Pin<Box<dyn Future<Output = Self> + Send + 'static>>;
type Future = Pin<Box<dyn Future<Output = Self> + Send + Sync + 'static>>;

fn retry(&self, req: &Req, result: Result<&Res, &E>) -> Option<Self::Future> {
if let Err(e) = result {
if self.remaining_tries > 0 {
tracing::debug!(?req, ?e, remaining_tries = self.remaining_tries, "retrying");

let remaining_tries = self.remaining_tries - 1;
let retry_outcome = RetryLimit { remaining_tries };

Some(
async move {
// Let other tasks run, so we're more likely to choose a different peer,
// and so that any notfound inv entries win the race to the PeerSet.
//
// TODO: move syncer retries into the PeerSet,
// so we always choose different peers (#3235)
tokio::task::yield_now().await;
RetryLimit { remaining_tries }
}
.boxed(),
// Let other tasks run, so we're more likely to choose a different peer,
// and so that any notfound inv entries win the race to the PeerSet.
//
// TODO: move syncer retries into the PeerSet,
// so we always choose different peers (#3235)
Box::pin(tokio::task::yield_now().map(move |()| retry_outcome)),
)
} else {
None
Expand Down
Loading