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

Inbound FindBlocks and FindHeaders #1347

Merged
merged 29 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
680d270
implement inbound `FindBlocks`
oxarbitrage Nov 20, 2020
88cd84b
Apply suggestions from code review
yaahc Nov 24, 2020
aed0170
Apply some suggestions from code review
oxarbitrage Nov 24, 2020
e81b823
fix build after suggestions
oxarbitrage Nov 24, 2020
33ee423
remove non needed iterator
oxarbitrage Nov 24, 2020
5f8c93c
fix stop parameter
oxarbitrage Nov 24, 2020
b3c7f9e
handle empty response
oxarbitrage Nov 24, 2020
20bc94d
remove redundant call in
yaahc Nov 24, 2020
e967c97
Update zebra-state/src/service.rs
oxarbitrage Nov 24, 2020
24904ce
Merge branch 'main' into issue1306
oxarbitrage Nov 24, 2020
9124315
rustfmt
oxarbitrage Nov 25, 2020
7a74fc1
Apply suggestions from code review
oxarbitrage Nov 25, 2020
187534d
handle request before having any chain tip
oxarbitrage Nov 25, 2020
b8ee598
fix known blocks matching with our chain
oxarbitrage Nov 25, 2020
190d7cf
remove known blocks empty check
oxarbitrage Nov 25, 2020
d5c126a
clippy
oxarbitrage Nov 25, 2020
973a85c
Split state height functions into "any chain" and "best chain"
teor2345 Nov 26, 2020
92940f4
Split `find_chain_hashes` into smaller functions
teor2345 Nov 26, 2020
c43c255
Refactor - use more iterator methods
teor2345 Nov 26, 2020
266278f
Rename `hash()` to `best_hash()`
teor2345 Nov 26, 2020
5d3723c
Document the only remaining use of an "any chain" method
teor2345 Nov 26, 2020
cd061fd
Rename the best chain block method to `best_block`
teor2345 Nov 26, 2020
76070a5
Improve some logs and comments
teor2345 Nov 26, 2020
a50ebfa
Handle inbound peer FindHeaders requests
teor2345 Nov 26, 2020
2813c1c
Move fmt utilities to zebra_chain::fmt
teor2345 Nov 26, 2020
6174d23
Summarise Debug for some Message variants
teor2345 Nov 26, 2020
adaf13f
Fix some comments
teor2345 Nov 26, 2020
8d96d43
Refactor to avoid an unwrap
teor2345 Nov 30, 2020
4d8bbd5
Clean up the rest of the expanded `derive(Debug)`
teor2345 Nov 30, 2020
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
7 changes: 7 additions & 0 deletions zebra-state/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,11 @@ pub enum Request {
/// Code making this request should apply a timeout layer to the service to
/// handle missing UTXOs.
AwaitUtxo(transparent::OutPoint),

/// Find intersection of provided and best chain and returns block hashes ahead.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
///
/// Returns
///
/// [`Response::Hashes(Vec<block::Hash>)`](Response::Hashes) with max of 500 block hashes.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
GetHashes(Vec<block::Hash>, Option<block::Hash>),
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 4 additions & 1 deletion zebra-state/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub enum Response {
/// Response to [`Request::Block`] with the specified block.
Block(Option<Arc<Block>>),

/// The response to a `AwaitUtxo` request
/// The response to a `AwaitUtxo` request.
Utxo(transparent::Output),

/// The response to a `GetHashes` request.
Hashes(Option<Vec<block::Hash>>),
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}
93 changes: 93 additions & 0 deletions zebra-state/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,95 @@ impl StateService {
state: IterState::NonFinalized(hash),
}
}

/// Return an iterator over the finalized blocks of the chain
/// starting (and descending) from the block identified by `height`.
///
/// The block identified by `height` is included in the chain of blocks yielded
/// by the iterator.
pub fn chain_finalized(&self, height: block::Height) -> Iter<'_> {
Iter {
service: self,
state: IterState::Finalized(height),
}
}
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

/// Return a list of blocks ahead given a list of blocks.
yaahc marked this conversation as resolved.
Show resolved Hide resolved
///
/// 1. Make sure we have the list of blocks provided in our chain.
/// 2. Get a max of 500 hashes ahead of the provided tip.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
pub fn find_chain_hashes(
&self,
block_locator: Vec<block::Hash>,
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
stop: Option<block::Hash>,
) -> Option<Vec<block::Hash>> {
let locator_tip_hash = block_locator.first()?;
let locator_tip_height = self.height_by_hash(*locator_tip_hash)?;
let chain = self.chain_finalized(locator_tip_height);
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

tracing::info!(
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
"REQUESTED TIP: {:?} {:?}",
locator_tip_height,
locator_tip_hash
);

// Block locator are not continuous but we need to make sure all the blocks
// provided are in our chain and in the right order.
let mut collect_block_locator: Vec<block::Hash> = Vec::new();
let mut index = 0;
for block in chain {
// We get out of the loop as soon as we collect a vector of equal
// lenght of the provided.
if collect_block_locator.len() == block_locator.len() {
break;
}

if block.hash() == block_locator[index] {
collect_block_locator.push(block.hash());
index += 1
}
}

// If the 2 vectors are not equal we cant continue.
if collect_block_locator != block_locator {
return None;
}
teor2345 marked this conversation as resolved.
Show resolved Hide resolved

// The number of next hashes to return.
let max_results = 500;
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved

// Compute a new tip, make sure it is below our chain tip.
let (chain_tip_height, ..) = self.tip().expect("tip must always be available?");
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
let new_tip = block::Height(std::cmp::min(
locator_tip_height.0 + max_results,
chain_tip_height.0,
));

// Get a new chain starting at the new "requested" tip.
let new_chain = self.chain_finalized(new_tip);

let mut res: Vec<block::Hash> = Vec::new();
for block in new_chain {
// If we get the requested tip we are over
if block.hash() == *locator_tip_hash {
break;
}

// Check the stop parameter
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
if stop.is_some() && stop.unwrap() == block.hash() {
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
break;
}

// Insert in reverse order
res.insert(0, block.hash());
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
tracing::info!(
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
"RESPONSE: {:?} {:?}",
self.height_by_hash(block.hash())?,
block.hash()
);
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
}
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
Some(res)
}
}

struct Iter<'a> {
Expand Down Expand Up @@ -452,6 +541,10 @@ impl Service<Request> for StateService {

fut.boxed()
}
Request::GetHashes(hashes, stop) => {
let res = self.find_chain_hashes(hashes, stop);
async move { Ok(Response::Hashes(res)) }.boxed()
}
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions zebrad/src/components/inbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,17 @@ impl Service<zn::Request> for Inbound {
debug!("ignoring unimplemented request");
async { Ok(zn::Response::Nil) }.boxed()
}
zn::Request::FindBlocks { .. } => {
debug!("ignoring unimplemented request");
async { Ok(zn::Response::Nil) }.boxed()
zn::Request::FindBlocks { known_blocks, stop } => {
let request = zs::Request::GetHashes(known_blocks, stop);
let mut state = self.state.clone();
async move {
let fut = state.ready_and().await?.call(request).await?;
match fut {
zs::Response::Hashes(Some(hashes)) => Ok(zn::Response::BlockHashes(hashes)),
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
_ => Ok(zn::Response::Nil),
}
}
.boxed()
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
}
zn::Request::FindHeaders { .. } => {
debug!("ignoring unimplemented request");
Expand Down