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

change(rpc): Add getpeerinfo RPC method #5951

Merged
merged 58 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
37d5afd
adds ValidateBlock request to state
arya2 Dec 15, 2022
6eb6048
adds `Request` enum in block verifier
arya2 Dec 15, 2022
162dedb
uses new Request in references to chain verifier
arya2 Dec 15, 2022
f7c5941
adds getblocktemplate proposal mode response type
arya2 Dec 15, 2022
9e0b8d1
makes getblocktemplate-rpcs feature in zebra-consensus select getbloc…
arya2 Dec 15, 2022
8420b75
Adds PR review revisions
arya2 Dec 16, 2022
e3b6d28
adds info log in CheckBlockProposalValidity
arya2 Dec 16, 2022
95cea02
Reverts replacement of match statement
arya2 Dec 16, 2022
31472a8
adds `GetBlockTemplate::capabilities` fn
arya2 Dec 16, 2022
ba302f7
conditions calling checkpoint verifier on !request.is_proposal
arya2 Dec 16, 2022
02b6758
updates references to validate_and_commit_non_finalized
arya2 Dec 16, 2022
2faa823
adds snapshot test, updates test vectors
arya2 Dec 16, 2022
32e6ac9
adds `should_count_metrics` to NonFinalizedState
arya2 Dec 16, 2022
a2ae3fb
Returns an error from chain verifier for block proposal requests belo…
arya2 Dec 16, 2022
40d002a
adds "proposal" to GET_BLOCK_TEMPLATE_CAPABILITIES_FIELD
arya2 Dec 17, 2022
1b658a1
Merge branch 'main' into gbt-proposal-mode
arya2 Dec 19, 2022
da1b308
adds back block::Request to zebra-consensus lib
arya2 Dec 19, 2022
cb26b8a
updates snapshots
arya2 Dec 19, 2022
78e95d9
Removes unnecessary network arg
arya2 Dec 22, 2022
0c55a67
skips req in tracing intstrument for read state
arya2 Dec 22, 2022
616d280
Moves out block proposal validation to its own fn
arya2 Dec 22, 2022
8978541
corrects `difficulty_threshold_is_valid` docs
arya2 Dec 23, 2022
4551cf0
Update zebra-state/src/service.rs
arya2 Jan 5, 2023
e888039
Merge branch 'main' into gbt-proposal-mode
arya2 Jan 5, 2023
5cc7378
Apply suggestions from code review
arya2 Jan 10, 2023
67bf095
Update zebra-rpc/src/methods/get_block_template_rpcs.rs
arya2 Jan 10, 2023
f774822
check best chain tip
arya2 Jan 9, 2023
d75e17a
Update zebra-state/src/service.rs
arya2 Jan 10, 2023
9ce7d8a
Applies cleanup suggestions from code review
arya2 Jan 10, 2023
8b89cba
updates gbt acceptance test to make a block proposal
arya2 Dec 19, 2022
0bf81c7
fixes json parsing mistake
arya2 Dec 19, 2022
1d043b1
adds retries
arya2 Dec 22, 2022
da54e85
returns reject reason if there are no retries left
arya2 Dec 22, 2022
ee0fc0b
moves result deserialization to RPCRequestClient method, adds docs, m…
arya2 Jan 2, 2023
a6ac270
moves sleep(EXPECTED_TX_TIME) out of loop
arya2 Jan 2, 2023
d58d474
updates/adds info logs in retry loop
arya2 Jan 2, 2023
f105b58
Revert "moves sleep(EXPECTED_TX_TIME) out of loop"
arya2 Jan 2, 2023
fc4bd13
adds `allow(dead_code)`
arya2 Jan 3, 2023
509f890
Merge branch 'main' into gbt-proposal-test
mergify[bot] Jan 12, 2023
516f17c
tests with curtime, mintime, & maxtime
arya2 Jan 12, 2023
60c7a13
Fixes doc comment
arya2 Jan 12, 2023
d2cae99
Logs error responses from chain_verifier CheckProposal requests
arya2 Jan 13, 2023
bb32c52
Removes retry loop, adds num_txs log
arya2 Jan 13, 2023
71c335f
removes verbose info log
arya2 Jan 13, 2023
f052448
sorts mempool_txs before generating merkle root
arya2 Jan 13, 2023
dc3f2fc
Merge branch 'fix-gbt-merkle-root' into gbt-proposal-test
arya2 Jan 13, 2023
8c51e13
Make imports conditional on a feature
arya2 Jan 16, 2023
dd2438b
Disable new CI tests until bugs are fixed
arya2 Jan 16, 2023
632fca6
adds support for getpeerinfo RPC
arya2 Jan 4, 2023
c24b618
adds vector test
arya2 Jan 6, 2023
836ba74
Always passes address_book to RpcServer
arya2 Jan 13, 2023
8f597a4
Update zebra-network/src/address_book.rs
arya2 Jan 16, 2023
4bf183e
Renames PeerObserver to AddressBookPeers
arya2 Jan 16, 2023
7b72395
adds getpeerinfo acceptance test
arya2 Jan 17, 2023
493412f
Asserts that addresses parse into SocketAddr
arya2 Jan 17, 2023
e80940e
adds launches_lightwalletd field to TestType::LaunchWithEmptyState an…
arya2 Jan 17, 2023
6c56341
renames peer_observer mod
arya2 Jan 17, 2023
f58b0f1
uses SocketAddr as `addr` field type in PeerInfo
arya2 Jan 17, 2023
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
1 change: 1 addition & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions zebra-chain/src/work/equihash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ impl Solution {

Ok(())
}

#[cfg(feature = "getblocktemplate-rpcs")]
/// Returns a [`Solution`] of `[0; SOLUTION_SIZE]` to be used in block proposals.
pub fn for_proposal() -> Self {
Self([0; SOLUTION_SIZE])
}
}

impl PartialEq<Solution> for Solution {
Expand Down
55 changes: 33 additions & 22 deletions zebra-network/src/address_book.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! The `AddressBook` manages information about what peers exist, when they were
//! seen, and what services they provide.

use std::{cmp::Reverse, iter::Extend, net::SocketAddr, time::Instant};
use std::{
cmp::Reverse,
iter::Extend,
net::SocketAddr,
sync::{Arc, Mutex},
time::Instant,
};

use chrono::Utc;
use ordered_map::OrderedMap;
Expand All @@ -12,9 +18,8 @@ use zebra_chain::parameters::Network;

use crate::{
constants, meta_addr::MetaAddrChange, protocol::external::canonical_socket_addr,
types::MetaAddr, PeerAddrState,
types::MetaAddr, AddressBookPeers, PeerAddrState,
};

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -288,7 +293,7 @@ impl AddressBook {
?updated,
?previous,
total_peers = self.by_addr.len(),
recent_peers = self.recently_live_peers(chrono_now).count(),
recent_peers = self.recently_live_peers(chrono_now).len(),
"calculated updated address book entry",
);

Expand Down Expand Up @@ -317,7 +322,7 @@ impl AddressBook {
?updated,
?previous,
total_peers = self.by_addr.len(),
recent_peers = self.recently_live_peers(chrono_now).count(),
recent_peers = self.recently_live_peers(chrono_now).len(),
"updated address book entry",
);

Expand All @@ -340,7 +345,7 @@ impl AddressBook {
surplus = ?surplus_peer,
?updated,
total_peers = self.by_addr.len(),
recent_peers = self.recently_live_peers(chrono_now).count(),
recent_peers = self.recently_live_peers(chrono_now).len(),
"removed surplus address book entry",
);
}
Expand Down Expand Up @@ -370,7 +375,7 @@ impl AddressBook {
trace!(
?removed_addr,
total_peers = self.by_addr.len(),
recent_peers = self.recently_live_peers(chrono_now).count(),
recent_peers = self.recently_live_peers(chrono_now).len(),
);

if let Some(entry) = self.by_addr.remove(&removed_addr) {
Expand Down Expand Up @@ -452,20 +457,6 @@ impl AddressBook {
.cloned()
}

/// Return an iterator over peers we've seen recently,
/// in reconnection attempt order.
pub fn recently_live_peers(
&'_ self,
now: chrono::DateTime<Utc>,
) -> impl Iterator<Item = MetaAddr> + DoubleEndedIterator + '_ {
let _guard = self.span.enter();

self.by_addr
.descending_values()
.filter(move |peer| peer.was_recently_live(now))
.cloned()
}

/// Returns the number of entries in this address book.
pub fn len(&self) -> usize {
self.by_addr.len()
Expand Down Expand Up @@ -501,7 +492,7 @@ impl AddressBook {
let failed = self.state_peers(PeerAddrState::Failed).count();
let attempt_pending = self.state_peers(PeerAddrState::AttemptPending).count();

let recently_live = self.recently_live_peers(now).count();
let recently_live = self.recently_live_peers(now).len();
let recently_stopped_responding = responded
.checked_sub(recently_live)
.expect("all recently live peers must have responded");
Expand Down Expand Up @@ -597,6 +588,26 @@ impl AddressBook {
}
}

impl AddressBookPeers for AddressBook {
fn recently_live_peers(&self, now: chrono::DateTime<Utc>) -> Vec<MetaAddr> {
let _guard = self.span.enter();

self.by_addr
.descending_values()
.filter(|peer| peer.was_recently_live(now))
.cloned()
.collect()
}
}

impl AddressBookPeers for Arc<Mutex<AddressBook>> {
fn recently_live_peers(&self, now: chrono::DateTime<Utc>) -> Vec<MetaAddr> {
self.lock()
.expect("panic in a previous thread that was holding the mutex")
.recently_live_peers(now)
}
}

impl Extend<MetaAddrChange> for AddressBook {
fn extend<T>(&mut self, iter: T)
where
Expand Down
17 changes: 17 additions & 0 deletions zebra-network/src/address_book_peers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! A AddressBookPeers trait for getting the [`MetaAddr`] of recently live peers.

use chrono::Utc;

use crate::meta_addr::MetaAddr;

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

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

/// Method signatures for getting [`MetaAddr`]s of recently live peers.
pub trait AddressBookPeers {
/// Return an Vec of peers we've seen recently, in reconnection attempt order.
fn recently_live_peers(&self, now: chrono::DateTime<Utc>) -> Vec<MetaAddr>;
}
25 changes: 25 additions & 0 deletions zebra-network/src/address_book_peers/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Mock [`AddressBookPeers`] for use in tests.

use crate::{meta_addr::MetaAddr, AddressBookPeers};

/// A mock [`AddressBookPeers`] implementation that's always empty.
#[derive(Default, Clone)]
pub struct MockAddressBookPeers {
/// Return value for mock `recently_live_peers` method.
recently_live_peers: Vec<MetaAddr>,
}

impl MockAddressBookPeers {
/// Creates a new [`MockAddressBookPeers`]
pub fn new(recently_live_peers: Vec<MetaAddr>) -> Self {
Self {
recently_live_peers,
}
}
}

impl AddressBookPeers for MockAddressBookPeers {
fn recently_live_peers(&self, _now: chrono::DateTime<chrono::Utc>) -> Vec<MetaAddr> {
self.recently_live_peers.clone()
}
}
2 changes: 2 additions & 0 deletions zebra-network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ extern crate bitflags;
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;

mod address_book;
pub mod address_book_peers;
mod address_book_updater;
mod config;
pub mod constants;
Expand Down Expand Up @@ -171,6 +172,7 @@ pub use crate::isolated::{

pub use crate::{
address_book::AddressBook,
address_book_peers::AddressBookPeers,
config::Config,
isolated::{connect_isolated, connect_isolated_tcp_direct},
meta_addr::PeerAddrState,
Expand Down
2 changes: 1 addition & 1 deletion zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,7 @@ pub enum GetBlock {
///
/// Also see the notes for the [`Rpc::get_best_block_hash`] and `get_block_hash` methods.
#[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct GetBlockHash(#[serde(with = "hex")] block::Hash);
pub struct GetBlockHash(#[serde(with = "hex")] pub block::Hash);

/// Response to a `z_gettreestate` RPC request.
///
Expand Down
58 changes: 37 additions & 21 deletions zebra-rpc/src/methods/get_block_template_rpcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use zebra_chain::{
transparent,
};
use zebra_consensus::VerifyChainError;
use zebra_network::AddressBookPeers;
use zebra_node_services::mempool;
use zebra_state::{ReadRequest, ReadResponse};

Expand All @@ -27,11 +28,11 @@ use crate::methods::{
},
get_block_template::{
check_miner_address, check_synced_to_tip, fetch_mempool_transactions,
fetch_state_tip_and_local_time, generate_coinbase_and_roots, validate_block_proposal,
fetch_state_tip_and_local_time, validate_block_proposal,
},
types::{
get_block_template::GetBlockTemplate, get_mining_info, hex_data::HexData,
long_poll::LongPollInput, submit_block,
long_poll::LongPollInput, peer_info::PeerInfo, submit_block,
},
},
height_from_signed_int, GetBlockHash, MISSING_BLOCK_ERROR_CODE,
Expand Down Expand Up @@ -149,10 +150,16 @@ pub trait GetBlockTemplateRpc {
) -> BoxFuture<Result<u64>> {
self.get_network_sol_ps(num_blocks, height)
}

/// Returns data about each connected network node.
///
/// zcashd reference: [`getpeerinfo`](https://zcash.github.io/rpc/getpeerinfo.html)
#[rpc(name = "getpeerinfo")]
fn get_peer_info(&self) -> BoxFuture<Result<Vec<PeerInfo>>>;
}

/// RPC method implementations.
pub struct GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
pub struct GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
where
Mempool: Service<
mempool::Request,
Expand All @@ -170,6 +177,7 @@ where
+ Sync
+ 'static,
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
AddressBook: AddressBookPeers,
{
// Configuration
//
Expand Down Expand Up @@ -197,10 +205,13 @@ where

/// The chain sync status, used for checking if Zebra is likely close to the network chain tip.
sync_status: SyncStatus,

/// Address book of peers, used for `getpeerinfo`.
address_book: AddressBook,
}

impl<Mempool, State, Tip, ChainVerifier, SyncStatus>
GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
impl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
where
Mempool: Service<
mempool::Request,
Expand All @@ -222,8 +233,10 @@ where
+ Sync
+ 'static,
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
AddressBook: AddressBookPeers + Clone + Send + Sync + 'static,
{
/// Create a new instance of the handler for getblocktemplate RPCs.
#[allow(clippy::too_many_arguments)]
pub fn new(
network: Network,
mining_config: config::Config,
Expand All @@ -232,6 +245,7 @@ where
latest_chain_tip: Tip,
chain_verifier: ChainVerifier,
sync_status: SyncStatus,
address_book: AddressBook,
) -> Self {
Self {
network,
Expand All @@ -241,12 +255,13 @@ where
latest_chain_tip,
chain_verifier,
sync_status,
address_book,
}
}
}

impl<Mempool, State, Tip, ChainVerifier, SyncStatus> GetBlockTemplateRpc
for GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
impl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook> GetBlockTemplateRpc
for GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
where
Mempool: Service<
mempool::Request,
Expand All @@ -271,6 +286,7 @@ where
+ 'static,
<ChainVerifier as Service<zebra_consensus::Request>>::Future: Send,
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
AddressBook: AddressBookPeers + Clone + Send + Sync + 'static,
{
fn get_block_count(&self) -> Result<u32> {
best_chain_tip_height(&self.latest_chain_tip).map(|height| height.0)
Expand Down Expand Up @@ -566,24 +582,12 @@ where

// - After this point, the template only depends on the previously fetched data.

// Generate the coinbase transaction and default roots
//
// TODO: move expensive root, hash, and tree cryptography to a rayon thread?
let (coinbase_txn, default_roots) = generate_coinbase_and_roots(
let response = GetBlockTemplate::new(
network,
next_block_height,
miner_address,
&mempool_txs,
chain_tip_and_local_time.history_tree.clone(),
COINBASE_LIKE_ZCASHD,
);

let response = GetBlockTemplate::new(
&chain_tip_and_local_time,
server_long_poll_id,
coinbase_txn,
&mempool_txs,
default_roots,
mempool_txs,
submit_old,
COINBASE_LIKE_ZCASHD,
);
Expand Down Expand Up @@ -716,6 +720,18 @@ where
}
.boxed()
}

fn get_peer_info(&self) -> BoxFuture<Result<Vec<PeerInfo>>> {
let address_book = self.address_book.clone();
async move {
Ok(address_book
.recently_live_peers(chrono::Utc::now())
.into_iter()
.map(PeerInfo::from)
.collect())
}
.boxed()
}
}

// Put support functions in a submodule, to keep this file small.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ where
+ Sync
+ 'static,
{
let Ok(block) = block_proposal_bytes.zcash_deserialize_into() else {
let Ok(block) = block_proposal_bytes.zcash_deserialize_into::<block::Block>() else {
return Ok(ProposalRejectReason::Rejected.into())
};

Expand All @@ -125,7 +125,14 @@ where

Ok(chain_verifier_response
.map(|_hash| ProposalResponse::Valid)
.unwrap_or_else(|_| ProposalRejectReason::Rejected.into())
.unwrap_or_else(|verify_chain_error| {
tracing::info!(
verify_chain_error,
"Got error response from chain_verifier CheckProposal request"
);

ProposalRejectReason::Rejected.into()
})
.into())
}

Expand Down
1 change: 1 addition & 0 deletions zebra-rpc/src/methods/get_block_template_rpcs/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ pub mod get_block_template;
pub mod get_mining_info;
pub mod hex_data;
pub mod long_poll;
pub mod peer_info;
pub mod submit_block;
pub mod transaction;
Loading