use std::num::NonZeroU32;
pub use esplora_client;
use esplora_client::BlockingClient;
use rgb::bitcoin::constants::ChainHash;
use rgb::bitcoin::Txid;
use rgbcore::validation::{ResolveWitness, WitnessResolverError, WitnessStatus};
use rgbcore::vm::{WitnessOrd, WitnessPos};
use rgbcore::ChainNet;
pub struct EsploraClient {
pub inner: BlockingClient,
}
impl ResolveWitness for EsploraClient {
fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError> {
let block_hash = self
.inner
.get_block_hash(0)
.map_err(|e| WitnessResolverError::ResolverIssue(None, e.to_string()))?;
let chain_hash = ChainHash::from_genesis_block_hash(block_hash);
if chain_net.chain_hash() != chain_hash {
return Err(WitnessResolverError::WrongChainNet);
}
Ok(())
}
fn resolve_witness(&self, txid: Txid) -> Result<WitnessStatus, WitnessResolverError> {
let Some(tx) = self
.inner
.get_tx(&txid)
.map_err(|e| WitnessResolverError::ResolverIssue(Some(txid), e.to_string()))?
else {
return Ok(WitnessStatus::Unresolved);
};
let status = self
.inner
.get_tx_status(&txid)
.map_err(|e| WitnessResolverError::ResolverIssue(Some(txid), e.to_string()))?;
let ord = match status
.block_height
.and_then(|h| status.block_time.map(|t| (h, t)))
{
Some((h, t)) => {
let height = NonZeroU32::new(h).ok_or(WitnessResolverError::InvalidResolverData)?;
WitnessOrd::Mined(
WitnessPos::bitcoin(height, t as i64)
.ok_or(WitnessResolverError::InvalidResolverData)?,
)
}
None => WitnessOrd::Tentative,
};
Ok(WitnessStatus::Resolved(tx, ord))
}
}