diff --git a/Cargo.lock b/Cargo.lock index a5f6b991..732b9a1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1374,7 +1374,7 @@ dependencies = [ "tower-http 0.6.6", "tracing", "tx3-cardano", - "tx3-lang", + "tx3-lang 0.11.4", "tx3-resolver", "tx3-sdk", ] @@ -5402,23 +5402,37 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tx3-cardano" version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5f14e3e1b68b1bff81d58c891604a3087f34be70c2a2ad58a8605b6f15ed82" +source = "git+https://github.com/tx3-lang/tx3.git#1784858e67721d8e6b87084c479fe94714290b64" dependencies = [ "hex", "pallas 1.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "thiserror 2.0.12", "trait-variant", - "tx3-lang", + "tx3-lang 0.11.4", "utxorpc", ] [[package]] name = "tx3-lang" version = "0.11.4" +source = "git+https://github.com/tx3-lang/tx3.git#1784858e67721d8e6b87084c479fe94714290b64" +dependencies = [ + "bincode 2.0.1", + "hex", + "miette", + "pest", + "pest_derive", + "serde", + "thiserror 2.0.12", + "trait-variant", +] + +[[package]] +name = "tx3-lang" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7607218726810f53079b50a63ff4b5e25a8ccf53a82a80d7b6cc1815feec7a65" +checksum = "f9ffdc30232bfe0bfeced3d48768b8f00ed9f3015d9e78323ecda4cf45cbbd56" dependencies = [ "bincode 2.0.1", "hex", @@ -5433,13 +5447,12 @@ dependencies = [ [[package]] name = "tx3-resolver" version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654a0598f575d665145dc711443082683d66a0fc8a4673e68dbc1f314d87d028" +source = "git+https://github.com/tx3-lang/tx3.git#1784858e67721d8e6b87084c479fe94714290b64" dependencies = [ "hex", "thiserror 2.0.12", "trait-variant", - "tx3-lang", + "tx3-lang 0.11.4", ] [[package]] @@ -5455,7 +5468,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.12", - "tx3-lang", + "tx3-lang 0.11.5", "uuid", ] diff --git a/crates/trp/Cargo.toml b/crates/trp/Cargo.toml index bf5b468b..5c26bfda 100644 --- a/crates/trp/Cargo.toml +++ b/crates/trp/Cargo.toml @@ -24,17 +24,17 @@ jsonrpsee = { version = "0.24.9", features = ["server"] } opentelemetry = "0.30.0" opentelemetry_sdk = "0.30.0" -tx3-lang = "0.11.4" -tx3-cardano = "0.11.4" -tx3-resolver = "0.11.4" +# tx3-lang = "0.11.4" +# tx3-cardano = "0.11.4" +# tx3-resolver = "0.11.4" # tx3-lang = { path = "../../../../tx3-lang/tx3/crates/tx3-lang" } # tx3-cardano = { path = "../../../../tx3-lang/tx3/crates/tx3-cardano" } # tx3-resolver = { path = "../../../../tx3-lang/tx3/crates/tx3-resolver" } -# tx3-lang = { git = "https://github.com/tx3-lang/tx3.git" } -# tx3-cardano = { git = "https://github.com/tx3-lang/tx3.git" } -# tx3-resolver = { git = "https://github.com/tx3-lang/tx3.git" } +tx3-lang = { git = "https://github.com/tx3-lang/tx3.git" } +tx3-cardano = { git = "https://github.com/tx3-lang/tx3.git" } +tx3-resolver = { git = "https://github.com/tx3-lang/tx3.git" } tx3-sdk = { version = "^0" } # tx3-sdk = { path = "../../../../tx3-lang/rust-sdk/sdk" } diff --git a/crates/trp/src/compiler.rs b/crates/trp/src/compiler.rs index 15c40a04..8b9b5134 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,36 +29,29 @@ 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_effective_pparams::(domain.state()) - .map_err(|_| Error::PParamsNotAvailable)?; + let pparams = domain.get_pparams()?; let costs = pparams.cost_models_for_script_languages(); - 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, - }; - - Ok(out) -} + let chain_tip = domain.get_chain_tip()?; -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..0cba3c0f 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.state()) + .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(); + let timestamp = (slot * 1000) as u128; // TODO: check if this is the correct way to get timestamp + + Ok(ChainPoint { slot, hash, timestamp }) + } + + pub fn get_pparams(&self) -> Result { + let pparams = dolos_cardano::load_effective_pparams::(&self.inner.state()) + .map_err(|_| 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) + } }