urma-runtime 0.3.1

URMA publication planning, network transports and recovery
Documentation
#[cfg(not(target_arch = "wasm32"))]
use crate::electrum::Electrum;
use crate::endpoints::PublicEndpoint;
use crate::error::Error;
use crate::light::LightSync;
#[cfg(not(target_arch = "wasm32"))]
use crate::p2p::P2pProvider;
#[cfg(not(target_arch = "wasm32"))]
use crate::pinning::Pins;
use crate::remote::Remote;
use crate::transport::Provider;
#[cfg(not(target_arch = "wasm32"))]
use std::path::Path;
#[cfg(not(target_arch = "wasm32"))]
use std::sync::Arc;
use urma_chain::observation::Chain;

pub enum LightClient {
    Absent,
    #[cfg(not(target_arch = "wasm32"))]
    P2p(Arc<P2pProvider>),
}

impl LightClient {
    pub(crate) fn providers(&self) -> Vec<Box<dyn Provider>> {
        match self {
            Self::Absent => Vec::new(),
            #[cfg(not(target_arch = "wasm32"))]
            Self::P2p(provider) => vec![Box::new(provider.clone())],
        }
    }

    pub(crate) fn state(&self) -> LightSync {
        match self {
            Self::Absent => LightSync::Absent,
            #[cfg(not(target_arch = "wasm32"))]
            Self::P2p(provider) => provider.state(),
        }
    }

    pub(crate) fn warm(&self) -> Result<(), Error> {
        match self {
            Self::Absent => {
                tracing::debug!("no light client to warm");
                Ok(())
            }
            #[cfg(not(target_arch = "wasm32"))]
            Self::P2p(provider) => provider.warm(),
        }
    }
}

#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn light_clients(chain: Chain, cache_dir: &Path) -> Result<LightClient, Error> {
    match chain {
        Chain::LitecoinMainnet | Chain::LitecoinTestnet => Ok(LightClient::P2p(Arc::new(
            P2pProvider::new(chain, cache_dir)?,
        ))),
        Chain::BitcoinMainnet | Chain::BitcoinRegtest | Chain::BitcoinTestnet4 => {
            tracing::debug!(
                ?chain,
                "no light client provider for this chain; reads start at public providers"
            );
            Ok(LightClient::Absent)
        }
    }
}

#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn assemble(
    endpoints: Vec<PublicEndpoint>,
    pins: Arc<Pins>,
    light: &LightClient,
) -> Result<Vec<Box<dyn Provider>>, Error> {
    let mut providers = light.providers();
    for endpoint in endpoints {
        let provider: Box<dyn Provider> = match endpoint {
            PublicEndpoint::Electrum(_) => Box::new(Electrum::new(endpoint, pins.clone())?),
            PublicEndpoint::Rpc(_) | PublicEndpoint::Esplora(_) => Box::new(Remote::new(endpoint)?),
        };
        providers.push(provider);
    }
    Ok(providers)
}

#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn ephemeral(
    chain: Chain,
    endpoints: Vec<PublicEndpoint>,
) -> Result<Vec<Box<dyn Provider>>, Error> {
    tracing::debug!(
        ?chain,
        "ephemeral public node has no cache directory; no light client"
    );
    assemble(endpoints, Arc::new(Pins::ephemeral()), &LightClient::Absent)
}

#[cfg(target_arch = "wasm32")]
pub(crate) fn ephemeral(
    chain: Chain,
    endpoints: Vec<PublicEndpoint>,
) -> Result<Vec<Box<dyn Provider>>, Error> {
    tracing::debug!(?chain, "no light client provider on WASM");
    let mut providers = LightClient::Absent.providers();
    for endpoint in endpoints {
        let provider: Box<dyn Provider> = match endpoint {
            PublicEndpoint::Electrum(url) => {
                return Err(Error::Unsupported(format!(
                    "electrum endpoint {url} needs a TCP socket, unavailable on WASM"
                )));
            }
            PublicEndpoint::Rpc(_) | PublicEndpoint::Esplora(_) => Box::new(Remote::new(endpoint)?),
        };
        providers.push(provider);
    }
    Ok(providers)
}