Skip to content

Commit

Permalink
Merge pull request #1292 from mintlayer/peer_discovery_on_stale_tip
Browse files Browse the repository at this point in the history
Tests for new peer discovery when the tip is stale
  • Loading branch information
TheQuantumPhysicist authored Oct 24, 2023
2 parents f879707 + b0d09b0 commit a08e4a5
Show file tree
Hide file tree
Showing 27 changed files with 1,110 additions and 255 deletions.
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() {
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

0 comments on commit a08e4a5

Please sign in to comment.