use alloy::{primitives::Address, providers::Provider, sol};
use crate::newton_prover_task_manager::NewtonProverTaskManager;
sol! {
#[sol(rpc)]
interface ITaskResponseHandlerVerifier {
function certificateVerifier() external view returns (address);
}
}
#[derive(Debug, Clone, Copy)]
pub struct ResolvedDestinationVerifier {
pub task_response_handler: Address,
pub certificate_verifier: Address,
pub source_chain_avs: Address,
}
pub async fn resolve_destination_verifier<P>(
task_manager_addr: Address,
provider: P,
) -> Result<ResolvedDestinationVerifier, eyre::Error>
where
P: Provider + Clone,
{
let task_manager = NewtonProverTaskManager::new(task_manager_addr, provider.clone());
let task_response_handler = task_manager
.taskResponseHandler()
.call()
.await
.map_err(|e| eyre::eyre!("failed to get task response handler address: {:?}", e))?;
let task_response_handler_contract = ITaskResponseHandlerVerifier::new(task_response_handler, provider.clone());
let certificate_verifier = task_response_handler_contract
.certificateVerifier()
.call()
.await
.map_err(|e| eyre::eyre!("failed to get certificate verifier from task response handler: {:?}", e))?;
let source_chain_avs = task_manager
.serviceManager()
.call()
.await
.map_err(|e| eyre::eyre!("failed to get source chain avs address: {:?}", e))?;
Ok(ResolvedDestinationVerifier {
task_response_handler,
certificate_verifier,
source_chain_avs,
})
}
#[cfg(feature = "rpc")]
pub const DESTINATION_VERIFIER_TTL: std::time::Duration = std::time::Duration::from_secs(60);
#[cfg(feature = "rpc")]
#[async_trait::async_trait]
pub trait TaskResponseHandlerSource: Send + Sync {
async fn current_handler(&self, chain_id: u64, task_manager: Address) -> Option<Address>;
}
#[cfg(feature = "rpc")]
static HANDLER_SOURCE: std::sync::OnceLock<std::sync::Arc<dyn TaskResponseHandlerSource>> = std::sync::OnceLock::new();
#[cfg(feature = "rpc")]
pub fn set_task_response_handler_source(source: std::sync::Arc<dyn TaskResponseHandlerSource>) -> bool {
HANDLER_SOURCE.set(source).is_ok()
}
#[cfg(feature = "rpc")]
type VerifierCache =
std::sync::Mutex<std::collections::HashMap<(Address, String), (std::time::Instant, ResolvedDestinationVerifier)>>;
#[cfg(feature = "rpc")]
type HandlerWiringCache =
std::sync::Mutex<std::collections::HashMap<(Address, Address, String), ResolvedDestinationVerifier>>;
#[cfg(feature = "rpc")]
static DESTINATION_VERIFIERS: std::sync::LazyLock<VerifierCache> = std::sync::LazyLock::new(Default::default);
#[cfg(feature = "rpc")]
static HANDLER_WIRING: std::sync::LazyLock<HandlerWiringCache> = std::sync::LazyLock::new(Default::default);
#[cfg(feature = "rpc")]
#[tracing::instrument(
name = "chain.destination_verifier",
target = "newton::task_evaluation",
level = "debug",
skip(rpc_url),
fields(chain_id, %task_manager_addr, cache = tracing::field::Empty)
)]
pub async fn resolve_destination_verifier_cached(
chain_id: u64,
task_manager_addr: Address,
rpc_url: &str,
) -> Result<ResolvedDestinationVerifier, eyre::Error> {
let span = tracing::Span::current();
let handler = match HANDLER_SOURCE.get() {
Some(source) => source.current_handler(chain_id, task_manager_addr).await,
None => None,
};
if let Some(handler) = handler {
let key = (task_manager_addr, handler, rpc_url.to_string());
let cached = HANDLER_WIRING
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.get(&key)
.copied();
if let Some(resolved) = cached {
span.record("cache", "indexed");
return Ok(resolved);
}
span.record("cache", "indexed_miss");
let resolved = resolve_handler_wiring(task_manager_addr, handler, rpc_url).await?;
HANDLER_WIRING
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.insert(key, resolved);
return Ok(resolved);
}
let key = (task_manager_addr, rpc_url.to_string());
let cached = DESTINATION_VERIFIERS
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.get(&key)
.copied();
if let Some((at, resolved)) = cached {
if at.elapsed() < DESTINATION_VERIFIER_TTL {
span.record("cache", "hit");
return Ok(resolved);
}
}
span.record("cache", "miss");
let resolved = resolve_destination_verifier(task_manager_addr, newton_rpc_provider::get_provider(rpc_url)).await?;
DESTINATION_VERIFIERS
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.insert(key, (std::time::Instant::now(), resolved));
Ok(resolved)
}
#[cfg(feature = "rpc")]
async fn resolve_handler_wiring(
task_manager_addr: Address,
handler: Address,
rpc_url: &str,
) -> Result<ResolvedDestinationVerifier, eyre::Error> {
let provider = newton_rpc_provider::get_provider(rpc_url);
let task_manager = NewtonProverTaskManager::new(task_manager_addr, provider.clone());
let handler_contract = ITaskResponseHandlerVerifier::new(handler, provider.clone());
let (certificate_verifier, source_chain_avs) = tokio::try_join!(
async {
handler_contract
.certificateVerifier()
.call()
.await
.map_err(|e| eyre::eyre!("failed to get certificate verifier from task response handler: {:?}", e))
},
async {
task_manager
.serviceManager()
.call()
.await
.map_err(|e| eyre::eyre!("failed to get source chain avs address: {:?}", e))
},
)?;
Ok(ResolvedDestinationVerifier {
task_response_handler: handler,
certificate_verifier,
source_chain_avs,
})
}