From 946719a7e914513264a7dcedf51242031c8603f0 Mon Sep 17 00:00:00 2001 From: opencode-bot Date: Fri, 24 Jul 2026 06:32:23 +0700 Subject: [PATCH] fix: heartbeat timestamp unit, transfer normalization, validator propagation, error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Fix heartbeat timestamp: seconds → milliseconds (setu-rpc/src/registration.rs) - Heartbeat used as_secs() while entire codebase uses milliseconds - Staleness checks were off by 1000×, causing false timeout/alive decisions 2. Fix transfer forwards unnormalized addresses (setu-validator/src/user_handler.rs) - Anti-replay precheck and signature used normalized (lowercase) addresses - But SubmitTransferRequest forwarded original-case addresses - Downstream TEE runtime computed different nonce marker → precheck bypass 3. Fix add_validator not propagated to consensus engine (setu-validator/src/consensus_integration.rs) - add_validator() updated local ValidatorSet but NOT the engine's copy - New validators were invisible to quorum/leader election - add_peer_validator() already did this correctly; add_validator() was missing it 4. Fix GenericHandler swallowing errors (crates/setu-network-anemo/src/generic_handler.rs) - Handler errors returned 200 OK with empty body - Callers could not distinguish errors from legitimate empty responses - Now returns error message in body with __HANDLER_ERROR__: prefix --- crates/setu-network-anemo/src/generic_handler.rs | 8 ++++++-- setu-rpc/src/registration.rs | 2 +- setu-validator/src/consensus_integration.rs | 8 ++++++-- setu-validator/src/user_handler.rs | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/setu-network-anemo/src/generic_handler.rs b/crates/setu-network-anemo/src/generic_handler.rs index f7cac25d..6e5e443f 100644 --- a/crates/setu-network-anemo/src/generic_handler.rs +++ b/crates/setu-network-anemo/src/generic_handler.rs @@ -110,8 +110,12 @@ where Ok(Response::new(Bytes::new())) } Err(e) => { - tracing::warn!("Handler error: {}", e); - Ok(Response::new(Bytes::new())) + tracing::warn!("Handler error on route {}: {}", route, e); + // Return the error as the response body instead of silently + // swallowing it. Callers can detect errors by checking for + // the "__HANDLER_ERROR__:" prefix. + let error_body = format!("__HANDLER_ERROR__:{e}"); + Ok(Response::new(Bytes::from(error_body))) } } } diff --git a/setu-rpc/src/registration.rs b/setu-rpc/src/registration.rs index ded1f157..e52462dd 100644 --- a/setu-rpc/src/registration.rs +++ b/setu-rpc/src/registration.rs @@ -208,7 +208,7 @@ impl RegistrationClient { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() - .as_secs(); + .as_millis() as u64; let request = HeartbeatRequest { node_id, diff --git a/setu-validator/src/consensus_integration.rs b/setu-validator/src/consensus_integration.rs index 2c53b22b..05bf5f71 100644 --- a/setu-validator/src/consensus_integration.rs +++ b/setu-validator/src/consensus_integration.rs @@ -847,8 +847,12 @@ impl ConsensusValidator { let mut vs = self.validator_set.write().await; vs.add_validator(info.clone()); - // Also register in TEE verifier if they have a public key - // (This would be extended in a real implementation) + // Also update the engine's ValidatorSet + ConsensusManager.validator_count + // so the new validator is visible to quorum/leader election logic. + // Without this, the validator exists in the local copy but is invisible + // to the consensus engine. + drop(vs); + self.engine.add_consensus_validator(info.clone()).await; info!( validator_id = %info.node.id, diff --git a/setu-validator/src/user_handler.rs b/setu-validator/src/user_handler.rs index 72954e5a..ab58fc7e 100644 --- a/setu-validator/src/user_handler.rs +++ b/setu-validator/src/user_handler.rs @@ -1142,8 +1142,8 @@ impl UserRpcHandler for ValidatorUserHandler { // Forward the canonical subnet id (D1); no local side effects before // DAG submission succeeds or fails inside submit_transfer. let submit_request = SubmitTransferRequest { - from: request.from, - to: request.to, + from: normalized_from, + to: normalized_to, amount: amount_units, transfer_type: "setu".to_string(), resources: vec![],