networkk connectivity fixes
This commit is contained in:
parent
a370c18825
commit
ff67566944
|
|
@ -171,7 +171,10 @@ async fn reconnect_replacement_inner(excluded_ip: &str) {
|
|||
};
|
||||
|
||||
let Some((connections_key, stream)) = live_connection else {
|
||||
warn!("[reconnect] no live stream available for bootstrap recovery");
|
||||
// Topology discovery needs an operational stream. If none remains,
|
||||
// fall back to configured-peer outage recovery instead of retrying
|
||||
// this impossible operation every minute.
|
||||
spawn_outage_recovery(context.db, context.wallet, context.map);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -203,7 +206,7 @@ async fn retry_dropped_outgoing(ip: String, port: u16) {
|
|||
|
||||
// Losing every miner peer is process-level outage recovery, not an
|
||||
// independent retry of each socket that happened to time out.
|
||||
if miner_connection_count().await == 0 {
|
||||
if peer_connection_count().await == 0 {
|
||||
spawn_outage_recovery(context.db, context.wallet, context.map);
|
||||
return;
|
||||
}
|
||||
|
|
@ -992,16 +995,18 @@ fn spawn_monitor_activation(
|
|||
// A reconnecting membership remains pending until an active sponsor's
|
||||
// monitor-add arrives. Do not let that pending node author its own
|
||||
// monitor event first; monitor validation correctly rejects it.
|
||||
let local_activation = timeout(Duration::from_secs(30), async {
|
||||
while !NodeInfo::is_active_address(&monitoring_address).await {
|
||||
let mapping_prerequisites = timeout(Duration::from_secs(30), async {
|
||||
while !NodeInfo::is_active_address(&monitoring_address).await
|
||||
|| !NodeInfo::contains_address(&monitored_address).await
|
||||
{
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
})
|
||||
.await;
|
||||
if local_activation.is_err() {
|
||||
if mapping_prerequisites.is_err() {
|
||||
warn!(
|
||||
"[network_map] connection setup timed out waiting for local membership activation: address={} peer={}:{}",
|
||||
monitoring_address, ip, port
|
||||
"[network_map] connection setup timed out waiting for mapping prerequisites: local={} monitored={} peer={}:{}",
|
||||
monitoring_address, monitored_address, ip, port
|
||||
);
|
||||
remove_stream_from_memory(&stream).await;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -208,42 +208,57 @@ impl NodeInfo {
|
|||
|
||||
pub(crate) async fn finish_mapping_snapshot_sync() {
|
||||
loop {
|
||||
let update = {
|
||||
let updates = {
|
||||
let mut state = MAPPING_SNAPSHOT_STATE.lock().await;
|
||||
match state.updates.pop_front() {
|
||||
Some(update) => Some(update),
|
||||
None => {
|
||||
if state.updates.is_empty() {
|
||||
state.active = false;
|
||||
None
|
||||
}
|
||||
Vec::new()
|
||||
} else {
|
||||
state.updates.drain(..).collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
|
||||
if updates.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Membership is the prerequisite for monitor validation. Live
|
||||
// broadcasts can reach a syncing node in either order, so replay
|
||||
// every deferred membership/snapshot change before monitor events.
|
||||
let mut monitor_updates = Vec::new();
|
||||
for update in updates {
|
||||
match update {
|
||||
Some(DeferredMappingUpdate::Add(db, edit)) => {
|
||||
DeferredMappingUpdate::Monitor(params, action) => {
|
||||
monitor_updates.push((params, action));
|
||||
}
|
||||
DeferredMappingUpdate::Add(db, edit) => {
|
||||
if let Err(err) = Self::import_signed_mapping_address(&db, edit, 0).await {
|
||||
warn!("[network_map] deferred node update was rejected: {err}");
|
||||
}
|
||||
}
|
||||
Some(DeferredMappingUpdate::Monitor(params, action)) => {
|
||||
DeferredMappingUpdate::SnapshotAddress(db, state) => {
|
||||
if let Err(err) = Self::import_synced_mapping_address_now(&db, state).await
|
||||
{
|
||||
warn!("[network_map] deferred snapshot-address update was rejected: {err}");
|
||||
}
|
||||
}
|
||||
DeferredMappingUpdate::ReconciledMembership(db, state) => {
|
||||
if let Err(err) = Self::import_reconciled_membership_now(&db, state).await {
|
||||
warn!(
|
||||
"[network_map] deferred reconciled membership was rejected: {err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (params, action) in monitor_updates {
|
||||
let RpcResponse::Binary(bytes) = Self::apply_monitor_now(params, action).await;
|
||||
let response = String::from_utf8_lossy(&bytes);
|
||||
if response != "Success" {
|
||||
warn!("[network_map] deferred monitor update was rejected: {response}");
|
||||
}
|
||||
}
|
||||
Some(DeferredMappingUpdate::SnapshotAddress(db, state)) => {
|
||||
if let Err(err) = Self::import_synced_mapping_address_now(&db, state).await {
|
||||
warn!("[network_map] deferred snapshot-address update was rejected: {err}");
|
||||
}
|
||||
}
|
||||
Some(DeferredMappingUpdate::ReconciledMembership(db, state)) => {
|
||||
if let Err(err) = Self::import_reconciled_membership_now(&db, state).await {
|
||||
warn!("[network_map] deferred reconciled membership was rejected: {err}");
|
||||
}
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ impl NodeInfo {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) async fn contains_address(address: &str) -> bool {
|
||||
ADDRESS_MAP.lock().await.contains_key(address)
|
||||
}
|
||||
|
||||
pub(crate) async fn signed_mapping_state() -> (Vec<SyncedNodeState>, Vec<SignedMonitorEdit>) {
|
||||
let map = ADDRESS_MAP.lock().await;
|
||||
let monitor_events = MONITOR_EVENT_STATE.lock().await;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::common::network_startup::{get_ip_and_port, get_node_connections};
|
|||
use crate::log::{error, info, warn};
|
||||
use crate::miner::flag::{is_mining_stop_requested, is_normal_mode};
|
||||
use crate::records::memory::connections::{
|
||||
miner_connection_count, operational_peer_wallets, ready_outgoing_connection_count,
|
||||
operational_peer_wallets, peer_connection_count, ready_outgoing_connection_count,
|
||||
refill_outgoing_connections_once,
|
||||
};
|
||||
use crate::records::memory::network_mapping::NodeInfo;
|
||||
|
|
@ -48,16 +48,18 @@ pub async fn handle_connections(
|
|||
info!("OUTGOING_CONNECTIONS is 0; waiting for an incoming sponsored peer.");
|
||||
}
|
||||
|
||||
loop {
|
||||
if outgoing_connections > 0
|
||||
&& attempt_bootstrap_connections(db.clone(), wallet.clone(), map.clone(), "startup")
|
||||
.await?
|
||||
&& attempt_bootstrap_connections(db.clone(), wallet.clone(), map.clone(), "startup").await?
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Startup gets one bounded pass through configured peers. If none can
|
||||
// sponsor this node, wait for a real incoming peer instead of repeatedly
|
||||
// dialing the list. Genesis remains blocked until reciprocal sponsorship
|
||||
// makes that peer operational.
|
||||
info!("No existing network peer is available. Waiting for connections.");
|
||||
for _ in 0..60 {
|
||||
loop {
|
||||
let peer_wallets = operational_peer_wallets().await;
|
||||
if is_normal_mode()
|
||||
&& !is_mining_stop_requested()
|
||||
|
|
@ -69,8 +71,6 @@ pub async fn handle_connections(
|
|||
}
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
warn!("No sponsored peer is operational; retrying configured bootstrap peers");
|
||||
}
|
||||
}
|
||||
|
||||
async fn attempt_bootstrap_connections(
|
||||
|
|
@ -81,7 +81,17 @@ async fn attempt_bootstrap_connections(
|
|||
) -> Result<bool, String> {
|
||||
// Try the configured bootstrap peers one by one until a
|
||||
// handshake succeeds or the list is exhausted.
|
||||
let filtered_servers = get_node_connections().await;
|
||||
let mut filtered_servers = get_node_connections().await;
|
||||
if context != "startup" {
|
||||
// During a live outage the synchronized in-memory mapping is still
|
||||
// available. Use its active endpoints as recovery candidates so the
|
||||
// configured bootstrap host is not a runtime single point of failure.
|
||||
for endpoint in NodeInfo::active_node_endpoints().await {
|
||||
if !filtered_servers.contains(&endpoint) {
|
||||
filtered_servers.push(endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
let (_, _, local_endpoint) = get_ip_and_port().await;
|
||||
let mut last_error: Option<String> = None;
|
||||
|
||||
|
|
@ -174,9 +184,10 @@ pub fn spawn_outage_recovery(db: Db, wallet: Arc<Wallet>, map: Arc<Mutex<Command
|
|||
tokio::spawn(async move {
|
||||
let _recovery_guard = recovery_guard;
|
||||
|
||||
// A miner socket still completing setup owns recovery even though it
|
||||
// is not ready for normal traffic yet.
|
||||
if miner_connection_count().await != 0 {
|
||||
// A raw socket that never completed setup is not network recovery.
|
||||
// Only an operational miner peer should suppress configured-peer
|
||||
// outage recovery.
|
||||
if peer_connection_count().await != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +216,7 @@ pub fn spawn_isolated_bootstrap_recovery(db: Db, wallet: Arc<Wallet>, map: Arc<M
|
|||
continue;
|
||||
}
|
||||
|
||||
if miner_connection_count().await == 0 {
|
||||
if peer_connection_count().await == 0 {
|
||||
spawn_outage_recovery(db.clone(), wallet.clone(), map.clone());
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue