From 39297988c12c92eaa065d67bd8feab425c4d591c Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Sun, 19 Jan 2025 17:53:06 -0300 Subject: [PATCH] refactor: revisit the pparams folding approach --- Cargo.lock | 33 +++++----- src/bin/dolos/data/summary.rs | 6 +- src/bin/dolos/eval.rs | 5 +- src/ledger/pparams/mod.rs | 103 ++++++----------------------- src/ledger/pparams/summary.rs | 121 +++++++++++++++++++++++++--------- src/mempool.rs | 52 ++++++++------- src/serve/grpc/mod.rs | 2 +- src/serve/grpc/query.rs | 8 ++- 8 files changed, 167 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5c6dc9..8ec3955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,7 +365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes 0.11.0", - "rand_core 0.6.4", + "rand_core 0.5.1", "serde", "unicode-normalization", ] @@ -2239,7 +2239,7 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" [[package]] name = "pallas" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "pallas-addresses 0.32.0", "pallas-applying", @@ -2273,7 +2273,7 @@ dependencies = [ [[package]] name = "pallas-addresses" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "base58", "bech32 0.9.1", @@ -2288,7 +2288,7 @@ dependencies = [ [[package]] name = "pallas-applying" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "chrono", "hex", @@ -2298,6 +2298,7 @@ dependencies = [ "pallas-primitives 0.32.0", "pallas-traverse 0.32.0", "rand", + "thiserror 1.0.65", ] [[package]] @@ -2315,7 +2316,7 @@ dependencies = [ [[package]] name = "pallas-codec" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "hex", "minicbor", @@ -2326,7 +2327,7 @@ dependencies = [ [[package]] name = "pallas-configs" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "base64 0.22.1", "hex", @@ -2358,7 +2359,7 @@ dependencies = [ [[package]] name = "pallas-crypto" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "cryptoxide", "hex", @@ -2386,7 +2387,7 @@ dependencies = [ [[package]] name = "pallas-hardano" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "binary-layout", "pallas-network 0.32.0", @@ -2417,7 +2418,7 @@ dependencies = [ [[package]] name = "pallas-network" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "byteorder", "hex", @@ -2450,7 +2451,7 @@ dependencies = [ [[package]] name = "pallas-primitives" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "base58", "bech32 0.9.1", @@ -2482,7 +2483,7 @@ dependencies = [ [[package]] name = "pallas-traverse" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "hex", "itertools 0.13.0", @@ -2498,7 +2499,7 @@ dependencies = [ [[package]] name = "pallas-txbuilder" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "hex", "pallas-addresses 0.32.0", @@ -2515,7 +2516,7 @@ dependencies = [ [[package]] name = "pallas-utxorpc" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "pallas-applying", "pallas-codec 0.32.0", @@ -2529,7 +2530,7 @@ dependencies = [ [[package]] name = "pallas-wallet" version = "0.32.0" -source = "git+https://github.com/txpipe/pallas.git#f6f344cff56871a5bd5da80336db10439f903c19" +source = "git+https://github.com/txpipe/pallas.git#305c5c562285b5a6b81e91eba18e72444481bd23" dependencies = [ "bech32 0.9.1", "bip39", @@ -2747,7 +2748,7 @@ checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" dependencies = [ "bytes", "heck", - "itertools 0.13.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -2780,7 +2781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn", diff --git a/src/bin/dolos/data/summary.rs b/src/bin/dolos/data/summary.rs index 6d68814..e89d444 100644 --- a/src/bin/dolos/data/summary.rs +++ b/src/bin/dolos/data/summary.rs @@ -113,11 +113,9 @@ pub fn run(config: &crate::Config, _args: &Args) -> miette::Result<()> { let genesis = crate::common::open_genesis_files(&config.genesis)?; - let (pparams, summary) = dolos::ledger::pparams::fold(&genesis, &updates); + let eras = dolos::ledger::pparams::fold(&genesis, &updates); - println!("{:?}", summary); - println!("---"); - println!("{:?}", pparams); + println!("{:?}", eras); println!("---"); diff --git a/src/bin/dolos/eval.rs b/src/bin/dolos/eval.rs index a6a5ffa..11e9d6d 100644 --- a/src/bin/dolos/eval.rs +++ b/src/bin/dolos/eval.rs @@ -87,7 +87,10 @@ pub fn run(config: &super::Config, args: &Args) -> miette::Result<()> { }) .try_collect()?; - let (pparams, _) = dolos::ledger::pparams::fold_until_epoch(&genesis, &updates, args.epoch); + let pparams = dolos::ledger::pparams::fold(&genesis, &updates) + .edge() + .pparams + .clone(); let context = ValidationContext { block_slot: args.block_slot, diff --git a/src/ledger/pparams/mod.rs b/src/ledger/pparams/mod.rs index 3534de4..683c257 100644 --- a/src/ledger/pparams/mod.rs +++ b/src/ledger/pparams/mod.rs @@ -9,7 +9,7 @@ use pallas::{ traverse::MultiEraUpdate, }, }; -use tracing::{debug, warn}; +use tracing::{debug, trace, warn}; mod summary; @@ -183,7 +183,8 @@ fn bootstrap_conway_pparams( min_pool_cost: previous.min_pool_cost, desired_number_of_stake_pools: previous.desired_number_of_stake_pools, // In the hardfork, the value got translated from words to bytes - // Since the transformation from words to bytes is hardcoded, the transformation here is also hardcoded + // Since the transformation from words to bytes is hardcoded, the transformation here is + // also hardcoded ada_per_utxo_byte: previous.ada_per_utxo_byte / 8, execution_costs: previous.execution_costs, max_tx_ex_units: previous.max_tx_ex_units, @@ -308,9 +309,15 @@ fn apply_param_update( pparams.max_tx_size = new; } + if let Some(new) = update.byron_proposed_block_version() { + debug!("found new byron block version update proposal"); + pparams.block_version = new; + } + MultiEraProtocolParameters::Byron(pparams) } MultiEraProtocolParameters::Shelley(mut pparams) => { + apply_field!(pparams, update, protocol_version); apply_field!(pparams, update, minfee_a); apply_field!(pparams, update, minfee_b); apply_field!(pparams, update, max_block_body_size); @@ -330,6 +337,7 @@ fn apply_param_update( MultiEraProtocolParameters::Shelley(pparams) } MultiEraProtocolParameters::Alonzo(mut pparams) => { + apply_field!(pparams, update, protocol_version); apply_field!(pparams, update, minfee_a); apply_field!(pparams, update, minfee_b); apply_field!(pparams, update, max_block_body_size); @@ -365,6 +373,7 @@ fn apply_param_update( MultiEraProtocolParameters::Alonzo(pparams) } MultiEraProtocolParameters::Babbage(mut pparams) => { + apply_field!(pparams, update, protocol_version); apply_field!(pparams, update, minfee_a); apply_field!(pparams, update, minfee_b); apply_field!(pparams, update, max_block_body_size); @@ -400,6 +409,7 @@ fn apply_param_update( MultiEraProtocolParameters::Babbage(pparams) } MultiEraProtocolParameters::Conway(mut pparams) => { + apply_field!(pparams, update, protocol_version); apply_field!(pparams, update, minfee_a); apply_field!(pparams, update, minfee_b); apply_field!(pparams, update, max_block_body_size); @@ -500,83 +510,16 @@ fn migrate_pparams( } } -pub fn fold_until_epoch( - genesis: &Genesis, - updates: &[MultiEraUpdate], - for_epoch: u64, -) -> (MultiEraProtocolParameters, ChainSummary) { - debug!("Initializing with Byron parameters"); - let mut pparams = MultiEraProtocolParameters::Byron(bootstrap_byron_pparams(&genesis.byron)); - - let mut summary = ChainSummary::start(&pparams); - - if let Some(force_protocol) = genesis.force_protocol { - while summary.current().protocol_version < force_protocol { - let next_protocol = summary.current().protocol_version + 1; - pparams = migrate_pparams(pparams, genesis, next_protocol); - summary.advance(0, &pparams); - - debug!( - protocol = summary.current().protocol_version, - "forced hardfork" - ); - } - } - - for epoch in 1..for_epoch { - let epoch_updates: Vec<_> = updates - .iter() - .filter(|e| e.epoch() == (epoch - 1)) - .collect(); - - if !epoch_updates.is_empty() { - debug!( - epoch, - count = epoch_updates.len(), - "found updates for epoch", - ); - } - - for update in epoch_updates { - pparams = apply_param_update(pparams, update); +pub fn fold(genesis: &Genesis, updates: &[MultiEraUpdate]) -> ChainSummary { + let mut summary = ChainSummary::start(genesis); - let byron_version_change = update - .byron_proposed_block_version() - .map(|(v, _, _)| (v as usize)); + updates.to_vec().sort_by_key(|u| u.epoch()); - let post_byron_version_change = update - .first_proposed_protocol_version() - .map(|(v, _)| v as usize); - - let version_change = byron_version_change.or(post_byron_version_change); - - if let Some(next_protocol) = version_change { - while summary.current().protocol_version < next_protocol { - let next_protocol = summary.current().protocol_version + 1; - pparams = migrate_pparams(pparams, genesis, next_protocol); - summary.advance(epoch, &pparams); - - debug!( - protocol = summary.current().protocol_version, - "hardfork executed" - ); - } - } - } + for update in updates { + summary.apply_update(update, genesis); } - (pparams, summary) -} - -pub fn fold( - genesis: &Genesis, - updates: &[MultiEraUpdate], -) -> (MultiEraProtocolParameters, ChainSummary) { - let for_epoch = updates.last().map(|u| u.epoch()).unwrap_or(0); - - let (pparams, summary) = fold_until_epoch(genesis, updates, for_epoch); - - (pparams, summary) + summary } #[cfg(test)] @@ -649,17 +592,11 @@ mod tests { println!("Comparing to {:?}", filename); - let epoch = filename - .file_stem() - .and_then(|s| s.to_str()) - .and_then(|s| s.parse::().ok()) - .unwrap(); - // TODO: implement serialize/deserialize, and get full protocol param json files let expected = load_json::(filename); - let (_, summary) = fold_until_epoch(&genesis, &chained_updates, epoch); + let summary = fold(&genesis, &chained_updates); - assert_eq!(expected, summary.current().protocol_version) + assert_eq!(expected, summary.edge().pparams.protocol_version()) //assert_eq!(expected, actual) } diff --git a/src/ledger/pparams/summary.rs b/src/ledger/pparams/summary.rs index eaa19b1..c4f8e11 100644 --- a/src/ledger/pparams/summary.rs +++ b/src/ledger/pparams/summary.rs @@ -1,4 +1,7 @@ -use pallas::applying::MultiEraProtocolParameters; +use pallas::{applying::MultiEraProtocolParameters, ledger::traverse::MultiEraUpdate}; +use tracing::debug; + +use super::Genesis; #[derive(Clone, Debug)] pub struct EraBoundary { @@ -11,67 +14,125 @@ pub struct EraBoundary { pub struct EraSummary { pub start: EraBoundary, pub end: Option, - pub protocol_version: usize, - pub epoch_length: u64, - pub slot_length: u64, + pub pparams: MultiEraProtocolParameters, } #[derive(Debug)] pub struct ChainSummary { past: Vec, - current: Option, + edge: Option, } impl ChainSummary { - pub fn start(initial_pparams: &MultiEraProtocolParameters) -> Self { + pub fn start(genesis: &Genesis) -> Self { + let mut pparams = + MultiEraProtocolParameters::Byron(super::bootstrap_byron_pparams(&genesis.byron)); + + if let Some(force_protocol) = genesis.force_protocol { + for next_protocol in 1..=force_protocol { + pparams = super::migrate_pparams(pparams, genesis, next_protocol); + + debug!(protocol = next_protocol, "forced hardfork"); + } + } + Self { past: vec![], - current: Some(EraSummary { + edge: Some(EraSummary { start: EraBoundary { epoch: 0, slot: 0, - timestamp: initial_pparams.system_start(), + timestamp: pparams.system_start(), }, end: None, - protocol_version: initial_pparams.protocol_version(), - epoch_length: initial_pparams.epoch_length(), - slot_length: initial_pparams.slot_length(), + pparams, }), } } - pub fn advance(&mut self, end_epoch: u64, pparams: &MultiEraProtocolParameters) { - let mut current = self.current.take().unwrap(); - let epoch_delta = end_epoch - current.start.epoch; + pub fn apply_update(&mut self, update: &MultiEraUpdate, genesis: &Genesis) { + let apply_epoch = update.epoch() + 1; + + assert!( + apply_epoch >= self.edge().start.epoch, + "can't apply update for past era" + ); + + let mut pparams = super::apply_param_update(self.edge().pparams.clone(), update); + + let next_version = pparams.protocol_version(); + + if next_version > self.edge().pparams.protocol_version() { + pparams = super::migrate_pparams(pparams, genesis, next_version); + debug!(protocol = next_version, "hardfork executed"); + } + + self.advance(apply_epoch, pparams); + } + + pub fn advance(&mut self, at_epoch: u64, pparams: MultiEraProtocolParameters) { + let mut edge = self.edge.take().unwrap(); + let epoch_delta = at_epoch - edge.start.epoch; - let slot_delta = epoch_delta * current.epoch_length; - let end_slot = current.start.slot + slot_delta; - let second_delta = slot_delta * current.slot_length; - let end_timestamp = - current.start.timestamp + chrono::Duration::seconds(second_delta as i64); + let slot_delta = epoch_delta * edge.pparams.epoch_length(); + let end_slot = edge.start.slot + slot_delta; + let second_delta = slot_delta * edge.pparams.slot_length(); + let end_timestamp = edge.start.timestamp + chrono::Duration::seconds(second_delta as i64); let boundary = EraBoundary { - epoch: end_epoch, + epoch: at_epoch, slot: end_slot, timestamp: end_timestamp, }; - let next_protocol = current.protocol_version + 1; - - current.end = Some(boundary.clone()); - self.past.push(current); + edge.end = Some(boundary.clone()); + self.past.push(edge); - self.current = Some(EraSummary { + self.edge = Some(EraSummary { start: boundary.clone(), end: None, - protocol_version: next_protocol, - epoch_length: pparams.epoch_length(), - slot_length: pparams.slot_length(), + pparams, }); } - pub fn current(&self) -> &EraSummary { + /// Return the edge era + /// + /// The edge era represent the last era in chronological order that we know + /// about. This generally represents the current era except when the + /// chain has already received a hardfork update that is going to be applied + /// in the next epoch. + pub fn edge(&self) -> &EraSummary { // safe to unwrap since it's a business invariant - self.current.as_ref().unwrap() + self.edge.as_ref().unwrap() + } + + /// Return the era for a given epoch + /// + /// This method will scan the different eras looking for one that includes + /// the given epoch. + pub fn era_for_epoch(&self, epoch: u64) -> &EraSummary { + if epoch >= self.edge().start.epoch { + return self.edge(); + } + + self.past + .iter() + .find(|e| epoch >= e.start.epoch && e.end.as_ref().unwrap().epoch > epoch) + .unwrap() + } + + /// Return the era for a given slot + /// + /// This method will scan the different eras looking for one that includes + /// the given slot. + pub fn era_for_slot(&self, slot: u64) -> &EraSummary { + if slot >= self.edge().start.slot { + return self.edge(); + } + + self.past + .iter() + .find(|e| slot >= e.start.slot && e.end.as_ref().unwrap().slot > slot) + .unwrap() } } diff --git a/src/mempool.rs b/src/mempool.rs index d9f5085..6ce0b7b 100644 --- a/src/mempool.rs +++ b/src/mempool.rs @@ -6,14 +6,19 @@ use crate::{ use futures_util::StreamExt; use itertools::Itertools; use pallas::{ - applying::{utils::AccountState, validate_tx, CertState, Environment, UTxOs}, - crypto::hash::Hash, ledger::{primitives::TransactionInput, - traverse::{wellknown::GenesisValues, MultiEraBlock, MultiEraInput, MultiEraOutput, MultiEraTx}} + applying::{utils::AccountState, validate_tx, CertState, Environment, UTxOs}, + crypto::hash::Hash, + ledger::{ + primitives::TransactionInput, + traverse::{ + wellknown::GenesisValues, MultiEraBlock, MultiEraInput, MultiEraOutput, MultiEraTx, + }, + }, }; use std::{ - borrow::Cow, - collections::{HashMap, HashSet}, - sync::{Arc, RwLock} + borrow::Cow, + collections::{HashMap, HashSet}, + sync::{Arc, RwLock}, }; use thiserror::Error; use tokio::sync::broadcast; @@ -127,25 +132,26 @@ impl Mempool { pub fn validate(&self, tx: &MultiEraTx) -> Result<(), MempoolError> { let tip = self.ledger.cursor()?; - let updates: Vec<_> = self + let updates: Vec<_> = self .ledger .get_pparams(tip.as_ref().map(|p| p.0).unwrap_or_default())?; let updates: Vec<_> = updates.into_iter().map(TryInto::try_into).try_collect()?; - let (pparams, _) = crate::ledger::pparams::fold(&self.genesis, &updates); + let eras = crate::ledger::pparams::fold(&self.genesis, &updates); + + let era = eras.era_for_slot(tip.as_ref().unwrap().0); let network_magic = self.genesis.shelley.network_magic.unwrap(); let genesis_values = GenesisValues::from_magic(network_magic.into()).unwrap(); - + let env = Environment { - prot_params: pparams, + prot_params: era.pparams.clone(), prot_magic: self.genesis.shelley.network_magic.unwrap(), block_slot: tip.unwrap().0, network_id: genesis_values.network_id as u8, acnt: Some(AccountState::default()), - }; let input_refs = tx.requires().iter().map(From::from).collect(); @@ -159,14 +165,16 @@ impl Mempool { transaction_id: txoref.0, index: txoref.1.into(), }; - let input = MultiEraInput::AlonzoCompatible(>>::from(Cow::Owned(tx_in))); + let input = MultiEraInput::AlonzoCompatible(>>::from( + Cow::Owned(tx_in), + )); let output = MultiEraOutput::try_from(eracbor)?; pallas_utxos.insert(input, output); } - + validate_tx(tx, 0, &env, &pallas_utxos, &mut CertState::default())?; - Ok(()) + Ok(()) } #[cfg(feature = "phase2")] @@ -179,25 +187,19 @@ impl Mempool { let updates: Vec<_> = updates.into_iter().map(TryInto::try_into).try_collect()?; - let (pparams, eras) = crate::ledger::pparams::fold(&self.genesis, &updates); + let eras = crate::ledger::pparams::fold(&self.genesis, &updates); let slot_config = SlotConfig { - slot_length: eras.current().slot_length, - zero_slot: eras.current().start.slot, - zero_time: eras - .current() - .start - .timestamp - .timestamp() - .try_into() - .unwrap(), + slot_length: eras.edge().pparams.slot_length(), + zero_slot: eras.edge().start.slot, + zero_time: eras.edge().start.timestamp.timestamp().try_into().unwrap(), }; let input_refs = tx.requires().iter().map(From::from).collect(); let utxos = self.ledger.get_utxos(input_refs)?; - let report = tx::eval_tx(tx, &pparams, &utxos, &slot_config)?; + let report = tx::eval_tx(tx, &eras.edge().pparams, &utxos, &slot_config)?; Ok(report) } diff --git a/src/serve/grpc/mod.rs b/src/serve/grpc/mod.rs index 8b63d15..0b83ac9 100644 --- a/src/serve/grpc/mod.rs +++ b/src/serve/grpc/mod.rs @@ -56,7 +56,7 @@ pub async fn serve( .register_encoded_file_descriptor_set(u5c::submit::FILE_DESCRIPTOR_SET) .register_encoded_file_descriptor_set(u5c::watch::FILE_DESCRIPTOR_SET) .register_encoded_file_descriptor_set(protoc_wkt::google::protobuf::FILE_DESCRIPTOR_SET) - .build_v1() + .build_v1alpha() .unwrap(); let cors_layer = if config.permissive_cors.unwrap_or_default() { diff --git a/src/serve/grpc/query.rs b/src/serve/grpc/query.rs index fc890e5..a7c51c2 100644 --- a/src/serve/grpc/query.rs +++ b/src/serve/grpc/query.rs @@ -203,7 +203,7 @@ fn into_u5c_utxo( mapper: &interop::Mapper, ) -> Result { let parsed = MultiEraOutput::try_from(body)?; - let parsed = mapper.map_tx_output(&parsed); + let parsed = mapper.map_tx_output(&parsed, None); Ok(u5c::query::AnyUtxoData { txo_ref: Some(u5c::query::TxoRef { @@ -237,12 +237,14 @@ impl u5c::query::query_service_server::QueryService for QueryServiceImpl { .try_collect::<_, _, pallas::codec::minicbor::decode::Error>() .map_err(|e| Status::internal(e.to_string()))?; - let (pparams, _) = pparams::fold(&self.genesis, &updates); + let summary = pparams::fold(&self.genesis, &updates); + + let era = summary.era_for_slot(tip.as_ref().unwrap().0); let mut response = u5c::query::ReadParamsResponse { values: Some(u5c::query::AnyChainParams { params: u5c::query::any_chain_params::Params::Cardano( - self.mapper.map_pparams(pparams), + self.mapper.map_pparams(era.pparams.clone()), ) .into(), }),