change(rpc): Add getpeerinfo RPC method (#5951)
* adds ValidateBlock request to state * adds `Request` enum in block verifier skips solution check for BlockProposal requests calls CheckBlockValidity instead of Commit block for BlockProposal requests * uses new Request in references to chain verifier * adds getblocktemplate proposal mode response type * makes getblocktemplate-rpcs feature in zebra-consensus select getblocktemplate-rpcs in zebra-state * Adds PR review revisions * adds info log in CheckBlockProposalValidity * Reverts replacement of match statement * adds `GetBlockTemplate::capabilities` fn * conditions calling checkpoint verifier on !request.is_proposal * updates references to validate_and_commit_non_finalized * adds snapshot test, updates test vectors * adds `should_count_metrics` to NonFinalizedState * Returns an error from chain verifier for block proposal requests below checkpoint height adds feature flags * adds "proposal" to GET_BLOCK_TEMPLATE_CAPABILITIES_FIELD * adds back block::Request to zebra-consensus lib * updates snapshots * Removes unnecessary network arg * skips req in tracing intstrument for read state * Moves out block proposal validation to its own fn * corrects `difficulty_threshold_is_valid` docs adds/fixes some comments, adds TODOs general cleanup from a self-review. * Update zebra-state/src/service.rs * Apply suggestions from code review Co-authored-by: teor <teor@riseup.net> * Update zebra-rpc/src/methods/get_block_template_rpcs.rs Co-authored-by: teor <teor@riseup.net> * check best chain tip * Update zebra-state/src/service.rs Co-authored-by: teor <teor@riseup.net> * Applies cleanup suggestions from code review * updates gbt acceptance test to make a block proposal * fixes json parsing mistake * adds retries * returns reject reason if there are no retries left * moves result deserialization to RPCRequestClient method, adds docs, moves jsonrpc_core to dev-dependencies * moves sleep(EXPECTED_TX_TIME) out of loop * updates/adds info logs in retry loop * Revert "moves sleep(EXPECTED_TX_TIME) out of loop" This reverts commit f7f0926f4050519687a79afc16656c3f345c004b. * adds `allow(dead_code)` * tests with curtime, mintime, & maxtime * Fixes doc comment * Logs error responses from chain_verifier CheckProposal requests * Removes retry loop, adds num_txs log * removes verbose info log * sorts mempool_txs before generating merkle root * Make imports conditional on a feature * Disable new CI tests until bugs are fixed * adds support for getpeerinfo RPC * adds vector test * Always passes address_book to RpcServer * Update zebra-network/src/address_book.rs Co-authored-by: teor <teor@riseup.net> * Renames PeerObserver to AddressBookPeers * adds getpeerinfo acceptance test * Asserts that addresses parse into SocketAddr * adds launches_lightwalletd field to TestType::LaunchWithEmptyState and uses it from the get_peer_info test * renames peer_observer mod * uses SocketAddr as `addr` field type in PeerInfo Co-authored-by: teor <teor@riseup.net> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
dcf30679bf
commit
1bb8a9c924
|
@ -1,7 +1,13 @@
|
||||||
//! The `AddressBook` manages information about what peers exist, when they were
|
//! The `AddressBook` manages information about what peers exist, when they were
|
||||||
//! seen, and what services they provide.
|
//! 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 chrono::Utc;
|
||||||
use ordered_map::OrderedMap;
|
use ordered_map::OrderedMap;
|
||||||
|
@ -12,9 +18,8 @@ use zebra_chain::parameters::Network;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants, meta_addr::MetaAddrChange, protocol::external::canonical_socket_addr,
|
constants, meta_addr::MetaAddrChange, protocol::external::canonical_socket_addr,
|
||||||
types::MetaAddr, PeerAddrState,
|
types::MetaAddr, AddressBookPeers, PeerAddrState,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
@ -288,7 +293,7 @@ impl AddressBook {
|
||||||
?updated,
|
?updated,
|
||||||
?previous,
|
?previous,
|
||||||
total_peers = self.by_addr.len(),
|
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",
|
"calculated updated address book entry",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -317,7 +322,7 @@ impl AddressBook {
|
||||||
?updated,
|
?updated,
|
||||||
?previous,
|
?previous,
|
||||||
total_peers = self.by_addr.len(),
|
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",
|
"updated address book entry",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -340,7 +345,7 @@ impl AddressBook {
|
||||||
surplus = ?surplus_peer,
|
surplus = ?surplus_peer,
|
||||||
?updated,
|
?updated,
|
||||||
total_peers = self.by_addr.len(),
|
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",
|
"removed surplus address book entry",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -370,7 +375,7 @@ impl AddressBook {
|
||||||
trace!(
|
trace!(
|
||||||
?removed_addr,
|
?removed_addr,
|
||||||
total_peers = self.by_addr.len(),
|
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) {
|
if let Some(entry) = self.by_addr.remove(&removed_addr) {
|
||||||
|
@ -452,20 +457,6 @@ impl AddressBook {
|
||||||
.cloned()
|
.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.
|
/// Returns the number of entries in this address book.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.by_addr.len()
|
self.by_addr.len()
|
||||||
|
@ -501,7 +492,7 @@ impl AddressBook {
|
||||||
let failed = self.state_peers(PeerAddrState::Failed).count();
|
let failed = self.state_peers(PeerAddrState::Failed).count();
|
||||||
let attempt_pending = self.state_peers(PeerAddrState::AttemptPending).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
|
let recently_stopped_responding = responded
|
||||||
.checked_sub(recently_live)
|
.checked_sub(recently_live)
|
||||||
.expect("all recently live peers must have responded");
|
.expect("all recently live peers must have responded");
|
||||||
|
@ -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 {
|
impl Extend<MetaAddrChange> for AddressBook {
|
||||||
fn extend<T>(&mut self, iter: T)
|
fn extend<T>(&mut self, iter: T)
|
||||||
where
|
where
|
||||||
|
|
|
@ -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>;
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -144,6 +144,7 @@ extern crate bitflags;
|
||||||
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
mod address_book;
|
mod address_book;
|
||||||
|
pub mod address_book_peers;
|
||||||
mod address_book_updater;
|
mod address_book_updater;
|
||||||
mod config;
|
mod config;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
@ -171,6 +172,7 @@ pub use crate::isolated::{
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
address_book::AddressBook,
|
address_book::AddressBook,
|
||||||
|
address_book_peers::AddressBookPeers,
|
||||||
config::Config,
|
config::Config,
|
||||||
isolated::{connect_isolated, connect_isolated_tcp_direct},
|
isolated::{connect_isolated, connect_isolated_tcp_direct},
|
||||||
meta_addr::PeerAddrState,
|
meta_addr::PeerAddrState,
|
||||||
|
|
|
@ -16,6 +16,7 @@ use zebra_chain::{
|
||||||
transparent,
|
transparent,
|
||||||
};
|
};
|
||||||
use zebra_consensus::VerifyChainError;
|
use zebra_consensus::VerifyChainError;
|
||||||
|
use zebra_network::AddressBookPeers;
|
||||||
use zebra_node_services::mempool;
|
use zebra_node_services::mempool;
|
||||||
use zebra_state::{ReadRequest, ReadResponse};
|
use zebra_state::{ReadRequest, ReadResponse};
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ use crate::methods::{
|
||||||
},
|
},
|
||||||
types::{
|
types::{
|
||||||
get_block_template::GetBlockTemplate, get_mining_info, hex_data::HexData,
|
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,
|
height_from_signed_int, GetBlockHash, MISSING_BLOCK_ERROR_CODE,
|
||||||
|
@ -149,10 +150,16 @@ pub trait GetBlockTemplateRpc {
|
||||||
) -> BoxFuture<Result<u64>> {
|
) -> BoxFuture<Result<u64>> {
|
||||||
self.get_network_sol_ps(num_blocks, height)
|
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.
|
/// RPC method implementations.
|
||||||
pub struct GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
|
pub struct GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
|
||||||
where
|
where
|
||||||
Mempool: Service<
|
Mempool: Service<
|
||||||
mempool::Request,
|
mempool::Request,
|
||||||
|
@ -170,6 +177,7 @@ where
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
||||||
|
AddressBook: AddressBookPeers,
|
||||||
{
|
{
|
||||||
// Configuration
|
// Configuration
|
||||||
//
|
//
|
||||||
|
@ -197,10 +205,13 @@ where
|
||||||
|
|
||||||
/// The chain sync status, used for checking if Zebra is likely close to the network chain tip.
|
/// The chain sync status, used for checking if Zebra is likely close to the network chain tip.
|
||||||
sync_status: SyncStatus,
|
sync_status: SyncStatus,
|
||||||
|
|
||||||
|
/// Address book of peers, used for `getpeerinfo`.
|
||||||
|
address_book: AddressBook,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mempool, State, Tip, ChainVerifier, SyncStatus>
|
impl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
|
||||||
GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
|
GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
|
||||||
where
|
where
|
||||||
Mempool: Service<
|
Mempool: Service<
|
||||||
mempool::Request,
|
mempool::Request,
|
||||||
|
@ -222,8 +233,10 @@ where
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
||||||
|
AddressBook: AddressBookPeers + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
/// Create a new instance of the handler for getblocktemplate RPCs.
|
/// Create a new instance of the handler for getblocktemplate RPCs.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
network: Network,
|
network: Network,
|
||||||
mining_config: config::Config,
|
mining_config: config::Config,
|
||||||
|
@ -232,6 +245,7 @@ where
|
||||||
latest_chain_tip: Tip,
|
latest_chain_tip: Tip,
|
||||||
chain_verifier: ChainVerifier,
|
chain_verifier: ChainVerifier,
|
||||||
sync_status: SyncStatus,
|
sync_status: SyncStatus,
|
||||||
|
address_book: AddressBook,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
network,
|
network,
|
||||||
|
@ -241,12 +255,13 @@ where
|
||||||
latest_chain_tip,
|
latest_chain_tip,
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
sync_status,
|
sync_status,
|
||||||
|
address_book,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mempool, State, Tip, ChainVerifier, SyncStatus> GetBlockTemplateRpc
|
impl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook> GetBlockTemplateRpc
|
||||||
for GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus>
|
for GetBlockTemplateRpcImpl<Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>
|
||||||
where
|
where
|
||||||
Mempool: Service<
|
Mempool: Service<
|
||||||
mempool::Request,
|
mempool::Request,
|
||||||
|
@ -271,6 +286,7 @@ where
|
||||||
+ 'static,
|
+ 'static,
|
||||||
<ChainVerifier as Service<zebra_consensus::Request>>::Future: Send,
|
<ChainVerifier as Service<zebra_consensus::Request>>::Future: Send,
|
||||||
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
||||||
|
AddressBook: AddressBookPeers + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn get_block_count(&self) -> Result<u32> {
|
fn get_block_count(&self) -> Result<u32> {
|
||||||
best_chain_tip_height(&self.latest_chain_tip).map(|height| height.0)
|
best_chain_tip_height(&self.latest_chain_tip).map(|height| height.0)
|
||||||
|
@ -704,6 +720,18 @@ where
|
||||||
}
|
}
|
||||||
.boxed()
|
.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.
|
// Put support functions in a submodule, to keep this file small.
|
||||||
|
|
|
@ -5,5 +5,6 @@ pub mod get_block_template;
|
||||||
pub mod get_mining_info;
|
pub mod get_mining_info;
|
||||||
pub mod hex_data;
|
pub mod hex_data;
|
||||||
pub mod long_poll;
|
pub mod long_poll;
|
||||||
|
pub mod peer_info;
|
||||||
pub mod submit_block;
|
pub mod submit_block;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
//! An array of [`PeerInfo`] is the output of the `getpeerinfo` RPC method.
|
||||||
|
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use zebra_network::types::MetaAddr;
|
||||||
|
|
||||||
|
/// Item of the `getpeerinfo` response
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct PeerInfo {
|
||||||
|
/// The IP address and port of the peer
|
||||||
|
pub addr: SocketAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MetaAddr> for PeerInfo {
|
||||||
|
fn from(meta_addr: MetaAddr) -> Self {
|
||||||
|
Self {
|
||||||
|
addr: meta_addr.addr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
//! cargo insta test --review --features getblocktemplate-rpcs --delete-unreferenced-snapshots
|
//! cargo insta test --review --features getblocktemplate-rpcs --delete-unreferenced-snapshots
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
use hex::FromHex;
|
use hex::FromHex;
|
||||||
use insta::Settings;
|
use insta::Settings;
|
||||||
use tower::{buffer::Buffer, Service};
|
use tower::{buffer::Buffer, Service};
|
||||||
|
@ -19,6 +21,7 @@ use zebra_chain::{
|
||||||
transparent,
|
transparent,
|
||||||
work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256},
|
work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256},
|
||||||
};
|
};
|
||||||
|
use zebra_network::{address_book_peers::MockAddressBookPeers, types::MetaAddr};
|
||||||
use zebra_node_services::mempool;
|
use zebra_node_services::mempool;
|
||||||
|
|
||||||
use zebra_state::{GetBlockTemplateChainInfo, ReadRequest, ReadResponse};
|
use zebra_state::{GetBlockTemplateChainInfo, ReadRequest, ReadResponse};
|
||||||
|
@ -36,6 +39,7 @@ use crate::methods::{
|
||||||
get_mining_info,
|
get_mining_info,
|
||||||
hex_data::HexData,
|
hex_data::HexData,
|
||||||
long_poll::{LongPollId, LONG_POLL_ID_LENGTH},
|
long_poll::{LongPollId, LONG_POLL_ID_LENGTH},
|
||||||
|
peer_info::PeerInfo,
|
||||||
submit_block,
|
submit_block,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -113,6 +117,14 @@ pub async fn test_responses<State, ReadState>(
|
||||||
mock_chain_tip_sender.send_best_tip_hash(fake_tip_hash);
|
mock_chain_tip_sender.send_best_tip_hash(fake_tip_hash);
|
||||||
mock_chain_tip_sender.send_estimated_distance_to_network_chain_tip(Some(0));
|
mock_chain_tip_sender.send_estimated_distance_to_network_chain_tip(Some(0));
|
||||||
|
|
||||||
|
let mock_address_book =
|
||||||
|
MockAddressBookPeers::new(vec![MetaAddr::new_initial_peer(SocketAddr::new(
|
||||||
|
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
|
network.default_port(),
|
||||||
|
))
|
||||||
|
.into_new_meta_addr()
|
||||||
|
.unwrap()]);
|
||||||
|
|
||||||
// get an rpc instance with continuous blockchain state
|
// get an rpc instance with continuous blockchain state
|
||||||
let get_block_template_rpc = GetBlockTemplateRpcImpl::new(
|
let get_block_template_rpc = GetBlockTemplateRpcImpl::new(
|
||||||
network,
|
network,
|
||||||
|
@ -122,6 +134,7 @@ pub async fn test_responses<State, ReadState>(
|
||||||
mock_chain_tip.clone(),
|
mock_chain_tip.clone(),
|
||||||
chain_verifier.clone(),
|
chain_verifier.clone(),
|
||||||
mock_sync_status.clone(),
|
mock_sync_status.clone(),
|
||||||
|
mock_address_book,
|
||||||
);
|
);
|
||||||
|
|
||||||
// `getblockcount`
|
// `getblockcount`
|
||||||
|
@ -145,6 +158,13 @@ pub async fn test_responses<State, ReadState>(
|
||||||
.expect("We should have a success response");
|
.expect("We should have a success response");
|
||||||
snapshot_rpc_getmininginfo(get_mining_info, &settings);
|
snapshot_rpc_getmininginfo(get_mining_info, &settings);
|
||||||
|
|
||||||
|
// `getpeerinfo`
|
||||||
|
let get_peer_info = get_block_template_rpc
|
||||||
|
.get_peer_info()
|
||||||
|
.await
|
||||||
|
.expect("We should have a success response");
|
||||||
|
snapshot_rpc_getpeerinfo(get_peer_info, &settings);
|
||||||
|
|
||||||
// `getnetworksolps` (and `getnetworkhashps`)
|
// `getnetworksolps` (and `getnetworkhashps`)
|
||||||
let get_network_sol_ps = get_block_template_rpc
|
let get_network_sol_ps = get_block_template_rpc
|
||||||
.get_network_sol_ps(None, None)
|
.get_network_sol_ps(None, None)
|
||||||
|
@ -169,6 +189,7 @@ pub async fn test_responses<State, ReadState>(
|
||||||
mock_chain_tip.clone(),
|
mock_chain_tip.clone(),
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
mock_sync_status.clone(),
|
mock_sync_status.clone(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Basic variant (default mode and no extra features)
|
// Basic variant (default mode and no extra features)
|
||||||
|
@ -308,6 +329,7 @@ pub async fn test_responses<State, ReadState>(
|
||||||
mock_chain_tip,
|
mock_chain_tip,
|
||||||
mock_chain_verifier.clone(),
|
mock_chain_verifier.clone(),
|
||||||
mock_sync_status,
|
mock_sync_status,
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let get_block_template = tokio::spawn(get_block_template_rpc.get_block_template(Some(
|
let get_block_template = tokio::spawn(get_block_template_rpc.get_block_template(Some(
|
||||||
|
@ -391,6 +413,11 @@ fn snapshot_rpc_getmininginfo(
|
||||||
settings.bind(|| insta::assert_json_snapshot!("get_mining_info", get_mining_info));
|
settings.bind(|| insta::assert_json_snapshot!("get_mining_info", get_mining_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Snapshot `getpeerinfo` response, using `cargo insta` and JSON serialization.
|
||||||
|
fn snapshot_rpc_getpeerinfo(get_peer_info: Vec<PeerInfo>, settings: &insta::Settings) {
|
||||||
|
settings.bind(|| insta::assert_json_snapshot!("get_peer_info", get_peer_info));
|
||||||
|
}
|
||||||
|
|
||||||
/// Snapshot `getnetworksolps` response, using `cargo insta` and JSON serialization.
|
/// Snapshot `getnetworksolps` response, using `cargo insta` and JSON serialization.
|
||||||
fn snapshot_rpc_getnetworksolps(get_network_sol_ps: u64, settings: &insta::Settings) {
|
fn snapshot_rpc_getnetworksolps(get_network_sol_ps: u64, settings: &insta::Settings) {
|
||||||
settings.bind(|| insta::assert_json_snapshot!("get_network_sol_ps", get_network_sol_ps));
|
settings.bind(|| insta::assert_json_snapshot!("get_network_sol_ps", get_network_sol_ps));
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
|
||||||
|
expression: get_peer_info
|
||||||
|
---
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"addr": "127.0.0.1:8233"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs
|
||||||
|
expression: get_peer_info
|
||||||
|
---
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"addr": "127.0.0.1:18233"
|
||||||
|
}
|
||||||
|
]
|
|
@ -625,6 +625,7 @@ async fn rpc_getaddressutxos_response() {
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
async fn rpc_getblockcount() {
|
async fn rpc_getblockcount() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
let _init_guard = zebra_test::init();
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
@ -667,6 +668,7 @@ async fn rpc_getblockcount() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the tip height using RPC method `get_block_count`
|
// Get the tip height using RPC method `get_block_count`
|
||||||
|
@ -684,6 +686,7 @@ async fn rpc_getblockcount() {
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn rpc_getblockcount_empty_state() {
|
async fn rpc_getblockcount_empty_state() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
let _init_guard = zebra_test::init();
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
@ -715,6 +718,7 @@ async fn rpc_getblockcount_empty_state() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the tip height using RPC method `get_block_count
|
// Get the tip height using RPC method `get_block_count
|
||||||
|
@ -729,10 +733,78 @@ async fn rpc_getblockcount_empty_state() {
|
||||||
mempool.expect_no_requests().await;
|
mempool.expect_no_requests().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn rpc_getpeerinfo() {
|
||||||
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
|
let _init_guard = zebra_test::init();
|
||||||
|
let network = Mainnet;
|
||||||
|
|
||||||
|
// Get a mempool handle
|
||||||
|
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||||
|
// Create an empty state
|
||||||
|
let (state, read_state, latest_chain_tip, _chain_tip_change) =
|
||||||
|
zebra_state::init_test_services(Mainnet);
|
||||||
|
|
||||||
|
let (
|
||||||
|
chain_verifier,
|
||||||
|
_transaction_verifier,
|
||||||
|
_parameter_download_task_handle,
|
||||||
|
_max_checkpoint_height,
|
||||||
|
) = zebra_consensus::chain::init(
|
||||||
|
zebra_consensus::Config::default(),
|
||||||
|
network,
|
||||||
|
state.clone(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let mock_peer_address =
|
||||||
|
zebra_network::types::MetaAddr::new_initial_peer(std::net::SocketAddr::new(
|
||||||
|
std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
|
network.default_port(),
|
||||||
|
))
|
||||||
|
.into_new_meta_addr()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mock_address_book = MockAddressBookPeers::new(vec![mock_peer_address]);
|
||||||
|
|
||||||
|
// Init RPC
|
||||||
|
let get_block_template_rpc = get_block_template_rpcs::GetBlockTemplateRpcImpl::new(
|
||||||
|
network,
|
||||||
|
Default::default(),
|
||||||
|
Buffer::new(mempool.clone(), 1),
|
||||||
|
read_state,
|
||||||
|
latest_chain_tip.clone(),
|
||||||
|
chain_verifier,
|
||||||
|
MockSyncStatus::default(),
|
||||||
|
mock_address_book,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call `get_peer_info`
|
||||||
|
let get_peer_info = get_block_template_rpc
|
||||||
|
.get_peer_info()
|
||||||
|
.await
|
||||||
|
.expect("We should have an array of addresses");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_peer_info
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("there should be a mock peer address"),
|
||||||
|
mock_peer_address.into()
|
||||||
|
);
|
||||||
|
|
||||||
|
mempool.expect_no_requests().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn rpc_getblockhash() {
|
async fn rpc_getblockhash() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
let _init_guard = zebra_test::init();
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
@ -769,6 +841,7 @@ async fn rpc_getblockhash() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
tower::ServiceBuilder::new().service(chain_verifier),
|
tower::ServiceBuilder::new().service(chain_verifier),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Query the hashes using positive indexes
|
// Query the hashes using positive indexes
|
||||||
|
@ -801,6 +874,7 @@ async fn rpc_getblockhash() {
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn rpc_getmininginfo() {
|
async fn rpc_getmininginfo() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
let _init_guard = zebra_test::init();
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
@ -823,6 +897,7 @@ async fn rpc_getmininginfo() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
MockService::build().for_unit_tests(),
|
MockService::build().for_unit_tests(),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
get_block_template_rpc
|
get_block_template_rpc
|
||||||
|
@ -835,6 +910,7 @@ async fn rpc_getmininginfo() {
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn rpc_getnetworksolps() {
|
async fn rpc_getnetworksolps() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
let _init_guard = zebra_test::init();
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
@ -857,6 +933,7 @@ async fn rpc_getnetworksolps() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
MockService::build().for_unit_tests(),
|
MockService::build().for_unit_tests(),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let get_network_sol_ps_inputs = [
|
let get_network_sol_ps_inputs = [
|
||||||
|
@ -910,6 +987,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) {
|
||||||
work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256},
|
work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256},
|
||||||
};
|
};
|
||||||
use zebra_consensus::MAX_BLOCK_SIGOPS;
|
use zebra_consensus::MAX_BLOCK_SIGOPS;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
use zebra_state::{GetBlockTemplateChainInfo, ReadRequest, ReadResponse};
|
use zebra_state::{GetBlockTemplateChainInfo, ReadRequest, ReadResponse};
|
||||||
|
|
||||||
use crate::methods::{
|
use crate::methods::{
|
||||||
|
@ -969,6 +1047,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) {
|
||||||
mock_chain_tip,
|
mock_chain_tip,
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
mock_sync_status.clone(),
|
mock_sync_status.clone(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fake the ChainInfo response
|
// Fake the ChainInfo response
|
||||||
|
@ -1140,6 +1219,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) {
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn rpc_submitblock_errors() {
|
async fn rpc_submitblock_errors() {
|
||||||
use zebra_chain::chain_sync_status::MockSyncStatus;
|
use zebra_chain::chain_sync_status::MockSyncStatus;
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
|
|
||||||
use crate::methods::get_block_template_rpcs::types::{hex_data::HexData, submit_block};
|
use crate::methods::get_block_template_rpcs::types::{hex_data::HexData, submit_block};
|
||||||
|
|
||||||
|
@ -1179,6 +1259,7 @@ async fn rpc_submitblock_errors() {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Try to submit pre-populated blocks and assert that it responds with duplicate.
|
// Try to submit pre-populated blocks and assert that it responds with duplicate.
|
||||||
|
|
|
@ -19,6 +19,7 @@ use tracing::{Instrument, *};
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block, chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, parameters::Network,
|
block, chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, parameters::Network,
|
||||||
};
|
};
|
||||||
|
use zebra_network::AddressBookPeers;
|
||||||
use zebra_node_services::mempool;
|
use zebra_node_services::mempool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -69,7 +70,7 @@ impl RpcServer {
|
||||||
//
|
//
|
||||||
// TODO: put some of the configs or services in their own struct?
|
// TODO: put some of the configs or services in their own struct?
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn spawn<Version, Mempool, State, Tip, ChainVerifier, SyncStatus>(
|
pub fn spawn<Version, Mempool, State, Tip, ChainVerifier, SyncStatus, AddressBook>(
|
||||||
config: Config,
|
config: Config,
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
mining_config: get_block_template_rpcs::config::Config,
|
mining_config: get_block_template_rpcs::config::Config,
|
||||||
|
@ -83,6 +84,8 @@ impl RpcServer {
|
||||||
chain_verifier: ChainVerifier,
|
chain_verifier: ChainVerifier,
|
||||||
#[cfg_attr(not(feature = "getblocktemplate-rpcs"), allow(unused_variables))]
|
#[cfg_attr(not(feature = "getblocktemplate-rpcs"), allow(unused_variables))]
|
||||||
sync_status: SyncStatus,
|
sync_status: SyncStatus,
|
||||||
|
#[cfg_attr(not(feature = "getblocktemplate-rpcs"), allow(unused_variables))]
|
||||||
|
address_book: AddressBook,
|
||||||
latest_chain_tip: Tip,
|
latest_chain_tip: Tip,
|
||||||
network: Network,
|
network: Network,
|
||||||
) -> (JoinHandle<()>, JoinHandle<()>, Option<Self>)
|
) -> (JoinHandle<()>, JoinHandle<()>, Option<Self>)
|
||||||
|
@ -114,6 +117,7 @@ impl RpcServer {
|
||||||
+ 'static,
|
+ 'static,
|
||||||
<ChainVerifier as Service<zebra_consensus::Request>>::Future: Send,
|
<ChainVerifier as Service<zebra_consensus::Request>>::Future: Send,
|
||||||
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
SyncStatus: ChainSyncStatus + Clone + Send + Sync + 'static,
|
||||||
|
AddressBook: AddressBookPeers + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
if let Some(listen_addr) = config.listen_addr {
|
if let Some(listen_addr) = config.listen_addr {
|
||||||
info!("Trying to open RPC endpoint at {}...", listen_addr,);
|
info!("Trying to open RPC endpoint at {}...", listen_addr,);
|
||||||
|
@ -144,6 +148,7 @@ impl RpcServer {
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
chain_verifier,
|
chain_verifier,
|
||||||
sync_status,
|
sync_status,
|
||||||
|
address_book,
|
||||||
);
|
);
|
||||||
|
|
||||||
io.extend_with(get_block_template_rpc_impl.to_delegate());
|
io.extend_with(get_block_template_rpc_impl.to_delegate());
|
||||||
|
|
|
@ -11,6 +11,7 @@ use tower::buffer::Buffer;
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
chain_sync_status::MockSyncStatus, chain_tip::NoChainTip, parameters::Network::*,
|
chain_sync_status::MockSyncStatus, chain_tip::NoChainTip, parameters::Network::*,
|
||||||
};
|
};
|
||||||
|
use zebra_network::address_book_peers::MockAddressBookPeers;
|
||||||
use zebra_node_services::BoxError;
|
use zebra_node_services::BoxError;
|
||||||
|
|
||||||
use zebra_test::mock_service::MockService;
|
use zebra_test::mock_service::MockService;
|
||||||
|
@ -61,6 +62,7 @@ fn rpc_server_spawn(parallel_cpu_threads: bool) {
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
@ -146,6 +148,7 @@ fn rpc_server_spawn_unallocated_port(parallel_cpu_threads: bool, do_shutdown: bo
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
@ -225,6 +228,7 @@ fn rpc_server_spawn_port_conflict() {
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
@ -241,6 +245,7 @@ fn rpc_server_spawn_port_conflict() {
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
@ -331,6 +336,7 @@ fn rpc_server_spawn_port_conflict_parallel_auto() {
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
@ -347,6 +353,7 @@ fn rpc_server_spawn_port_conflict_parallel_auto() {
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(chain_verifier.clone(), 1),
|
Buffer::new(chain_verifier.clone(), 1),
|
||||||
MockSyncStatus::default(),
|
MockSyncStatus::default(),
|
||||||
|
MockAddressBookPeers::default(),
|
||||||
NoChainTip,
|
NoChainTip,
|
||||||
Mainnet,
|
Mainnet,
|
||||||
);
|
);
|
||||||
|
|
|
@ -186,6 +186,7 @@ impl StartCmd {
|
||||||
read_only_state_service,
|
read_only_state_service,
|
||||||
chain_verifier.clone(),
|
chain_verifier.clone(),
|
||||||
sync_status.clone(),
|
sync_status.clone(),
|
||||||
|
address_book.clone(),
|
||||||
latest_chain_tip.clone(),
|
latest_chain_tip.clone(),
|
||||||
config.network.network,
|
config.network.network,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1483,7 +1483,9 @@ fn non_blocking_logger() -> Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
fn lightwalletd_integration() -> Result<()> {
|
fn lightwalletd_integration() -> Result<()> {
|
||||||
lightwalletd_integration_test(LaunchWithEmptyState)
|
lightwalletd_integration_test(LaunchWithEmptyState {
|
||||||
|
launches_lightwalletd: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make sure `zebrad` can sync from peers, but don't actually launch `lightwalletd`.
|
/// Make sure `zebrad` can sync from peers, but don't actually launch `lightwalletd`.
|
||||||
|
@ -1547,7 +1549,9 @@ fn lightwalletd_full_sync() -> Result<()> {
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
async fn lightwalletd_test_suite() -> Result<()> {
|
async fn lightwalletd_test_suite() -> Result<()> {
|
||||||
lightwalletd_integration_test(LaunchWithEmptyState)?;
|
lightwalletd_integration_test(LaunchWithEmptyState {
|
||||||
|
launches_lightwalletd: true,
|
||||||
|
})?;
|
||||||
|
|
||||||
// Only runs when ZEBRA_CACHED_STATE_DIR is set.
|
// Only runs when ZEBRA_CACHED_STATE_DIR is set.
|
||||||
lightwalletd_integration_test(UpdateZebraCachedStateNoRpc)?;
|
lightwalletd_integration_test(UpdateZebraCachedStateNoRpc)?;
|
||||||
|
@ -2174,6 +2178,15 @@ async fn lightwalletd_wallet_grpc_tests() -> Result<()> {
|
||||||
common::lightwalletd::wallet_grpc_test::run().await
|
common::lightwalletd::wallet_grpc_test::run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test successful getpeerinfo rpc call
|
||||||
|
///
|
||||||
|
/// See [`common::get_block_template_rpcs::get_peer_info`] for more information.
|
||||||
|
#[tokio::test]
|
||||||
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
|
async fn get_peer_info() -> Result<()> {
|
||||||
|
common::get_block_template_rpcs::get_peer_info::run().await
|
||||||
|
}
|
||||||
|
|
||||||
/// Test successful getblocktemplate rpc call
|
/// Test successful getblocktemplate rpc call
|
||||||
///
|
///
|
||||||
/// See [`common::get_block_template_rpcs::get_block_template`] for more information.
|
/// See [`common::get_block_template_rpcs::get_block_template`] for more information.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! Acceptance tests for getblocktemplate RPC methods in Zebra.
|
//! Acceptance tests for getblocktemplate RPC methods in Zebra.
|
||||||
|
|
||||||
pub(crate) mod get_block_template;
|
pub(crate) mod get_block_template;
|
||||||
|
pub(crate) mod get_peer_info;
|
||||||
pub(crate) mod submit_block;
|
pub(crate) mod submit_block;
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
//! Tests that `getpeerinfo` RPC method responds with info about at least 1 peer.
|
||||||
|
|
||||||
|
use color_eyre::eyre::{Context, Result};
|
||||||
|
|
||||||
|
use zebra_chain::parameters::Network;
|
||||||
|
use zebra_rpc::methods::get_block_template_rpcs::types::peer_info::PeerInfo;
|
||||||
|
|
||||||
|
use crate::common::{
|
||||||
|
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
|
||||||
|
rpc_client::RPCRequestClient,
|
||||||
|
test_type::TestType,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) async fn run() -> Result<()> {
|
||||||
|
let _init_guard = zebra_test::init();
|
||||||
|
|
||||||
|
let test_type = TestType::LaunchWithEmptyState {
|
||||||
|
launches_lightwalletd: false,
|
||||||
|
};
|
||||||
|
let test_name = "get_peer_info_test";
|
||||||
|
let network = Network::Mainnet;
|
||||||
|
|
||||||
|
// Skip the test unless the user specifically asked for it and there is a zebrad_state_path
|
||||||
|
if !can_spawn_zebrad_for_rpc(test_name, test_type) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!(?network, "running getpeerinfo test using zebrad",);
|
||||||
|
|
||||||
|
let (mut zebrad, zebra_rpc_address) =
|
||||||
|
spawn_zebrad_for_rpc(network, test_name, test_type, true)?
|
||||||
|
.expect("Already checked zebra state path with can_spawn_zebrad_for_rpc");
|
||||||
|
|
||||||
|
let rpc_address = zebra_rpc_address.expect("getpeerinfo test must have RPC port");
|
||||||
|
|
||||||
|
// Wait until port is open.
|
||||||
|
zebrad.expect_stdout_line_matches(&format!("Opened RPC endpoint at {rpc_address}"))?;
|
||||||
|
|
||||||
|
tracing::info!(?rpc_address, "zebrad opened its RPC port",);
|
||||||
|
|
||||||
|
// call `getpeerinfo` RPC method
|
||||||
|
let peer_info_result: Vec<PeerInfo> = RPCRequestClient::new(rpc_address)
|
||||||
|
.json_result_from_call("getpeerinfo", "[]".to_string())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!peer_info_result.is_empty(),
|
||||||
|
"getpeerinfo should return info for at least 1 peer"
|
||||||
|
);
|
||||||
|
|
||||||
|
zebrad.kill(false)?;
|
||||||
|
|
||||||
|
let output = zebrad.wait_with_output()?;
|
||||||
|
let output = output.assert_failure()?;
|
||||||
|
|
||||||
|
// [Note on port conflict](#Note on port conflict)
|
||||||
|
output
|
||||||
|
.assert_was_killed()
|
||||||
|
.wrap_err("Possible port conflict. Are there other acceptance tests running?")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -23,7 +23,10 @@ use TestType::*;
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum TestType {
|
pub enum TestType {
|
||||||
/// Launch with an empty Zebra and lightwalletd state.
|
/// Launch with an empty Zebra and lightwalletd state.
|
||||||
LaunchWithEmptyState,
|
LaunchWithEmptyState {
|
||||||
|
/// Configures whether the test uses lightwalletd.
|
||||||
|
launches_lightwalletd: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// Do a full sync from an empty lightwalletd state.
|
/// Do a full sync from an empty lightwalletd state.
|
||||||
///
|
///
|
||||||
|
@ -66,7 +69,7 @@ impl TestType {
|
||||||
// - FullSyncFromGenesis, UpdateCachedState, UpdateZebraCachedStateNoRpc:
|
// - FullSyncFromGenesis, UpdateCachedState, UpdateZebraCachedStateNoRpc:
|
||||||
// skip the test if it is not available
|
// skip the test if it is not available
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState => false,
|
LaunchWithEmptyState { .. } => false,
|
||||||
FullSyncFromGenesis { .. }
|
FullSyncFromGenesis { .. }
|
||||||
| UpdateCachedState
|
| UpdateCachedState
|
||||||
| UpdateZebraCachedStateNoRpc
|
| UpdateZebraCachedStateNoRpc
|
||||||
|
@ -77,11 +80,10 @@ impl TestType {
|
||||||
/// Does this test need a Zebra rpc server?
|
/// Does this test need a Zebra rpc server?
|
||||||
pub fn needs_zebra_rpc_server(&self) -> bool {
|
pub fn needs_zebra_rpc_server(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
UpdateZebraCachedStateWithRpc => true,
|
UpdateZebraCachedStateWithRpc | LaunchWithEmptyState { .. } => true,
|
||||||
UpdateZebraCachedStateNoRpc
|
UpdateZebraCachedStateNoRpc | FullSyncFromGenesis { .. } | UpdateCachedState => {
|
||||||
| LaunchWithEmptyState
|
self.launches_lightwalletd()
|
||||||
| FullSyncFromGenesis { .. }
|
}
|
||||||
| UpdateCachedState => self.launches_lightwalletd(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +91,10 @@ impl TestType {
|
||||||
pub fn launches_lightwalletd(&self) -> bool {
|
pub fn launches_lightwalletd(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => false,
|
UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => false,
|
||||||
LaunchWithEmptyState | FullSyncFromGenesis { .. } | UpdateCachedState => true,
|
FullSyncFromGenesis { .. } | UpdateCachedState => true,
|
||||||
|
LaunchWithEmptyState {
|
||||||
|
launches_lightwalletd,
|
||||||
|
} => *launches_lightwalletd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +105,7 @@ impl TestType {
|
||||||
// - FullSyncFromGenesis: use it if available, timeout if it is already populated
|
// - FullSyncFromGenesis: use it if available, timeout if it is already populated
|
||||||
// - UpdateCachedState: skip the test if it is not available
|
// - UpdateCachedState: skip the test if it is not available
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState
|
LaunchWithEmptyState { .. }
|
||||||
| FullSyncFromGenesis { .. }
|
| FullSyncFromGenesis { .. }
|
||||||
| UpdateZebraCachedStateNoRpc
|
| UpdateZebraCachedStateNoRpc
|
||||||
| UpdateZebraCachedStateWithRpc => false,
|
| UpdateZebraCachedStateWithRpc => false,
|
||||||
|
@ -111,7 +116,7 @@ impl TestType {
|
||||||
/// Does this test allow a `lightwalletd` cached state, even if it is not required?
|
/// Does this test allow a `lightwalletd` cached state, even if it is not required?
|
||||||
pub fn allow_lightwalletd_cached_state(&self) -> bool {
|
pub fn allow_lightwalletd_cached_state(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState => false,
|
LaunchWithEmptyState { .. } => false,
|
||||||
FullSyncFromGenesis {
|
FullSyncFromGenesis {
|
||||||
allow_lightwalletd_cached_state,
|
allow_lightwalletd_cached_state,
|
||||||
} => *allow_lightwalletd_cached_state,
|
} => *allow_lightwalletd_cached_state,
|
||||||
|
@ -122,7 +127,7 @@ impl TestType {
|
||||||
/// Can this test create a new `LIGHTWALLETD_DATA_DIR` cached state?
|
/// Can this test create a new `LIGHTWALLETD_DATA_DIR` cached state?
|
||||||
pub fn can_create_lightwalletd_cached_state(&self) -> bool {
|
pub fn can_create_lightwalletd_cached_state(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState => false,
|
LaunchWithEmptyState { .. } => false,
|
||||||
FullSyncFromGenesis { .. } | UpdateCachedState => true,
|
FullSyncFromGenesis { .. } | UpdateCachedState => true,
|
||||||
UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => false,
|
UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => false,
|
||||||
}
|
}
|
||||||
|
@ -232,7 +237,7 @@ impl TestType {
|
||||||
/// Returns the `zebrad` timeout for this test type.
|
/// Returns the `zebrad` timeout for this test type.
|
||||||
pub fn zebrad_timeout(&self) -> Duration {
|
pub fn zebrad_timeout(&self) -> Duration {
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState => LIGHTWALLETD_DELAY,
|
LaunchWithEmptyState { .. } => LIGHTWALLETD_DELAY,
|
||||||
FullSyncFromGenesis { .. } => LIGHTWALLETD_FULL_SYNC_TIP_DELAY,
|
FullSyncFromGenesis { .. } => LIGHTWALLETD_FULL_SYNC_TIP_DELAY,
|
||||||
UpdateCachedState | UpdateZebraCachedStateNoRpc => LIGHTWALLETD_UPDATE_TIP_DELAY,
|
UpdateCachedState | UpdateZebraCachedStateNoRpc => LIGHTWALLETD_UPDATE_TIP_DELAY,
|
||||||
UpdateZebraCachedStateWithRpc => FINISH_PARTIAL_SYNC_TIMEOUT,
|
UpdateZebraCachedStateWithRpc => FINISH_PARTIAL_SYNC_TIMEOUT,
|
||||||
|
@ -249,7 +254,7 @@ impl TestType {
|
||||||
// We use the same timeouts for zebrad and lightwalletd,
|
// We use the same timeouts for zebrad and lightwalletd,
|
||||||
// because the tests check zebrad and lightwalletd concurrently.
|
// because the tests check zebrad and lightwalletd concurrently.
|
||||||
match self {
|
match self {
|
||||||
LaunchWithEmptyState => LIGHTWALLETD_DELAY,
|
LaunchWithEmptyState { .. } => LIGHTWALLETD_DELAY,
|
||||||
FullSyncFromGenesis { .. } => LIGHTWALLETD_FULL_SYNC_TIP_DELAY,
|
FullSyncFromGenesis { .. } => LIGHTWALLETD_FULL_SYNC_TIP_DELAY,
|
||||||
UpdateCachedState | UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => {
|
UpdateCachedState | UpdateZebraCachedStateNoRpc | UpdateZebraCachedStateWithRpc => {
|
||||||
LIGHTWALLETD_UPDATE_TIP_DELAY
|
LIGHTWALLETD_UPDATE_TIP_DELAY
|
||||||
|
@ -270,7 +275,7 @@ impl TestType {
|
||||||
// Fail if we need a cached Zebra state, but it's empty
|
// Fail if we need a cached Zebra state, but it's empty
|
||||||
zebrad_failure_messages.push("loaded Zebra state cache .*tip.*=.*None".to_string());
|
zebrad_failure_messages.push("loaded Zebra state cache .*tip.*=.*None".to_string());
|
||||||
}
|
}
|
||||||
if *self == LaunchWithEmptyState {
|
if matches!(*self, LaunchWithEmptyState { .. }) {
|
||||||
// Fail if we need an empty Zebra state, but it has blocks
|
// Fail if we need an empty Zebra state, but it has blocks
|
||||||
zebrad_failure_messages
|
zebrad_failure_messages
|
||||||
.push(r"loaded Zebra state cache .*tip.*=.*Height\([1-9][0-9]*\)".to_string());
|
.push(r"loaded Zebra state cache .*tip.*=.*Height\([1-9][0-9]*\)".to_string());
|
||||||
|
@ -311,7 +316,7 @@ impl TestType {
|
||||||
lightwalletd_failure_messages.push("Found [1-9][0-9]* blocks in cache".to_string());
|
lightwalletd_failure_messages.push("Found [1-9][0-9]* blocks in cache".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let lightwalletd_ignore_messages = if *self == LaunchWithEmptyState {
|
let lightwalletd_ignore_messages = if matches!(*self, LaunchWithEmptyState { .. }) {
|
||||||
LIGHTWALLETD_EMPTY_ZEBRA_STATE_IGNORE_MESSAGES.iter()
|
LIGHTWALLETD_EMPTY_ZEBRA_STATE_IGNORE_MESSAGES.iter()
|
||||||
} else {
|
} else {
|
||||||
NO_MATCHES_REGEX_ITER.iter()
|
NO_MATCHES_REGEX_ITER.iter()
|
||||||
|
|
Loading…
Reference in New Issue