From 8c4e7f79485153067278193e8fb9b03217dc70eb Mon Sep 17 00:00:00 2001 From: EehMauro Date: Tue, 30 Sep 2025 18:40:35 -0300 Subject: [PATCH] feat(trp): add trp resolve tx evaluate --- crates/trp/src/compiler.rs | 34 +++++++++------------- crates/trp/src/error.rs | 10 +++++++ crates/trp/src/lib.rs | 59 ++++++++++++++++++++++++++++++++++++-- crates/trp/src/methods.rs | 6 ++-- crates/trp/src/utxos.rs | 28 +++++++++++++++++- 5 files changed, 111 insertions(+), 26 deletions(-) diff --git a/crates/trp/src/compiler.rs b/crates/trp/src/compiler.rs index 02d6dc15..e45b1cdd 100644 --- a/crates/trp/src/compiler.rs +++ b/crates/trp/src/compiler.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use dolos_core::{Domain, Genesis}; -use crate::{Config, Error}; +use crate::{Facade, Config, Error}; pub fn network_id_from_genesis(genesis: &Genesis) -> Option { match genesis.shelley.network_id.as_ref() { @@ -29,39 +29,31 @@ fn map_cost_models(original: CostModels) -> HashMap HashMap::from_iter(present) } -fn build_pparams(domain: &D) -> Result { +pub fn load_compiler( + domain: &Facade, + config: &Config, +) -> Result { let network = network_id_from_genesis(domain.genesis()).unwrap(); - let pparams = dolos_cardano::load_active_pparams(domain) - .map_err(|_| Error::PParamsNotAvailable)? - .ok_or(Error::PParamsNotAvailable)?; + let pparams = domain.get_pparams()?; let costs = pparams .cost_models_for_script_languages() .ok_or(Error::PParamsNotAvailable)?; - let out = tx3_cardano::PParams { - network, - cost_models: map_cost_models(costs), - min_fee_coefficient: pparams.min_fee_a_or_default() as u64, - min_fee_constant: pparams.min_fee_b_or_default() as u64, - coins_per_utxo_byte: pparams.ada_per_utxo_byte_or_default() as u64, - }; + let chain_tip = domain.get_chain_tip()?; - Ok(out) -} - -pub fn load_compiler( - domain: &D, - config: &Config, -) -> Result { - let pparams = build_pparams::(domain)?; + let slot_config = domain.get_slot_config()?; let compiler = tx3_cardano::Compiler::new( - pparams, tx3_cardano::Config { extra_fees: config.extra_fees, }, + network, + chain_tip, + pparams, + map_cost_models(costs), + slot_config, ); Ok(compiler) diff --git a/crates/trp/src/error.rs b/crates/trp/src/error.rs index b7cfb7e2..94ccc024 100644 --- a/crates/trp/src/error.rs +++ b/crates/trp/src/error.rs @@ -52,6 +52,12 @@ pub enum Error { #[error("tx script returned failure")] TxScriptFailure(Vec), + + #[error("failed to resolve tip slot/hash")] + TipNotResolved, + + #[error("failed to resolve chain summary: {0}")] + ChainSummaryNotResolved(String), } trait IntoErrorData { @@ -128,6 +134,8 @@ impl Error { pub const CODE_MISSING_TX_ARG: i32 = -32001; pub const CODE_INPUT_NOT_RESOLVED: i32 = -32002; pub const CODE_TX_SCRIPT_FAILURE: i32 = -32003; + pub const CODE_TIP_NOT_RESOLVED: i32 = -32004; + pub const CODE_CHAIN_SUMMARY_NOT_RESOLVED: i32 = -32005; pub fn code(&self) -> i32 { match self { @@ -149,6 +157,8 @@ impl Error { Error::MissingTxArg { .. } => Self::CODE_MISSING_TX_ARG, Error::InputNotResolved(_, _, _) => Self::CODE_INPUT_NOT_RESOLVED, Error::TxScriptFailure(_) => Self::CODE_TX_SCRIPT_FAILURE, + Error::TipNotResolved => Self::CODE_TIP_NOT_RESOLVED, + Error::ChainSummaryNotResolved(_) => Self::CODE_CHAIN_SUMMARY_NOT_RESOLVED, } } diff --git a/crates/trp/src/lib.rs b/crates/trp/src/lib.rs index b77a6969..7d69dd43 100644 --- a/crates/trp/src/lib.rs +++ b/crates/trp/src/lib.rs @@ -1,12 +1,19 @@ use jsonrpsee::server::{RpcModule, Server}; use serde::{Deserialize, Serialize}; -use std::{net::SocketAddr, sync::Arc}; +use std::{ + net::SocketAddr, + sync::Arc, + ops::Deref, +}; use tokio::select; use tower::ServiceBuilder; use tower_http::cors::CorsLayer; use tracing::info; -use dolos_core::{CancelToken, Domain, ServeError}; +use tx3_cardano::ChainPoint; +use dolos_core::{Domain, StateStore, CancelToken, ServeError}; +use dolos_cardano::{ChainSummary, PParamsSet}; +use pallas::ledger::validate::phase2::script_context::SlotConfig; mod compiler; mod error; @@ -107,3 +114,51 @@ impl dolos_core::Driver for Driver { } } } + +#[derive(Clone)] +pub struct Facade { + pub inner: D, +} + +impl Deref for Facade { + type Target = D; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Facade { + pub fn get_chain_summary(&self) -> Result { + let summary = dolos_cardano::eras::load_era_summary(&self.inner) + .map_err(|e| error::Error::ChainSummaryNotResolved(e.to_string()))?; + + Ok(summary) + } + + pub fn get_slot_config(&self) -> Result { + let chain = self.get_chain_summary()?; + + Ok(SlotConfig { + slot_length: chain.edge().slot_length, + zero_slot: chain.edge().start.slot, + zero_time: chain.edge().start.timestamp, + }) + } + + pub fn get_chain_tip(&self) -> Result { + let cursor = self.inner.state().read_cursor()?.ok_or(Error::TipNotResolved)?; + let slot = cursor.slot(); + let hash = cursor.hash().map(|h| h.to_vec()).unwrap_or_default(); + + Ok(ChainPoint { slot, hash }) + } + + pub fn get_pparams(&self) -> Result { + let pparams = dolos_cardano::load_active_pparams(&self.inner) + .map_err(|_| Error::PParamsNotAvailable)? + .ok_or(Error::PParamsNotAvailable)?; + + Ok(pparams) + } +} \ No newline at end of file diff --git a/crates/trp/src/methods.rs b/crates/trp/src/methods.rs index ed6d048d..146eb3aa 100644 --- a/crates/trp/src/methods.rs +++ b/crates/trp/src/methods.rs @@ -8,7 +8,7 @@ use tx3_sdk::trp::{SubmitParams, SubmitWitness}; use dolos_core::{Domain, MempoolStore as _, StateStore as _}; -use crate::{compiler::load_compiler, utxos::UtxoStoreAdapter}; +use crate::{Facade, compiler::load_compiler, utxos::UtxoStoreAdapter}; use super::{Context, Error}; @@ -77,7 +77,9 @@ pub async fn trp_resolve( let tx = load_tx(params)?; - let mut compiler = load_compiler::(&context.domain, &context.config)?; + let facade = Facade { inner: context.domain.clone() }; + + let mut compiler = load_compiler::(&facade, &context.config)?; let utxos = UtxoStoreAdapter::::new(context.domain.state().clone()); diff --git a/crates/trp/src/utxos.rs b/crates/trp/src/utxos.rs index 94697851..07f8bdf7 100644 --- a/crates/trp/src/utxos.rs +++ b/crates/trp/src/utxos.rs @@ -5,7 +5,8 @@ use tx3_lang::{ UtxoRef, UtxoSet, }; -use dolos_core::{Domain, StateStore as _, TxoRef}; +use dolos_core::{Domain, StateStore as _, TxoRef, EraCbor}; +use pallas::ledger::validate::utils::UtxoMap; use crate::{ mapping::{from_tx3_utxoref, into_tx3_utxo, into_tx3_utxoref}, @@ -75,4 +76,29 @@ impl UtxoStore for UtxoStoreAdapter { Ok(utxos) } + + async fn fetch_utxos_deps( + &self, + refs: HashSet + ) -> Result { + let refs: Vec<_> = refs.into_iter().map(from_tx3_utxoref).collect(); + + let utxos = self.state().get_utxos(refs).map_err(Error::from)?; + + let utxos = utxos + .into_iter() + .map(|(txoref, eracbor)| { + let TxoRef(a, b) = txoref; + let EraCbor(c, d) = eracbor.as_ref(); + let era = pallas::ledger::traverse::Era::try_from(*c).expect("era out of range"); + + ( + pallas::ledger::validate::utils::TxoRef::from((a, b)), + pallas::ledger::validate::utils::EraCbor::from((era, d.clone())), + ) + }) + .collect(); + + Ok(utxos) + } }