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

Tests for new peer discovery when the tip is stale #1292

Merged
merged 7 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.

9 changes: 6 additions & 3 deletions p2p/p2p-test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,23 @@ pub fn start_subsystems(
ShutdownTrigger,
ManagerJoinHandle,
) {
let time_getter: TimeGetter = Default::default();
let chainstate = make_chainstate(
Arc::clone(&chain_config),
ChainstateConfig::new(),
chainstate_storage::inmemory::Store::new_empty().unwrap(),
DefaultTransactionVerificationStrategy::new(),
None,
Default::default(),
time_getter.clone(),
)
.unwrap();
start_subsystems_with_chainstate(chainstate, chain_config)
start_subsystems_with_chainstate(chainstate, chain_config, time_getter)
}

pub fn start_subsystems_with_chainstate(
chainstate: ChainstateSubsystem,
chain_config: Arc<ChainConfig>,
time_getter: TimeGetter,
) -> (
ChainstateHandle,
MempoolHandle,
Expand All @@ -66,7 +68,7 @@ pub fn start_subsystems_with_chainstate(

let chainstate = manager.add_subsystem("p2p-test-chainstate", chainstate);

let mempool = mempool::make_mempool(chain_config, chainstate.clone(), Default::default());
let mempool = mempool::make_mempool(chain_config, chainstate.clone(), time_getter);
let mempool = manager.add_custom_subsystem("p2p-test-mempool", |handle| mempool.init(handle));

let manager_handle = manager.main_in_task();
Expand All @@ -90,6 +92,7 @@ pub fn create_n_blocks(tf: &mut TestFramework, n: usize) -> Vec<Block> {
blocks
}

#[derive(Clone)]
pub struct P2pBasicTestTimeGetter {
current_time_millis: Arc<SeqCstAtomicU64>,
}
Expand Down
3 changes: 3 additions & 0 deletions p2p/src/net/default_backend/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,10 @@ where
None => return Ok(()),
};

log::debug!("Creating peer {peer_id} after handshake");

if self.is_connection_from_self(connection_info, handshake_nonce)? {
log::debug!("Peer {peer_id} is a connection from self");
return Ok(());
}

Expand Down
17 changes: 16 additions & 1 deletion p2p/src/net/default_backend/transport/impls/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,22 @@ pub struct MpscChannelTransport {

impl MpscChannelTransport {
pub fn new() -> Self {
let local_address: Ipv4Addr = NEXT_IP_ADDRESS.fetch_add(1, Ordering::Relaxed).into();
Self::new_with_addr_in_group(0, 0)
}

/// Create a new transport with a local address in the specified "group", which is represented
/// by a certain number of most significant bits in the ip address.
///
/// The resulting local address will be:
/// (addr_group_idx << (32 - addr_group_bits)) + NEXT_IP_ADDRESS
pub fn new_with_addr_in_group(addr_group_idx: u32, addr_group_bits: u32) -> Self {
let addr_group_bit_offset = 32 - addr_group_bits;
let next_addr = NEXT_IP_ADDRESS.fetch_add(1, Ordering::Relaxed);
assert!((next_addr as u64) < (1_u64 << addr_group_bit_offset));
let addr_group = (addr_group_idx as u64) << addr_group_bit_offset;
assert!(addr_group <= u32::MAX as u64);

let local_address: Ipv4Addr = (next_addr + addr_group as u32).into();
MpscChannelTransport {
local_address: local_address.into(),
last_port: 1024.into(),
Expand Down
2 changes: 1 addition & 1 deletion p2p/src/net/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl PeerRole {
/// wants to keep the connection open or close it and possibly ban the peer from.
///
/// If new fields are added, make sure they are limited in size.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PeerInfo {
/// Unique ID of the peer
pub peer_id: PeerId,
Expand Down
4 changes: 2 additions & 2 deletions p2p/src/peer_manager/address_groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use std::net::{Ipv4Addr, Ipv6Addr};
use crate::types::peer_address::PeerAddress;

// IPv4 addresses grouped into /16 subnets
const IPV4_GROUP_BYTES: usize = 2;
pub const IPV4_GROUP_BYTES: usize = 2;
// IPv6 addresses grouped into /32 subnets
const IPV6_GROUP_BYTES: usize = 4;
pub const IPV6_GROUP_BYTES: usize = 4;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AddressGroup {
Expand Down
100 changes: 100 additions & 0 deletions p2p/src/peer_manager/dns_seed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) 2021-2023 RBB S.r.l
// opensource@mintlayer.org
// SPDX-License-Identifier: MIT
// Licensed under the MIT License;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use async_trait::async_trait;
use common::chain::{config::ChainType, ChainConfig};
use crypto::random::{make_pseudo_rng, seq::IteratorRandom};
use logging::log;
use p2p_types::socket_address::SocketAddress;

use crate::config::P2pConfig;

#[async_trait]
pub trait DnsSeed: Send + Sync {
async fn obtain_addresses(&self) -> Vec<SocketAddress>;
}

pub struct DefaultDnsSeed {
chain_config: Arc<ChainConfig>,
p2p_config: Arc<P2pConfig>,
}

impl DefaultDnsSeed {
pub fn new(chain_config: Arc<ChainConfig>, p2p_config: Arc<P2pConfig>) -> Self {
Self {
chain_config,
p2p_config,
}
}
}

/// Hardcoded seed DNS hostnames
// TODO: Replace with actual values
const DNS_SEEDS_MAINNET: [&str; 0] = [];
const DNS_SEEDS_TESTNET: [&str; 1] = ["testnet-seed.mintlayer.org"];

/// Maximum number of records accepted in a single DNS server response
const MAX_DNS_RECORDS: usize = 10;

#[async_trait]
impl DnsSeed for DefaultDnsSeed {
async fn obtain_addresses(&self) -> Vec<SocketAddress> {
let dns_seed = match self.chain_config.chain_type() {
Comment on lines +55 to +56
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: the logic in this function is not new; it was moved here from reload_dns_seed

ChainType::Mainnet => DNS_SEEDS_MAINNET.as_slice(),
ChainType::Testnet => DNS_SEEDS_TESTNET.as_slice(),
ChainType::Regtest | ChainType::Signet => &[],
};

if dns_seed.is_empty() {
return Vec::new();
}

log::debug!("Resolve DNS seed...");
let results = futures::future::join_all(
dns_seed
.iter()
.map(|host| tokio::net::lookup_host((*host, self.chain_config.p2p_port()))),
)
.await;

let mut addresses = Vec::new();
for result in results {
match result {
Ok(list) => {
list.filter_map(|addr| {
SocketAddress::from_peer_address(
// Convert SocketAddr to PeerAddress
&addr.into(),
*self.p2p_config.allow_discover_private_ips,
)
})
// Randomize selection because records can be sorted by type (A and AAAA)
.choose_multiple(&mut make_pseudo_rng(), MAX_DNS_RECORDS)
.into_iter()
.for_each(|addr| {
addresses.push(addr);
});
}
Err(err) => {
log::error!("resolve DNS seed failed: {err}");
}
}
}
log::debug!("DNS seed records found: {}", addresses.len());
addresses
}
}
Loading