From fe8c1c9164580accbdbb86a4a79b7b828db2078d Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 21 Oct 2025 21:31:11 -0700 Subject: [PATCH 1/4] ### Description Resolves issue #163 This adds `NetworkId` into the `BlockInfo` struct, and introduces this identifier into the account state, drep state, epochs state and rest_blockfrost as these all rely on querying the `StakeAddressMap`. --- common/src/address.rs | 37 +++++--------- common/src/stake_addresses.rs | 2 +- common/src/types.rs | 17 ++++++- modules/accounts_state/src/snapshot.rs | 6 +-- modules/accounts_state/src/state.rs | 28 ++++++----- modules/drep_state/src/state.rs | 7 +-- modules/epochs_state/src/epochs_history.rs | 3 +- modules/epochs_state/src/state.rs | 5 +- .../src/genesis_bootstrapper.rs | 5 +- .../src/alonzo_babbage_voting.rs | 3 +- .../src/mithril_snapshot_fetcher.rs | 10 +++- .../src/handlers/governance.rs | 23 ++++++--- modules/rest_blockfrost/src/handlers/pools.rs | 2 +- .../rest_blockfrost/src/handlers_config.rs | 10 ++++ modules/spo_state/src/state.rs | 49 +++++++++++++------ modules/spo_state/src/test_utils.rs | 10 ++-- modules/stake_delta_filter/src/utils.rs | 6 ++- .../src/body_fetcher.rs | 7 ++- .../src/upstream_cache.rs | 6 +-- modules/upstream_chain_fetcher/src/utils.rs | 13 +++-- modules/utxo_state/src/state.rs | 3 +- processes/golden_tests/src/test_module.rs | 13 ++--- processes/omnibus/omnibus.toml | 3 ++ 23 files changed, 164 insertions(+), 104 deletions(-) diff --git a/common/src/address.rs b/common/src/address.rs index 225a148e..837a3bd8 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -4,12 +4,10 @@ use crate::cip19::{VarIntDecoder, VarIntEncoder}; use crate::types::{KeyHash, ScriptHash}; -use crate::Credential; +use crate::{Credential, NetworkId}; use anyhow::{anyhow, bail, Result}; use serde_with::{hex::Hex, serde_as}; -use std::borrow::Borrow; use std::fmt::{Display, Formatter}; -use std::hash::{Hash, Hasher}; /// a Byron-era address #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -28,6 +26,15 @@ pub enum AddressNetwork { Test, } +impl From for AddressNetwork { + fn from(network: NetworkId) -> Self { + match network { + NetworkId::Mainnet => Self::Main, + NetworkId::Testnet => Self::Test, + } + } +} + impl Default for AddressNetwork { fn default() -> Self { Self::Main @@ -201,7 +208,7 @@ impl StakeAddressPayload { } /// A stake address -#[derive(Debug, Clone, Eq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct StakeAddress { /// Network id pub network: AddressNetwork, @@ -211,7 +218,7 @@ pub struct StakeAddress { } impl StakeAddress { - pub fn new(network: AddressNetwork, payload: StakeAddressPayload) -> Self { + pub fn new(payload: StakeAddressPayload, network: AddressNetwork) -> Self { StakeAddress { network, payload } } @@ -305,26 +312,6 @@ impl Display for StakeAddress { } } -impl Hash for StakeAddress { - fn hash(&self, state: &mut H) { - self.network.hash(state); - std::mem::discriminant(&self.payload).hash(state); - self.get_hash().hash(state); - } -} - -impl Borrow<[u8]> for StakeAddress { - fn borrow(&self) -> &[u8] { - self.get_hash() - } -} - -impl PartialEq for StakeAddress { - fn eq(&self, other: &Self) -> bool { - self.network == other.network && self.payload == other.payload - } -} - impl minicbor::Encode for StakeAddress { fn encode( &self, diff --git a/common/src/stake_addresses.rs b/common/src/stake_addresses.rs index 945aac4b..2189fc03 100644 --- a/common/src/stake_addresses.rs +++ b/common/src/stake_addresses.rs @@ -528,10 +528,10 @@ mod tests { fn create_stake_address(hash: &[u8]) -> StakeAddress { StakeAddress::new( - AddressNetwork::Main, StakeAddressPayload::StakeKeyHash( hash.to_vec().try_into().expect("Invalid hash length"), ), + AddressNetwork::Main, ) } diff --git a/common/src/types.rs b/common/src/types.rs index c0cb1aa6..3f31598c 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -26,6 +26,16 @@ pub enum NetworkId { Mainnet, } +impl From for NetworkId { + fn from(s: String) -> Self { + match s.as_str() { + "testnet" => NetworkId::Testnet, + "mainnet" => NetworkId::Mainnet, + _ => NetworkId::Mainnet, + } + } +} + /// Protocol era #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, @@ -120,6 +130,9 @@ pub struct BlockInfo { #[serde(default)] pub timestamp: u64, + /// Network ID + pub network_id: NetworkId, + /// Protocol era pub era: Era, } @@ -614,7 +627,7 @@ impl Credential { pub type StakeCredential = Credential; impl StakeCredential { - pub fn to_stake_address(&self, network: Option) -> StakeAddress { + pub fn to_stake_address(&self, network: AddressNetwork) -> StakeAddress { let payload = match self { StakeCredential::AddrKeyHash(hash) => StakeAddressPayload::StakeKeyHash( hash.clone().try_into().expect("Invalid hash length"), @@ -623,7 +636,7 @@ impl StakeCredential { hash.clone().try_into().expect("Invalid hash length"), ), }; - StakeAddress::new(network.unwrap_or(AddressNetwork::Main), payload) + StakeAddress::new(payload, network) } } diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index c4720d3c..b9ecfe1b 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -165,12 +165,12 @@ impl Snapshot { return 0; }; - let addr_set: std::collections::HashSet<_> = addresses.iter().collect(); + let address_set: std::collections::HashSet<_> = addresses.iter().collect(); snapshot_spo .delegators .iter() - .filter_map(|(addr, amount)| { - if addr_set.contains(&addr.get_credential()) { + .filter_map(|(address, amount)| { + if address_set.contains(&address.get_credential()) { Some(*amount) } else { None diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index b4a9dad3..086035fa 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -14,9 +14,9 @@ use acropolis_common::{ protocol_params::ProtocolParams, stake_addresses::{StakeAddressMap, StakeAddressState}, BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, - InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolLiveStakeInfo, - PoolRegistration, Pot, SPORewards, StakeAddress, StakeCredential, StakeRewardDelta, - TxCertificate, + InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, NetworkId, + PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeCredential, + StakeRewardDelta, TxCertificate, }; use anyhow::Result; use imbl::OrdMap; @@ -95,6 +95,9 @@ pub struct State { /// List of SPOs (by operator ID) retiring in the current epoch retiring_spos: Vec, + /// Network ID + network_id: NetworkId, + /// Map of staking address values /// Wrapped in an Arc so it doesn't get cloned in full by StateHistory stake_addresses: Arc>, @@ -550,7 +553,8 @@ impl State { // Transfer to (in theory also from) stake addresses from (to) a pot let mut total_value: u64 = 0; for (credential, value) in deltas.iter() { - let stake_address = credential.to_stake_address(None); // Need to convert credential to address + let stake_address = + credential.to_stake_address(self.network_id.clone().into()); // Get old stake address state, or create one let mut stake_addresses = self.stake_addresses.lock().unwrap(); @@ -792,8 +796,8 @@ impl State { /// Register a stake address, with a specified deposit if known fn register_stake_address(&mut self, credential: &StakeCredential, deposit: Option) { - // TODO: Handle network - let stake_address = credential.to_stake_address(None); + + let stake_address = credential.to_stake_address(self.network_id.clone().into()); // Stake addresses can be registered after being used in UTXOs let mut stake_addresses = self.stake_addresses.lock().unwrap(); @@ -823,8 +827,8 @@ impl State { /// Deregister a stake address, with specified refund if known fn deregister_stake_address(&mut self, credential: &StakeCredential, refund: Option) { - // TODO: Handle network - let stake_address = credential.to_stake_address(None); + + let stake_address = credential.to_stake_address(self.network_id.clone().into()); // Check if it existed let mut stake_addresses = self.stake_addresses.lock().unwrap(); @@ -860,8 +864,8 @@ impl State { /// Record a stake delegation fn record_stake_delegation(&mut self, credential: &StakeCredential, spo: &KeyHash) { - // TODO: Handle network - let stake_address = credential.to_stake_address(None); + + let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.record_stake_delegation(&stake_address, spo); } @@ -874,8 +878,8 @@ impl State { /// record a drep delegation fn record_drep_delegation(&mut self, credential: &StakeCredential, drep: &DRepChoice) { - // TODO: Handle network - let stake_address = credential.to_stake_address(None); + + let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.record_drep_delegation(&stake_address, drep); } diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index 89fe9a5c..7a2c7296 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -4,7 +4,7 @@ use acropolis_common::{messages::{Message, StateQuery, StateQueryResponse}, quer accounts::{AccountsStateQuery, AccountsStateQueryResponse, DEFAULT_ACCOUNTS_QUERY_TOPIC}, get_query_topic, governance::{DRepActionUpdate, DRepUpdateEvent, VoteRecord}, -}, Anchor, Credential, DRepChoice, DRepCredential, KeyHash, Lovelace, StakeAddress, StakeCredential, TxCertificate, TxHash, Voter, VotingProcedures}; +}, Anchor, Credential, DRepChoice, DRepCredential, KeyHash, Lovelace, NetworkId, StakeAddress, StakeCredential, TxCertificate, TxHash, Voter, VotingProcedures}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; use serde_with::serde_as; @@ -89,6 +89,7 @@ impl DRepStorageConfig { pub struct State { pub config: DRepStorageConfig, pub dreps: HashMap, + pub network_id: NetworkId, pub historical_dreps: Option>, } @@ -97,6 +98,7 @@ impl State { Self { config, dreps: HashMap::new(), + network_id: NetworkId::default(), historical_dreps: if config.any_enabled() { Some(HashMap::new()) } else { @@ -470,8 +472,7 @@ impl State { delegators: Vec<(&StakeCredential, &DRepChoice)>, ) -> Result<()> { let stake_keys: Vec = delegators.iter().map(|(sc, _)| sc.get_hash()).collect(); - // TODO: USE NETWORK ID - let stake_addresses: Vec = delegators.iter().map(|(k, _) | k.to_stake_address(None) ).collect(); + let stake_addresses: Vec = delegators.iter().map(|(k, _) | k.to_stake_address(self.network_id.clone().into()) ).collect(); let stake_key_to_input: HashMap = delegators .iter() .zip(&stake_keys) diff --git a/modules/epochs_state/src/epochs_history.rs b/modules/epochs_state/src/epochs_history.rs index dc37b56a..145a309b 100644 --- a/modules/epochs_state/src/epochs_history.rs +++ b/modules/epochs_state/src/epochs_history.rs @@ -78,7 +78,7 @@ impl EpochsHistoryState { #[cfg(test)] mod tests { use super::*; - use acropolis_common::{BlockHash, BlockStatus, Era}; + use acropolis_common::{BlockHash, BlockStatus, Era, NetworkId}; fn make_block(epoch: u64) -> BlockInfo { BlockInfo { @@ -89,6 +89,7 @@ mod tests { epoch, epoch_slot: 99, new_epoch: false, + network_id: NetworkId::default(), timestamp: 99999, era: Era::Conway, } diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 0a46c07a..6fbd40f3 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -269,7 +269,7 @@ mod tests { crypto::keyhash_224, protocol_params::{Nonce, NonceHash}, state_history::{StateHistory, StateHistoryStore}, - BlockHash, BlockInfo, BlockStatus, Era, + BlockHash, BlockInfo, BlockStatus, Era, NetworkId, }; use tokio::sync::Mutex; @@ -281,6 +281,7 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, + network_id: NetworkId::default(), new_epoch: false, timestamp: 99999, era: Era::Shelley, @@ -295,6 +296,7 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, + network_id: NetworkId::default(), new_epoch: true, timestamp: 99999, era: Era::Shelley, @@ -309,6 +311,7 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, + network_id: NetworkId::default(), new_epoch: false, timestamp: 99999, era: Era::Conway, diff --git a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs index b256954c..54e7a224 100644 --- a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs +++ b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs @@ -7,8 +7,8 @@ use acropolis_common::{ CardanoMessage, GenesisCompleteMessage, GenesisUTxOsMessage, Message, PotDeltasMessage, UTXODeltasMessage, }, - Address, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, Lovelace, LovelaceDelta, Pot, - PotDelta, TxIdentifier, TxOutRef, TxOutput, UTXODelta, UTxOIdentifier, Value, + Address, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, Lovelace, LovelaceDelta, + NetworkId, Pot, PotDelta, TxIdentifier, TxOutRef, TxOutput, UTXODelta, UTxOIdentifier, Value, }; use anyhow::Result; use blake2::{digest::consts::U32, Blake2b, Digest}; @@ -128,6 +128,7 @@ impl GenesisBootstrapper { hash: BlockHash::default(), epoch: 0, epoch_slot: 0, + network_id: NetworkId::from(network_name), new_epoch: false, timestamp: byron_genesis.start_time, era: Era::Byron, diff --git a/modules/governance_state/src/alonzo_babbage_voting.rs b/modules/governance_state/src/alonzo_babbage_voting.rs index bc90a45b..b20a403c 100644 --- a/modules/governance_state/src/alonzo_babbage_voting.rs +++ b/modules/governance_state/src/alonzo_babbage_voting.rs @@ -113,7 +113,7 @@ mod tests { use crate::alonzo_babbage_voting::AlonzoBabbageVoting; use acropolis_common::{ rational_number::rational_number_from_f32, AlonzoBabbageUpdateProposal, - AlonzoBabbageVotingOutcome, BlockHash, BlockInfo, BlockStatus, GenesisKeyhash, + AlonzoBabbageVotingOutcome, BlockHash, BlockInfo, BlockStatus, GenesisKeyhash, NetworkId, ProtocolParamUpdate, }; use anyhow::Result; @@ -154,6 +154,7 @@ mod tests { epoch, epoch_slot: 0, era: era.try_into()?, + network_id: NetworkId::default(), new_epoch: new_epoch != 0, timestamp: 0, hash: BlockHash::default(), diff --git a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs index 20804f2f..7e6fafe7 100644 --- a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs +++ b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs @@ -4,7 +4,7 @@ use acropolis_common::{ genesis_values::GenesisValues, messages::{BlockBodyMessage, BlockHeaderMessage, CardanoMessage, Message}, - BlockInfo, BlockStatus, Era, + BlockInfo, BlockStatus, Era, NetworkId, }; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::{module, Context, Module}; @@ -45,6 +45,7 @@ const DEFAULT_PAUSE: (&str, PauseType) = ("pause", PauseType::NoPause); const DEFAULT_DOWNLOAD_MAX_AGE: &str = "download-max-age"; const DEFAULT_DIRECTORY: &str = "downloads"; const SNAPSHOT_METADATA_FILE: &str = "snapshot_metadata.json"; +const DEFAULT_NETWORK_ID: &str = "mainnet"; /// Mithril feedback receiver struct FeedbackLogger { @@ -307,6 +308,12 @@ impl MithrilSnapshotFetcher { let timestamp = genesis.slot_to_timestamp(slot); + let network_id = NetworkId::from( + config + .get_string("network-id") + .unwrap_or(DEFAULT_NETWORK_ID.to_string()), + ); + let era = match block.era() { PallasEra::Byron => Era::Byron, PallasEra::Shelley => Era::Shelley, @@ -328,6 +335,7 @@ impl MithrilSnapshotFetcher { epoch, epoch_slot, new_epoch, + network_id, timestamp, era, }; diff --git a/modules/rest_blockfrost/src/handlers/governance.rs b/modules/rest_blockfrost/src/handlers/governance.rs index 0563ddc8..5d0ef2d6 100644 --- a/modules/rest_blockfrost/src/handlers/governance.rs +++ b/modules/rest_blockfrost/src/handlers/governance.rs @@ -4,10 +4,14 @@ use crate::types::{ DRepInfoREST, DRepMetadataREST, DRepUpdateREST, DRepVoteREST, DRepsListREST, ProposalVoteREST, VoterRoleREST, }; -use acropolis_common::{messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse}, - governance::{GovernanceStateQuery, GovernanceStateQueryResponse}, -}, Credential, GovActionId, StakeAddress, TxHash, Voter}; +use acropolis_common::{ + messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, + queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse}, + governance::{GovernanceStateQuery, GovernanceStateQueryResponse}, + }, + Credential, GovActionId, StakeAddress, TxHash, Voter, +}; use anyhow::Result; use caryatid_sdk::Context; use reqwest::Client; @@ -95,8 +99,11 @@ pub async fn handle_single_drep_blockfrost( )) => { let active = !response.info.retired && !response.info.expired; - let stake_addresses = - response.delegators.iter().map(|addr| addr.to_stake_address(None)).collect(); + let stake_addresses = response + .delegators + .iter() + .map(|addr| addr.to_stake_address(handlers_config.network_id.clone().into())) + .collect(); let sum_msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsBalancesSum { stake_addresses }, @@ -203,8 +210,8 @@ pub async fn handle_drep_delegators_blockfrost( }; let hash = addr.get_hash(); - // TODO: NETWORK ID - let stake_address = addr.to_stake_address(None); + let stake_address = + addr.to_stake_address(handlers_config.network_id.clone().into()); stake_addresses.push(stake_address.clone()); stake_key_to_bech32.insert(hash, bech32); } diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index eaa27403..bad519a4 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -667,7 +667,7 @@ async fn handle_pools_spo_blockfrost( stake_addresses: pool_info .pool_owners .iter() - .map(|owner| owner.to_stake_address(None)) + .map(|owner| owner.to_stake_address(handlers_config.network_id.clone().into())) .collect(), }, ))); diff --git a/modules/rest_blockfrost/src/handlers_config.rs b/modules/rest_blockfrost/src/handlers_config.rs index 53ea6b79..0dbf22fc 100644 --- a/modules/rest_blockfrost/src/handlers_config.rs +++ b/modules/rest_blockfrost/src/handlers_config.rs @@ -9,10 +9,13 @@ use acropolis_common::queries::{ pools::DEFAULT_POOLS_QUERY_TOPIC, spdd::DEFAULT_SPDD_QUERY_TOPIC, }; +use acropolis_common::NetworkId; use config::Config; const DEFAULT_EXTERNAL_API_TIMEOUT: (&str, i64) = ("external_api_timeout", 3); // 3 seconds +const DEFAULT_NETWORK_ID: (&str, &str) = ("network", "mainnet"); + #[derive(Clone)] pub struct HandlersConfig { pub accounts_query_topic: String, @@ -25,6 +28,7 @@ pub struct HandlersConfig { pub parameters_query_topic: String, pub external_api_timeout: u64, pub offchain_token_registry_url: String, + pub network_id: NetworkId, } impl From> for HandlersConfig { @@ -69,6 +73,11 @@ impl From> for HandlersConfig { .get_string(DEFAULT_OFFCHAIN_TOKEN_REGISTRY_URL.0) .unwrap_or(DEFAULT_OFFCHAIN_TOKEN_REGISTRY_URL.1.to_string()); + let network_id = config + .get_string(DEFAULT_NETWORK_ID.0) + .unwrap_or(DEFAULT_NETWORK_ID.1.to_string()) + .into(); + Self { accounts_query_topic, assets_query_topic, @@ -80,6 +89,7 @@ impl From> for HandlersConfig { parameters_query_topic, external_api_timeout, offchain_token_registry_url, + network_id, } } } diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 059ff70b..de8a2c05 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -1,9 +1,19 @@ //! Acropolis SPOState: State storage -use acropolis_common::{crypto::keyhash_224, ledger_state::SPOState, messages::{ - CardanoMessage, Message, SPOStateMessage, StakeAddressDeltasMessage, - StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, -}, params::TECHNICAL_PARAMETER_POOL_RETIRE_MAX_EPOCH, queries::governance::VoteRecord, stake_addresses::StakeAddressMap, BlockInfo, KeyHash, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, StakeCredential, TxCertificate, TxHash, Voter, VotingProcedures}; +use acropolis_common::{ + crypto::keyhash_224, + ledger_state::SPOState, + messages::{ + CardanoMessage, Message, SPOStateMessage, StakeAddressDeltasMessage, + StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, + }, + params::TECHNICAL_PARAMETER_POOL_RETIRE_MAX_EPOCH, + queries::governance::VoteRecord, + stake_addresses::StakeAddressMap, + BlockInfo, KeyHash, NetworkId, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, + PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, StakeCredential, + TxCertificate, TxHash, Voter, VotingProcedures, +}; use anyhow::Result; use imbl::HashMap; use std::sync::{Arc, Mutex}; @@ -20,6 +30,8 @@ pub struct State { epoch: u64, + network_id: NetworkId, + spos: HashMap, PoolRegistration>, pending_updates: HashMap, PoolRegistration>, @@ -48,6 +60,7 @@ impl State { pending_updates: HashMap::new(), pending_deregistrations: HashMap::new(), total_blocks_minted: HashMap::new(), + network_id: NetworkId::default(), historical_spos: if config.store_historical_state() { Some(HashMap::new()) } else { @@ -98,6 +111,7 @@ impl From for State { store_config: StoreConfig::default(), block: 0, epoch: 0, + network_id: NetworkId::default(), spos, pending_updates: value.updates.into(), pending_deregistrations, @@ -432,16 +446,18 @@ impl State { return; }; let mut stake_addresses = stake_addresses.lock().unwrap(); - stake_addresses.register_stake_address(&credential.to_stake_address(None)); + stake_addresses + .register_stake_address(&credential.to_stake_address(self.network_id.clone().into())); } fn deregister_stake_address(&mut self, credential: &StakeCredential) { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return; }; - let stake_address = credential.to_stake_address(None); + let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = stake_addresses.lock().unwrap(); - let old_spo = stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); + let old_spo = + stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); if stake_addresses.deregister_stake_address(&stake_address) { // update historical_spos @@ -449,7 +465,9 @@ impl State { if let Some(old_spo) = old_spo.as_ref() { // remove delegators from old_spo if let Some(historical_spo) = historical_spos.get_mut(old_spo) { - if let Some(removed) = historical_spo.remove_delegator(&credential.to_stake_address(None)) { + if let Some(removed) = historical_spo.remove_delegator( + &credential.to_stake_address(self.network_id.clone().into()), + ) { if !removed { error!( "Historical SPO state for {} does not contain delegator {}", @@ -471,9 +489,10 @@ impl State { return; }; let hash = credential.get_hash(); - let stake_address = credential.to_stake_address(None); + let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = stake_addresses.lock().unwrap(); - let old_spo = stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); + let old_spo = + stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); if stake_addresses.record_stake_delegation(&stake_address, spo) { // update historical_spos @@ -653,7 +672,10 @@ impl State { for delta in reward_deltas_msg.deltas.iter() { let mut stake_addresses = stake_addresses.lock().unwrap(); if let Err(e) = stake_addresses.update_reward(&delta.stake_address, delta.delta) { - error!("Updating reward account {}: {e}", hex::encode(&delta.stake_address.get_hash())); + error!( + "Updating reward account {}: {e}", + hex::encode(&delta.stake_address.get_hash()) + ); } } @@ -677,10 +699,7 @@ mod tests { use tokio::sync::Mutex; fn pool_owners_from_bytes(owners: Vec>) -> Vec { - owners - .into_iter() - .map(|bytes| Credential::AddrKeyHash(bytes)) - .collect() + owners.into_iter().map(|bytes| Credential::AddrKeyHash(bytes)).collect() } fn default_pool_registration(operator: Vec) -> PoolRegistration { diff --git a/modules/spo_state/src/test_utils.rs b/modules/spo_state/src/test_utils.rs index 2e8772d8..92be798f 100644 --- a/modules/spo_state/src/test_utils.rs +++ b/modules/spo_state/src/test_utils.rs @@ -1,9 +1,6 @@ -use acropolis_common::{ - messages::{ - EpochActivityMessage, SPORewardsMessage, SPOStakeDistributionMessage, TxCertificatesMessage, - }, - BlockHash, BlockInfo, BlockStatus, Era, TxCertificate, -}; +use acropolis_common::{messages::{ + EpochActivityMessage, SPORewardsMessage, SPOStakeDistributionMessage, TxCertificatesMessage, +}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId, TxCertificate}; use crate::store_config::StoreConfig; @@ -68,6 +65,7 @@ pub fn new_block(epoch: u64) -> BlockInfo { epoch, epoch_slot: 0, new_epoch: true, + network_id: NetworkId::default(), timestamp: epoch, era: Era::Byron, } diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 334df1cd..7ce5b96e 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -401,8 +401,9 @@ mod test { use crate::*; use acropolis_common::{ messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, - ByronAddress, Era, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, - ShelleyAddressPointer, StakeAddress, StakeAddressPayload, ValueDelta, + ByronAddress, Era, NetworkId, ShelleyAddress, ShelleyAddressDelegationPart, + ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeAddressPayload, + ValueDelta, }; use bech32::{Bech32, Hrp}; @@ -541,6 +542,7 @@ mod test { epoch: 1, epoch_slot: 14243, new_epoch: true, + network_id: NetworkId::default(), timestamp: 2498243, era: Era::Conway, }; diff --git a/modules/upstream_chain_fetcher/src/body_fetcher.rs b/modules/upstream_chain_fetcher/src/body_fetcher.rs index afa2a5ee..21a2ed95 100644 --- a/modules/upstream_chain_fetcher/src/body_fetcher.rs +++ b/modules/upstream_chain_fetcher/src/body_fetcher.rs @@ -1,10 +1,7 @@ //! Acropolis Miniprotocols module for Caryatid //! Multi-connection, block body fetching part of the client (in separate thread). -use acropolis_common::{ - messages::{BlockBodyMessage, BlockHeaderMessage}, - BlockInfo, BlockStatus, Era, -}; +use acropolis_common::{messages::{BlockBodyMessage, BlockHeaderMessage}, BlockInfo, BlockStatus, Era, NetworkId}; use anyhow::{bail, Result}; use crossbeam::channel::{Receiver, TryRecvError}; use pallas::{ @@ -111,6 +108,7 @@ impl BodyFetcher { None => true, }; let timestamp = self.cfg.slot_to_timestamp(slot); + let network_id = NetworkId::from(self.cfg.network_id.clone()); Ok(BlockInfo { status: if rolled_back { @@ -123,6 +121,7 @@ impl BodyFetcher { hash, epoch, epoch_slot, + network_id, new_epoch, timestamp, era, diff --git a/modules/upstream_chain_fetcher/src/upstream_cache.rs b/modules/upstream_chain_fetcher/src/upstream_cache.rs index 9281a358..8be89694 100644 --- a/modules/upstream_chain_fetcher/src/upstream_cache.rs +++ b/modules/upstream_chain_fetcher/src/upstream_cache.rs @@ -170,10 +170,7 @@ impl Storage for FileStorage { #[cfg(test)] mod test { use crate::upstream_cache::{Storage, UpstreamCacheImpl, UpstreamCacheRecord}; - use acropolis_common::{ - messages::{BlockBodyMessage, BlockHeaderMessage}, - BlockHash, BlockInfo, BlockStatus, Era, - }; + use acropolis_common::{messages::{BlockBodyMessage, BlockHeaderMessage}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId}; use anyhow::Result; use std::{collections::HashMap, sync::Arc}; @@ -186,6 +183,7 @@ mod test { epoch: 0, epoch_slot: n, new_epoch: false, + network_id: NetworkId::default(), timestamp: n, era: Era::default(), } diff --git a/modules/upstream_chain_fetcher/src/utils.rs b/modules/upstream_chain_fetcher/src/utils.rs index dd3ee50b..1010a695 100644 --- a/modules/upstream_chain_fetcher/src/utils.rs +++ b/modules/upstream_chain_fetcher/src/utils.rs @@ -1,6 +1,7 @@ use crate::UpstreamCacheRecord; use acropolis_common::genesis_values::GenesisValues; use acropolis_common::messages::{CardanoMessage, Message}; +use acropolis_common::NetworkId; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::Context; use config::Config; @@ -19,6 +20,7 @@ const DEFAULT_GENESIS_COMPLETION_TOPIC: (&str, &str) = const DEFAULT_NODE_ADDRESS: (&str, &str) = ("node-address", "backbone.cardano.iog.io:3001"); const DEFAULT_MAGIC_NUMBER: (&str, u64) = ("magic-number", 764824073); +const DEFAULT_NETWORK_ID: (&str, &str) = ("network-id", "mainnet"); const DEFAULT_SYNC_POINT: (&str, SyncPoint) = ("sync-point", SyncPoint::Snapshot); const DEFAULT_CACHE_DIR: (&str, &str) = ("cache-dir", "upstream-cache"); @@ -49,6 +51,7 @@ pub struct FetcherConfig { pub genesis_completion_topic: String, pub node_address: String, pub magic_number: u64, + pub network_id: String, pub cache_dir: String, pub genesis_values: Option, @@ -108,6 +111,9 @@ impl FetcherConfig { magic_number: config .get::(DEFAULT_MAGIC_NUMBER.0) .unwrap_or(DEFAULT_MAGIC_NUMBER.1), + network_id: config + .get_string(DEFAULT_NETWORK_ID.0) + .unwrap_or(DEFAULT_NETWORK_ID.1.to_string()), node_address: Self::conf(&config, DEFAULT_NODE_ADDRESS), cache_dir: Self::conf(&config, DEFAULT_CACHE_DIR), genesis_values: Self::conf_genesis(&config), @@ -140,8 +146,8 @@ pub async fn publish_message(cfg: Arc, record: &UpstreamCacheReco pub async fn peer_connect(cfg: Arc, role: &str) -> Result> { info!( - "Connecting {role} to {} ({}) ...", - cfg.node_address, cfg.magic_number + "Connecting {role} to {} ({})-({}) ...", + cfg.node_address, cfg.network_id, cfg.magic_number ); match PeerClient::connect(cfg.node_address.clone(), cfg.magic_number).await { @@ -156,8 +162,9 @@ pub async fn peer_connect(cfg: Arc, role: &str) -> Result bail!( - "Cannot connect {role} to {} ({}): {e}", + "Cannot connect {role} to {} ({})-({}): {e}", cfg.node_address, + cfg.network_id, cfg.magic_number ), } diff --git a/modules/utxo_state/src/state.rs b/modules/utxo_state/src/state.rs index b3e03d55..0c703a90 100644 --- a/modules/utxo_state/src/state.rs +++ b/modules/utxo_state/src/state.rs @@ -373,7 +373,7 @@ impl State { mod tests { use super::*; use crate::InMemoryImmutableUTXOStore; - use acropolis_common::{AssetName, BlockHash, ByronAddress, Era, NativeAsset, Value}; + use acropolis_common::{AssetName, BlockHash, ByronAddress, Era, NativeAsset, NetworkId, Value}; use config::Config; use tokio::sync::Mutex; @@ -394,6 +394,7 @@ mod tests { epoch_slot: slot, new_epoch: false, timestamp: slot, + network_id: NetworkId::default(), era: Era::Byron, } } diff --git a/processes/golden_tests/src/test_module.rs b/processes/golden_tests/src/test_module.rs index 61377e6b..f12e1ed6 100644 --- a/processes/golden_tests/src/test_module.rs +++ b/processes/golden_tests/src/test_module.rs @@ -1,11 +1,7 @@ -use acropolis_common::{ - ledger_state::LedgerState, - messages::{ - CardanoMessage, Message, RawTxsMessage, SnapshotDumpMessage, SnapshotMessage, - SnapshotStateMessage, - }, - BlockHash, BlockInfo, BlockStatus, Era, -}; +use acropolis_common::{ledger_state::LedgerState, messages::{ + CardanoMessage, Message, RawTxsMessage, SnapshotDumpMessage, SnapshotMessage, + SnapshotStateMessage, +}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId}; use anyhow::{Context as AnyhowContext, Result}; use caryatid_sdk::{module, Context, Module}; use config::Config; @@ -47,6 +43,7 @@ impl TestModule { slot: 1, number: 1, hash: BlockHash::default(), + network_id: NetworkId::default(), epoch: 1, epoch_slot: 1, new_epoch: false, diff --git a/processes/omnibus/omnibus.toml b/processes/omnibus/omnibus.toml index 4fa7998e..6861a9c9 100644 --- a/processes/omnibus/omnibus.toml +++ b/processes/omnibus/omnibus.toml @@ -9,15 +9,18 @@ genesis-key = "5b3139312c36362c3134302c3138352c3133382c31312c3233372c3230372c323 download-max-age = "never" # Pause constraint E.g. "epoch:100", "block:1200" pause = "none" +network = "mainnet" [module.upstream-chain-fetcher] sync-point = "snapshot" node-address = "backbone.cardano.iog.io:3001" magic-number = 764824073 +network = "mainnet" [module.block-unpacker] [module.rest-blockfrost] +network = "mainnet" [module.tx-unpacker] publish-utxo-deltas-topic = "cardano.utxo.deltas" From f8a97b4bd72c06cc18e63d95d2d9145837c71ae8 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 22 Oct 2025 12:51:13 -0700 Subject: [PATCH 2/4] Refactor: Remove `NetworkId` from `BlockInfo` and standardize `StakeAddress` handling in tx_unpacker.rs - Removed `NetworkId` from structures and functions across modules. - Replaced `KeyHash` and `Credential` usage with `StakeAddress` for consistency. --- common/src/queries/governance.rs | 6 +- common/src/state_history.rs | 2 +- common/src/types.rs | 43 +++---- modules/accounts_state/src/rewards.rs | 3 +- modules/accounts_state/src/snapshot.rs | 16 +-- modules/accounts_state/src/state.rs | 114 ++++++++---------- modules/drep_state/src/drep_state.rs | 1 + modules/drep_state/src/state.rs | 60 +++++---- modules/epochs_state/src/epochs_history.rs | 3 +- modules/epochs_state/src/state.rs | 5 +- .../src/genesis_bootstrapper.rs | 5 +- .../src/alonzo_babbage_voting.rs | 3 +- .../src/mithril_snapshot_fetcher.rs | 10 +- .../src/handlers/governance.rs | 46 +++---- modules/rest_blockfrost/src/handlers/pools.rs | 8 +- .../rest_blockfrost/src/handlers_config.rs | 10 -- modules/spo_state/src/state.rs | 74 ++++++------ modules/spo_state/src/test_utils.rs | 3 +- modules/stake_delta_filter/src/state.rs | 15 +-- modules/stake_delta_filter/src/utils.rs | 3 +- modules/tx_unpacker/src/map_parameters.rs | 65 +++++++--- modules/tx_unpacker/src/tx_unpacker.rs | 5 +- .../src/body_fetcher.rs | 4 +- .../src/upstream_cache.rs | 9 +- modules/upstream_chain_fetcher/src/utils.rs | 1 - modules/utxo_state/src/state.rs | 3 +- processes/golden_tests/src/test_module.rs | 3 +- processes/omnibus/omnibus.toml | 4 +- 28 files changed, 247 insertions(+), 277 deletions(-) diff --git a/common/src/queries/governance.rs b/common/src/queries/governance.rs index be6b1240..678b35a9 100644 --- a/common/src/queries/governance.rs +++ b/common/src/queries/governance.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{Anchor, Credential, DRepCredential, GovActionId, Lovelace, ProposalProcedure, TxHash, Vote, Voter, VotingProcedure}; +use crate::{Anchor, DRepCredential, GovActionId, Lovelace, ProposalProcedure, StakeAddress, TxHash, Vote, Voter, VotingProcedure}; pub const DEFAULT_DREPS_QUERY_TOPIC: (&str, &str) = ("drep-state-query-topic", "cardano.query.dreps"); @@ -58,12 +58,12 @@ pub struct DRepInfo { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct DRepInfoWithDelegators { pub info: DRepInfo, - pub delegators: Vec, + pub delegators: Vec, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct DRepDelegatorAddresses { - pub addresses: Vec, + pub addresses: Vec, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/common/src/state_history.rs b/common/src/state_history.rs index 9e19a4c7..c8cf2979 100644 --- a/common/src/state_history.rs +++ b/common/src/state_history.rs @@ -54,7 +54,7 @@ impl StateHistory { /// Get the current state assuming any rollback has been done /// Cloned for modification - call commit() when done - pub fn get_current_state(&self) -> S { + pub fn get_current_state(&self) -> S { self.history.back().map(|entry| entry.state.clone()).unwrap_or_default() } diff --git a/common/src/types.rs b/common/src/types.rs index 3f31598c..592f6204 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -130,9 +130,6 @@ pub struct BlockInfo { #[serde(default)] pub timestamp: u64, - /// Network ID - pub network_id: NetworkId, - /// Protocol era pub era: Era, } @@ -752,7 +749,7 @@ pub struct PoolRegistration { /// Pool owners by their key hash // #[serde_as(as = "Vec")] #[n(6)] - pub pool_owners: Vec, + pub pool_owners: Vec, // Relays #[n(7)] @@ -837,8 +834,8 @@ pub struct PoolEpochState { /// Stake delegation data #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StakeDelegation { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// Pool ID to delegate to pub operator: KeyHash, @@ -907,8 +904,8 @@ pub struct MoveInstantaneousReward { /// Register stake (Conway version) = 'reg_cert' #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Registration { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// Deposit paid pub deposit: Lovelace, @@ -917,8 +914,8 @@ pub struct Registration { /// Deregister stake (Conway version) = 'unreg_cert' #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Deregistration { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// Deposit to be refunded pub refund: Lovelace, @@ -943,8 +940,8 @@ pub enum DRepChoice { /// Vote delegation (simple, existing registration) = vote_deleg_cert #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct VoteDelegation { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, // DRep choice pub drep: DRepChoice, @@ -953,8 +950,8 @@ pub struct VoteDelegation { /// Stake+vote delegation (to SPO and DRep) = stake_vote_deleg_cert #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StakeAndVoteDelegation { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// Pool pub operator: KeyHash, @@ -966,8 +963,8 @@ pub struct StakeAndVoteDelegation { /// Stake delegation to SPO + registration = stake_reg_deleg_cert #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StakeRegistrationAndDelegation { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// Pool pub operator: KeyHash, @@ -979,8 +976,8 @@ pub struct StakeRegistrationAndDelegation { /// Vote delegation to DRep + registration = vote_reg_deleg_cert #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StakeRegistrationAndVoteDelegation { - /// Stake credential - pub credential: StakeCredential, + /// Stake address + pub stake_address: StakeAddress, /// DRep choice pub drep: DRepChoice, @@ -995,7 +992,7 @@ pub struct StakeRegistrationAndVoteDelegation { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StakeRegistrationAndStakeAndVoteDelegation { /// Stake credential - pub credential: StakeCredential, + pub stake_address: StakeAddress, /// Pool pub operator: KeyHash, @@ -1673,8 +1670,8 @@ pub struct GovernanceOutcome { } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct StakeCredentialWithPos { - pub stake_credential: StakeCredential, +pub struct StakeAddressWithPos { + pub stake_address: StakeAddress, pub tx_index: u64, pub cert_index: u64, } @@ -1686,10 +1683,10 @@ pub enum TxCertificate { None(()), /// Stake registration - StakeRegistration(StakeCredentialWithPos), + StakeRegistration(StakeAddressWithPos), /// Stake de-registration - StakeDeregistration(StakeCredential), + StakeDeregistration(StakeAddress), /// Stake Delegation to a pool StakeDelegation(StakeDelegation), diff --git a/modules/accounts_state/src/rewards.rs b/modules/accounts_state/src/rewards.rs index 4b9bd8dd..06528a86 100644 --- a/modules/accounts_state/src/rewards.rs +++ b/modules/accounts_state/src/rewards.rs @@ -335,7 +335,6 @@ fn calculate_spo_rewards( if !to_delegators.is_zero() { let total_stake = BigDecimal::from(spo.total_stake); for (delegator_stake_address, stake) in &spo.delegators { - let delegator_credential = delegator_stake_address.get_credential(); let proportion = BigDecimal::from(stake) / &total_stake; // and hence how much of the total reward they get @@ -346,7 +345,7 @@ fn calculate_spo_rewards( delegator_stake_address); // Pool owners don't get member rewards (seems unfair!) - if spo.pool_owners.contains(&delegator_credential) { + if spo.pool_owners.contains(&delegator_stake_address) { debug!( "Skipping pool owner reward account {}, losing {to_pay}", delegator_stake_address diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index b9ecfe1b..81e09f46 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -1,7 +1,7 @@ //! Acropolis AccountsState: snapshot for rewards calculations use crate::state::{Pots, RegistrationChange}; -use acropolis_common::{stake_addresses::StakeAddressMap, Credential, KeyHash, Lovelace, PoolRegistration, Ratio, StakeAddress}; +use acropolis_common::{stake_addresses::StakeAddressMap, KeyHash, Lovelace, PoolRegistration, Ratio, StakeAddress}; use imbl::OrdMap; use std::collections::HashMap; use std::sync::Arc; @@ -35,7 +35,7 @@ pub struct SnapshotSPO { pub two_previous_reward_account_is_registered: bool, /// Pool owners - pub pool_owners: Vec, + pub pool_owners: Vec, } /// Snapshot of stake distribution taken at the end of an particular epoch @@ -159,7 +159,7 @@ impl Snapshot { pub fn get_stake_delegated_to_spo_by_addresses( &self, spo: &KeyHash, - addresses: &[Credential], + addresses: &[StakeAddress], ) -> Lovelace { let Some(snapshot_spo) = self.spos.get(spo) else { return 0; @@ -170,7 +170,7 @@ impl Snapshot { .delegators .iter() .filter_map(|(address, amount)| { - if address_set.contains(&address.get_credential()) { + if address_set.contains(&address) { Some(*amount) } else { None @@ -321,9 +321,9 @@ mod tests { // Extract key hashes from stake addresses for the API call let addresses = vec![ - addr2.get_credential(), - addr3.get_credential(), - addr4.get_credential(), + addr2, + addr3, + addr4, ]; let result = snapshot.get_stake_delegated_to_spo_by_addresses(&spo1, &addresses); assert_eq!(result, 500); @@ -347,7 +347,7 @@ mod tests { ); // Extract key hash from stake address for the API call - let addresses = vec![addr_x.get_credential()]; + let addresses = vec![addr_x]; let result = snapshot.get_stake_delegated_to_spo_by_addresses(&spo1, &addresses); assert_eq!(result, 0); } diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 086035fa..51010c9d 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -15,8 +15,8 @@ use acropolis_common::{ stake_addresses::{StakeAddressMap, StakeAddressState}, BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, NetworkId, - PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeCredential, - StakeRewardDelta, TxCertificate, + PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, + TxCertificate, }; use anyhow::Result; use imbl::OrdMap; @@ -795,10 +795,7 @@ impl State { } /// Register a stake address, with a specified deposit if known - fn register_stake_address(&mut self, credential: &StakeCredential, deposit: Option) { - - let stake_address = credential.to_stake_address(self.network_id.clone().into()); - + fn register_stake_address(&mut self, stake_address: &StakeAddress, deposit: Option) { // Stake addresses can be registered after being used in UTXOs let mut stake_addresses = self.stake_addresses.lock().unwrap(); if stake_addresses.register_stake_address(&stake_address) { @@ -820,16 +817,13 @@ impl State { // Add to registration changes self.current_epoch_registration_changes.lock().unwrap().push(RegistrationChange { - address: stake_address, + address: stake_address.clone(), kind: RegistrationChangeKind::Registered, }); } /// Deregister a stake address, with specified refund if known - fn deregister_stake_address(&mut self, credential: &StakeCredential, refund: Option) { - - let stake_address = credential.to_stake_address(self.network_id.clone().into()); - + fn deregister_stake_address(&mut self, stake_address: &StakeAddress, refund: Option) { // Check if it existed let mut stake_addresses = self.stake_addresses.lock().unwrap(); if stake_addresses.deregister_stake_address(&stake_address) { @@ -852,7 +846,7 @@ impl State { // Add to registration changes self.current_epoch_registration_changes.lock().unwrap().push(RegistrationChange { - address: stake_address, + address: stake_address.clone(), kind: RegistrationChangeKind::Deregistered, }); } @@ -863,9 +857,7 @@ impl State { } /// Record a stake delegation - fn record_stake_delegation(&mut self, credential: &StakeCredential, spo: &KeyHash) { - - let stake_address = credential.to_stake_address(self.network_id.clone().into()); + fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &KeyHash) { let mut stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.record_stake_delegation(&stake_address, spo); } @@ -877,9 +869,7 @@ impl State { } /// record a drep delegation - fn record_drep_delegation(&mut self, credential: &StakeCredential, drep: &DRepChoice) { - - let stake_address = credential.to_stake_address(self.network_id.clone().into()); + fn record_drep_delegation(&mut self, stake_address: &StakeAddress, drep: &DRepChoice) { let mut stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.record_drep_delegation(&stake_address, drep); } @@ -889,12 +879,12 @@ impl State { // Handle certificates for tx_cert in tx_certs_msg.certificates.iter() { match tx_cert { - TxCertificate::StakeRegistration(sc_with_pos) => { - self.register_stake_address(&sc_with_pos.stake_credential, None); + TxCertificate::StakeRegistration(stake_address_with_pos) => { + self.register_stake_address(&stake_address_with_pos.stake_address, None); } - TxCertificate::StakeDeregistration(sc) => { - self.deregister_stake_address(&sc, None); + TxCertificate::StakeDeregistration(stake_address) => { + self.deregister_stake_address(&stake_address, None); } TxCertificate::MoveInstantaneousReward(mir) => { @@ -902,40 +892,49 @@ impl State { } TxCertificate::Registration(reg) => { - self.register_stake_address(®.credential, Some(reg.deposit)); + self.register_stake_address(®.stake_address, Some(reg.deposit)); } TxCertificate::Deregistration(dreg) => { - self.deregister_stake_address(&dreg.credential, Some(dreg.refund)); + self.deregister_stake_address(&dreg.stake_address, Some(dreg.refund)); } TxCertificate::StakeDelegation(delegation) => { - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); } TxCertificate::VoteDelegation(delegation) => { - self.record_drep_delegation(&delegation.credential, &delegation.drep); + self.record_drep_delegation(&delegation.stake_address, &delegation.drep); } TxCertificate::StakeAndVoteDelegation(delegation) => { - self.record_stake_delegation(&delegation.credential, &delegation.operator); - self.record_drep_delegation(&delegation.credential, &delegation.drep); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); + self.record_drep_delegation(&delegation.stake_address, &delegation.drep); } TxCertificate::StakeRegistrationAndDelegation(delegation) => { - self.register_stake_address(&delegation.credential, Some(delegation.deposit)); - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.register_stake_address( + &delegation.stake_address, + Some(delegation.deposit), + ); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); } TxCertificate::StakeRegistrationAndVoteDelegation(delegation) => { - self.register_stake_address(&delegation.credential, Some(delegation.deposit)); - self.record_drep_delegation(&delegation.credential, &delegation.drep); + self.register_stake_address( + &delegation.stake_address, + Some(delegation.deposit), + ); + self.record_drep_delegation(&delegation.stake_address, &delegation.drep); } TxCertificate::StakeRegistrationAndStakeAndVoteDelegation(delegation) => { - self.register_stake_address(&delegation.credential, Some(delegation.deposit)); - self.record_stake_delegation(&delegation.credential, &delegation.operator); - self.record_drep_delegation(&delegation.credential, &delegation.drep); + self.register_stake_address( + &delegation.stake_address, + Some(delegation.deposit), + ); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); + self.record_drep_delegation(&delegation.stake_address, &delegation.drep); } _ => (), @@ -995,8 +994,8 @@ mod tests { use super::*; use acropolis_common::{ protocol_params::ConwayParams, rational_number::RationalNumber, AddressNetwork, Anchor, - Committee, Constitution, CostModel, Credential, DRepVotingThresholds, PoolVotingThresholds, - Pot, PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAddressPayload, + Committee, Constitution, CostModel, DRepVotingThresholds, PoolVotingThresholds, Pot, + PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAddressPayload, StakeAndVoteDelegation, StakeRegistrationAndStakeAndVoteDelegation, StakeRegistrationAndVoteDelegation, VoteDelegation, Withdrawal, }; @@ -1011,10 +1010,6 @@ mod tests { } } - fn create_stake_credential(hash: &[u8]) -> StakeCredential { - StakeCredential::AddrKeyHash(hash.to_vec()) - } - const STAKE_KEY_HASH: [u8; 3] = [0x99, 0x0f, 0x00]; const DREP_HASH: [u8; 4] = [0xca, 0xfe, 0xd0, 0x0d]; @@ -1024,7 +1019,7 @@ mod tests { let stake_address = create_address(&STAKE_KEY_HASH); // Register first - state.register_stake_address(&StakeCredential::AddrKeyHash(STAKE_KEY_HASH.to_vec()), None); + state.register_stake_address(&stake_address, None); { let stake_addresses = state.stake_addresses.lock().unwrap(); @@ -1111,14 +1106,12 @@ mod tests { // Delegate let addr1 = create_address(&[0x11]); - let cred1 = Credential::AddrKeyHash(addr1.get_hash().to_vec()); - state.register_stake_address(&cred1, None); - state.record_stake_delegation(&cred1, &spo1); + state.register_stake_address(&addr1, None); + state.record_stake_delegation(&addr1, &spo1); let addr2 = create_address(&[0x12]); - let cred2 = Credential::AddrKeyHash(addr2.get_hash().to_vec()); - state.register_stake_address(&cred2, None); - state.record_stake_delegation(&cred2, &spo2); + state.register_stake_address(&addr2, None); + state.record_stake_delegation(&addr2, &spo2); // Put some value in let msg1 = StakeAddressDeltasMessage { @@ -1224,13 +1217,13 @@ mod tests { fn mir_transfers_to_stake_addresses() { let mut state = State::default(); let stake_address = create_address(&STAKE_KEY_HASH); - let stake_credential = create_stake_credential(stake_address.get_hash()); + let stake_credential = stake_address.get_credential(); // Bootstrap with some in reserves state.pots.reserves = 100; // Set up one stake address - state.register_stake_address(&stake_credential, None); + state.register_stake_address(&stake_address, None); let msg = StakeAddressDeltasMessage { deltas: vec![StakeAddressDelta { @@ -1273,13 +1266,13 @@ mod tests { fn withdrawal_transfers_from_stake_addresses() { let mut state = State::default(); let stake_address = create_address(&STAKE_KEY_HASH); - let stake_credential = create_stake_credential(stake_address.get_hash()); + let stake_credential = stake_address.get_credential(); // Bootstrap with some in reserves state.pots.reserves = 100; // Set up one stake address - state.register_stake_address(&stake_credential, None); + state.register_stake_address(&stake_address, None); let msg = StakeAddressDeltasMessage { deltas: vec![StakeAddressDelta { address: stake_address.clone(), @@ -1379,38 +1372,33 @@ mod tests { let spo3 = create_address(&[0x03]); let spo4 = create_address(&[0x04]); - let spo1_credential = create_stake_credential(spo1.get_hash()); - let spo2_credential = create_stake_credential(spo2.get_hash()); - let spo3_credential = create_stake_credential(spo3.get_hash()); - let spo4_credential = create_stake_credential(spo4.get_hash()); - let certificates = vec![ // register the first two SPOs separately from their delegation TxCertificate::Registration(Registration { - credential: spo1_credential.clone(), + stake_address: spo1.clone(), deposit: 1, }), TxCertificate::Registration(Registration { - credential: spo2_credential.clone(), + stake_address: spo2.clone(), deposit: 1, }), TxCertificate::VoteDelegation(VoteDelegation { - credential: spo1_credential.clone(), + stake_address: spo1.clone(), drep: DRepChoice::Key(DREP_HASH.to_vec()), }), TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { - credential: spo2_credential.clone(), + stake_address: spo2.clone(), operator: spo1.get_hash().to_vec(), drep: DRepChoice::Script(DREP_HASH.to_vec()), }), TxCertificate::StakeRegistrationAndVoteDelegation(StakeRegistrationAndVoteDelegation { - credential: spo3_credential.clone(), + stake_address: spo3.clone(), drep: DRepChoice::Abstain, deposit: 1, }), TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { - credential: spo4_credential, + stake_address: spo4.clone(), operator: spo1.get_hash().to_vec(), drep: DRepChoice::NoConfidence, deposit: 1, diff --git a/modules/drep_state/src/drep_state.rs b/modules/drep_state/src/drep_state.rs index eaaaf208..ccb97901 100644 --- a/modules/drep_state/src/drep_state.rs +++ b/modules/drep_state/src/drep_state.rs @@ -141,6 +141,7 @@ impl DRepState { context.clone(), &tx_certs_msg.certificates, block_info.epoch, + ) .await .inspect_err(|e| error!("Certificates handling error: {e:#}")) diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index 7a2c7296..db7a89b1 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -1,10 +1,15 @@ //! Acropolis DRepState: State storage -use acropolis_common::{messages::{Message, StateQuery, StateQueryResponse}, queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse, DEFAULT_ACCOUNTS_QUERY_TOPIC}, - get_query_topic, - governance::{DRepActionUpdate, DRepUpdateEvent, VoteRecord}, -}, Anchor, Credential, DRepChoice, DRepCredential, KeyHash, Lovelace, NetworkId, StakeAddress, StakeCredential, TxCertificate, TxHash, Voter, VotingProcedures}; +use acropolis_common::{ + messages::{Message, StateQuery, StateQueryResponse}, + queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse, DEFAULT_ACCOUNTS_QUERY_TOPIC}, + get_query_topic, + governance::{DRepActionUpdate, DRepUpdateEvent, VoteRecord}, + }, + Anchor, DRepChoice, DRepCredential, KeyHash, Lovelace, + StakeAddress, TxCertificate, TxHash, Voter, VotingProcedures, +}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; use serde_with::serde_as; @@ -33,7 +38,7 @@ pub struct HistoricalDRepState { // - StakeAndVoteDelegation // - StakeRegistrationAndVoteDelegation // - StakeRegistrationAndStakeAndVoteDelegation - pub delegators: Option>, + pub delegators: Option>, // Populated from voting_procedures in GovernanceProceduresMessage pub votes: Option>, @@ -89,7 +94,6 @@ impl DRepStorageConfig { pub struct State { pub config: DRepStorageConfig, pub dreps: HashMap, - pub network_id: NetworkId, pub historical_dreps: Option>, } @@ -98,7 +102,6 @@ impl State { Self { config, dreps: HashMap::new(), - network_id: NetworkId::default(), historical_dreps: if config.any_enabled() { Some(HashMap::new()) } else { @@ -149,7 +152,7 @@ impl State { pub fn get_drep_delegators( &self, credential: &DRepCredential, - ) -> Result>, &'static str> { + ) -> Result>, &'static str> { let hist = self .historical_dreps .as_ref() @@ -225,7 +228,9 @@ impl State { for tx_cert in tx_certs { if store_delegators { - if let Some((cred, drep)) = Self::extract_delegation_fields(tx_cert) { + if let Some((cred, drep)) = + Self::extract_delegation_fields(tx_cert) + { batched_delegators.push((cred, drep)); continue; } @@ -469,15 +474,12 @@ impl State { async fn update_delegators( &mut self, context: &Arc>, - delegators: Vec<(&StakeCredential, &DRepChoice)>, + delegators: Vec<(StakeAddress, &DRepChoice)>, ) -> Result<()> { - let stake_keys: Vec = delegators.iter().map(|(sc, _)| sc.get_hash()).collect(); - let stake_addresses: Vec = delegators.iter().map(|(k, _) | k.to_stake_address(self.network_id.clone().into()) ).collect(); - let stake_key_to_input: HashMap = delegators - .iter() - .zip(&stake_keys) - .map(|((sc, drep), key)| (key.clone(), (*sc, *drep))) - .collect(); + let stake_addresses = delegators.iter().map(|(addr, _)| (addr).clone()).collect(); + + let stake_key_to_input: HashMap = + delegators.iter().map(|(addr, drep)| (addr.get_hash().to_vec(), (addr, *drep))).collect(); let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsDrepDelegationsMap { stake_addresses }, @@ -513,7 +515,7 @@ impl State { if old_drep_cred != new_drep_cred { self.update_historical(&old_drep_cred, false, |entry| { if let Some(delegators) = entry.delegators.as_mut() { - delegators.retain(|s| s != delegator); + delegators.retain(|s| s.to_binary() != delegator.to_binary()); } })?; } @@ -523,7 +525,7 @@ impl State { // Add delegator to new DRep match self.update_historical(&new_drep_cred, true, |entry| { if let Some(delegators) = entry.delegators.as_mut() { - if !delegators.contains(delegator) { + if !delegators.contains(&delegator) { delegators.push(delegator.clone()); } } @@ -536,13 +538,21 @@ impl State { Ok(()) } - fn extract_delegation_fields(cert: &TxCertificate) -> Option<(&StakeCredential, &DRepChoice)> { + fn extract_delegation_fields( + cert: &TxCertificate, + ) -> Option<(StakeAddress, &DRepChoice)> { match cert { - TxCertificate::VoteDelegation(d) => Some((&d.credential, &d.drep)), - TxCertificate::StakeAndVoteDelegation(d) => Some((&d.credential, &d.drep)), - TxCertificate::StakeRegistrationAndVoteDelegation(d) => Some((&d.credential, &d.drep)), + TxCertificate::VoteDelegation(d) => { + Some((d.stake_address.clone(), &d.drep)) + } + TxCertificate::StakeAndVoteDelegation(d) => { + Some((d.stake_address.clone(), &d.drep)) + } + TxCertificate::StakeRegistrationAndVoteDelegation(d) => { + Some((d.stake_address.clone(), &d.drep)) + } TxCertificate::StakeRegistrationAndStakeAndVoteDelegation(d) => { - Some((&d.credential, &d.drep)) + Some((d.stake_address.clone(), &d.drep)) } _ => None, } diff --git a/modules/epochs_state/src/epochs_history.rs b/modules/epochs_state/src/epochs_history.rs index 145a309b..dc37b56a 100644 --- a/modules/epochs_state/src/epochs_history.rs +++ b/modules/epochs_state/src/epochs_history.rs @@ -78,7 +78,7 @@ impl EpochsHistoryState { #[cfg(test)] mod tests { use super::*; - use acropolis_common::{BlockHash, BlockStatus, Era, NetworkId}; + use acropolis_common::{BlockHash, BlockStatus, Era}; fn make_block(epoch: u64) -> BlockInfo { BlockInfo { @@ -89,7 +89,6 @@ mod tests { epoch, epoch_slot: 99, new_epoch: false, - network_id: NetworkId::default(), timestamp: 99999, era: Era::Conway, } diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 6fbd40f3..0a46c07a 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -269,7 +269,7 @@ mod tests { crypto::keyhash_224, protocol_params::{Nonce, NonceHash}, state_history::{StateHistory, StateHistoryStore}, - BlockHash, BlockInfo, BlockStatus, Era, NetworkId, + BlockHash, BlockInfo, BlockStatus, Era, }; use tokio::sync::Mutex; @@ -281,7 +281,6 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, - network_id: NetworkId::default(), new_epoch: false, timestamp: 99999, era: Era::Shelley, @@ -296,7 +295,6 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, - network_id: NetworkId::default(), new_epoch: true, timestamp: 99999, era: Era::Shelley, @@ -311,7 +309,6 @@ mod tests { hash: BlockHash::default(), epoch, epoch_slot: 99, - network_id: NetworkId::default(), new_epoch: false, timestamp: 99999, era: Era::Conway, diff --git a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs index 54e7a224..b256954c 100644 --- a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs +++ b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs @@ -7,8 +7,8 @@ use acropolis_common::{ CardanoMessage, GenesisCompleteMessage, GenesisUTxOsMessage, Message, PotDeltasMessage, UTXODeltasMessage, }, - Address, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, Lovelace, LovelaceDelta, - NetworkId, Pot, PotDelta, TxIdentifier, TxOutRef, TxOutput, UTXODelta, UTxOIdentifier, Value, + Address, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, Lovelace, LovelaceDelta, Pot, + PotDelta, TxIdentifier, TxOutRef, TxOutput, UTXODelta, UTxOIdentifier, Value, }; use anyhow::Result; use blake2::{digest::consts::U32, Blake2b, Digest}; @@ -128,7 +128,6 @@ impl GenesisBootstrapper { hash: BlockHash::default(), epoch: 0, epoch_slot: 0, - network_id: NetworkId::from(network_name), new_epoch: false, timestamp: byron_genesis.start_time, era: Era::Byron, diff --git a/modules/governance_state/src/alonzo_babbage_voting.rs b/modules/governance_state/src/alonzo_babbage_voting.rs index b20a403c..bc90a45b 100644 --- a/modules/governance_state/src/alonzo_babbage_voting.rs +++ b/modules/governance_state/src/alonzo_babbage_voting.rs @@ -113,7 +113,7 @@ mod tests { use crate::alonzo_babbage_voting::AlonzoBabbageVoting; use acropolis_common::{ rational_number::rational_number_from_f32, AlonzoBabbageUpdateProposal, - AlonzoBabbageVotingOutcome, BlockHash, BlockInfo, BlockStatus, GenesisKeyhash, NetworkId, + AlonzoBabbageVotingOutcome, BlockHash, BlockInfo, BlockStatus, GenesisKeyhash, ProtocolParamUpdate, }; use anyhow::Result; @@ -154,7 +154,6 @@ mod tests { epoch, epoch_slot: 0, era: era.try_into()?, - network_id: NetworkId::default(), new_epoch: new_epoch != 0, timestamp: 0, hash: BlockHash::default(), diff --git a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs index 7e6fafe7..20804f2f 100644 --- a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs +++ b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs @@ -4,7 +4,7 @@ use acropolis_common::{ genesis_values::GenesisValues, messages::{BlockBodyMessage, BlockHeaderMessage, CardanoMessage, Message}, - BlockInfo, BlockStatus, Era, NetworkId, + BlockInfo, BlockStatus, Era, }; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::{module, Context, Module}; @@ -45,7 +45,6 @@ const DEFAULT_PAUSE: (&str, PauseType) = ("pause", PauseType::NoPause); const DEFAULT_DOWNLOAD_MAX_AGE: &str = "download-max-age"; const DEFAULT_DIRECTORY: &str = "downloads"; const SNAPSHOT_METADATA_FILE: &str = "snapshot_metadata.json"; -const DEFAULT_NETWORK_ID: &str = "mainnet"; /// Mithril feedback receiver struct FeedbackLogger { @@ -308,12 +307,6 @@ impl MithrilSnapshotFetcher { let timestamp = genesis.slot_to_timestamp(slot); - let network_id = NetworkId::from( - config - .get_string("network-id") - .unwrap_or(DEFAULT_NETWORK_ID.to_string()), - ); - let era = match block.era() { PallasEra::Byron => Era::Byron, PallasEra::Shelley => Era::Shelley, @@ -335,7 +328,6 @@ impl MithrilSnapshotFetcher { epoch, epoch_slot, new_epoch, - network_id, timestamp, era, }; diff --git a/modules/rest_blockfrost/src/handlers/governance.rs b/modules/rest_blockfrost/src/handlers/governance.rs index 5d0ef2d6..241fb5e4 100644 --- a/modules/rest_blockfrost/src/handlers/governance.rs +++ b/modules/rest_blockfrost/src/handlers/governance.rs @@ -10,9 +10,9 @@ use acropolis_common::{ accounts::{AccountsStateQuery, AccountsStateQueryResponse}, governance::{GovernanceStateQuery, GovernanceStateQueryResponse}, }, - Credential, GovActionId, StakeAddress, TxHash, Voter, + Credential, GovActionId, KeyHash, TxHash, Voter, }; -use anyhow::Result; +use anyhow::{anyhow, Result}; use caryatid_sdk::Context; use reqwest::Client; use serde_json::Value; @@ -99,11 +99,7 @@ pub async fn handle_single_drep_blockfrost( )) => { let active = !response.info.retired && !response.info.expired; - let stake_addresses = response - .delegators - .iter() - .map(|addr| addr.to_stake_address(handlers_config.network_id.clone().into())) - .collect(); + let stake_addresses = response.delegators.clone(); let sum_msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsBalancesSum { stake_addresses }, @@ -195,29 +191,23 @@ pub async fn handle_drep_delegators_blockfrost( Message::StateQueryResponse(StateQueryResponse::Governance( GovernanceStateQueryResponse::DRepDelegators(delegators), )) => { - let mut stake_addresses: Vec = Vec::new(); - let mut stake_key_to_bech32 = HashMap::new(); - - for addr in &delegators.addresses { - let bech32 = match addr.to_stake_bech32() { - Ok(b) => b, - Err(_) => { - return Ok(RESTResponse::with_text( - 500, - "Internal error: failed to encode stake address", - )); - } - }; - - let hash = addr.get_hash(); - let stake_address = - addr.to_stake_address(handlers_config.network_id.clone().into()); - stake_addresses.push(stake_address.clone()); - stake_key_to_bech32.insert(hash, bech32); - } + let stake_key_to_bech32: HashMap = delegators + .addresses + .iter() + .map(|addr| { + let bech32 = addr + .get_credential() + .to_stake_bech32() + .map_err(|_| anyhow!("Failed to encode stake address"))?; + let key_hash = addr.get_hash().to_vec(); + Ok((key_hash, bech32)) + }) + .collect::>>()?; let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( - AccountsStateQuery::GetAccountsUtxoValuesMap { stake_addresses }, + AccountsStateQuery::GetAccountsUtxoValuesMap { + stake_addresses: delegators.addresses.clone(), + }, ))); let raw_msg = diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index bad519a4..9ae26994 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -664,11 +664,7 @@ async fn handle_pools_spo_blockfrost( // Query owner accounts balance sum from accounts_state let live_pledge_msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsUtxoValuesSum { - stake_addresses: pool_info - .pool_owners - .iter() - .map(|owner| owner.to_stake_address(handlers_config.network_id.clone().into())) - .collect(), + stake_addresses: pool_info.pool_owners.clone(), }, ))); @@ -703,7 +699,7 @@ async fn handle_pools_spo_blockfrost( let pool_owners = pool_info .pool_owners .iter() - .map(|owner| owner.to_stake_bech32()) + .map(|owner| owner.get_credential().to_stake_bech32()) .collect::, _>>(); let Ok(pool_owners) = pool_owners else { return Ok(RESTResponse::with_text(404, "Invalid Pool Owners")); diff --git a/modules/rest_blockfrost/src/handlers_config.rs b/modules/rest_blockfrost/src/handlers_config.rs index 0dbf22fc..53ea6b79 100644 --- a/modules/rest_blockfrost/src/handlers_config.rs +++ b/modules/rest_blockfrost/src/handlers_config.rs @@ -9,13 +9,10 @@ use acropolis_common::queries::{ pools::DEFAULT_POOLS_QUERY_TOPIC, spdd::DEFAULT_SPDD_QUERY_TOPIC, }; -use acropolis_common::NetworkId; use config::Config; const DEFAULT_EXTERNAL_API_TIMEOUT: (&str, i64) = ("external_api_timeout", 3); // 3 seconds -const DEFAULT_NETWORK_ID: (&str, &str) = ("network", "mainnet"); - #[derive(Clone)] pub struct HandlersConfig { pub accounts_query_topic: String, @@ -28,7 +25,6 @@ pub struct HandlersConfig { pub parameters_query_topic: String, pub external_api_timeout: u64, pub offchain_token_registry_url: String, - pub network_id: NetworkId, } impl From> for HandlersConfig { @@ -73,11 +69,6 @@ impl From> for HandlersConfig { .get_string(DEFAULT_OFFCHAIN_TOKEN_REGISTRY_URL.0) .unwrap_or(DEFAULT_OFFCHAIN_TOKEN_REGISTRY_URL.1.to_string()); - let network_id = config - .get_string(DEFAULT_NETWORK_ID.0) - .unwrap_or(DEFAULT_NETWORK_ID.1.to_string()) - .into(); - Self { accounts_query_topic, assets_query_topic, @@ -89,7 +80,6 @@ impl From> for HandlersConfig { parameters_query_topic, external_api_timeout, offchain_token_registry_url, - network_id, } } } diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index de8a2c05..115e9dda 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -10,9 +10,9 @@ use acropolis_common::{ params::TECHNICAL_PARAMETER_POOL_RETIRE_MAX_EPOCH, queries::governance::VoteRecord, stake_addresses::StakeAddressMap, - BlockInfo, KeyHash, NetworkId, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, - PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, StakeCredential, - TxCertificate, TxHash, Voter, VotingProcedures, + BlockInfo, KeyHash, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, PoolRetirement, + PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, TxCertificate, TxHash, Voter, + VotingProcedures, }; use anyhow::Result; use imbl::HashMap; @@ -30,8 +30,6 @@ pub struct State { epoch: u64, - network_id: NetworkId, - spos: HashMap, PoolRegistration>, pending_updates: HashMap, PoolRegistration>, @@ -60,7 +58,6 @@ impl State { pending_updates: HashMap::new(), pending_deregistrations: HashMap::new(), total_blocks_minted: HashMap::new(), - network_id: NetworkId::default(), historical_spos: if config.store_historical_state() { Some(HashMap::new()) } else { @@ -111,7 +108,6 @@ impl From for State { store_config: StoreConfig::default(), block: 0, epoch: 0, - network_id: NetworkId::default(), spos, pending_updates: value.updates.into(), pending_deregistrations, @@ -441,20 +437,18 @@ impl State { } } - fn register_stake_address(&mut self, credential: &StakeCredential) { + fn register_stake_address(&mut self, stake_address: &StakeAddress) { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return; }; let mut stake_addresses = stake_addresses.lock().unwrap(); - stake_addresses - .register_stake_address(&credential.to_stake_address(self.network_id.clone().into())); + stake_addresses.register_stake_address(stake_address); } - fn deregister_stake_address(&mut self, credential: &StakeCredential) { + fn deregister_stake_address(&mut self, stake_address: &StakeAddress) { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return; }; - let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = stake_addresses.lock().unwrap(); let old_spo = stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); @@ -465,14 +459,12 @@ impl State { if let Some(old_spo) = old_spo.as_ref() { // remove delegators from old_spo if let Some(historical_spo) = historical_spos.get_mut(old_spo) { - if let Some(removed) = historical_spo.remove_delegator( - &credential.to_stake_address(self.network_id.clone().into()), - ) { + if let Some(removed) = historical_spo.remove_delegator(stake_address) { if !removed { error!( "Historical SPO state for {} does not contain delegator {}", hex::encode(old_spo), - hex::encode(&credential.get_hash()) + stake_address ); } } @@ -484,12 +476,10 @@ impl State { /// Record a stake delegation /// Update historical_spo_state's delegators - fn record_stake_delegation(&mut self, credential: &StakeCredential, spo: &KeyHash) { + fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &KeyHash) { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return; }; - let hash = credential.get_hash(); - let stake_address = credential.to_stake_address(self.network_id.clone().into()); let mut stake_addresses = stake_addresses.lock().unwrap(); let old_spo = stake_addresses.get(&stake_address).map(|s| s.delegated_spo.clone()).flatten(); @@ -506,7 +496,7 @@ impl State { error!( "Historical SPO state for {} does not contain delegator {}", hex::encode(old_spo), - hex::encode(&hash) + stake_address ); } } @@ -526,7 +516,7 @@ impl State { error!( "Historical SPO state for {} already contains delegator {}", hex::encode(spo), - hex::encode(&hash) + stake_address ); } } @@ -558,38 +548,38 @@ impl State { } // for stake addresses - TxCertificate::StakeRegistration(sc_with_pos) => { - self.register_stake_address(&sc_with_pos.stake_credential); + TxCertificate::StakeRegistration(stake_address_with_pos) => { + self.register_stake_address(&stake_address_with_pos.stake_address); } - TxCertificate::StakeDeregistration(sc) => { - self.deregister_stake_address(&sc); + TxCertificate::StakeDeregistration(stake_address) => { + self.deregister_stake_address(&stake_address); } TxCertificate::Registration(reg) => { - self.register_stake_address(®.credential); + self.register_stake_address(®.stake_address); // we don't care deposite } TxCertificate::Deregistration(dreg) => { - self.deregister_stake_address(&dreg.credential); + self.deregister_stake_address(&dreg.stake_address); // we don't care refund } TxCertificate::StakeDelegation(delegation) => { - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); } TxCertificate::StakeAndVoteDelegation(delegation) => { - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); // don't care about vote delegation } TxCertificate::StakeRegistrationAndDelegation(delegation) => { - self.register_stake_address(&delegation.credential); - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.register_stake_address(&delegation.stake_address); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); } TxCertificate::StakeRegistrationAndVoteDelegation(delegation) => { - self.register_stake_address(&delegation.credential); + self.register_stake_address(&delegation.stake_address); // don't care about vote delegation } TxCertificate::StakeRegistrationAndStakeAndVoteDelegation(delegation) => { - self.register_stake_address(&delegation.credential); - self.record_stake_delegation(&delegation.credential, &delegation.operator); + self.register_stake_address(&delegation.stake_address); + self.record_stake_delegation(&delegation.stake_address, &delegation.operator); // don't care about vote delegation } _ => (), @@ -694,12 +684,20 @@ mod tests { use crate::test_utils::*; use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, - Credential, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, + NetworkId, PoolRetirement, Ratio, StakeAddress, StakeAddressPayload, TxCertificate, TxHash, }; use tokio::sync::Mutex; - fn pool_owners_from_bytes(owners: Vec>) -> Vec { - owners.into_iter().map(|bytes| Credential::AddrKeyHash(bytes)).collect() + fn pool_owners_from_bytes(owners: Vec>) -> Vec { + owners + .into_iter() + .map(|bytes| { + StakeAddress::new( + StakeAddressPayload::StakeKeyHash(bytes), + NetworkId::default().into(), + ) + }) + .collect() } fn default_pool_registration(operator: Vec) -> PoolRegistration { @@ -713,7 +711,7 @@ mod tests { denominator: 0, }, reward_account: StakeAddress::default(), - pool_owners: pool_owners_from_bytes(vec![operator]), + pool_owners: pool_owners_from_bytes(vec![StakeAddress::default().get_hash().to_vec()]), relays: vec![], pool_metadata: None, } diff --git a/modules/spo_state/src/test_utils.rs b/modules/spo_state/src/test_utils.rs index 92be798f..b1fd1484 100644 --- a/modules/spo_state/src/test_utils.rs +++ b/modules/spo_state/src/test_utils.rs @@ -1,6 +1,6 @@ use acropolis_common::{messages::{ EpochActivityMessage, SPORewardsMessage, SPOStakeDistributionMessage, TxCertificatesMessage, -}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId, TxCertificate}; +}, BlockHash, BlockInfo, BlockStatus, Era, TxCertificate}; use crate::store_config::StoreConfig; @@ -65,7 +65,6 @@ pub fn new_block(epoch: u64) -> BlockInfo { epoch, epoch_slot: 0, new_epoch: true, - network_id: NetworkId::default(), timestamp: epoch, era: Era::Byron, } diff --git a/modules/stake_delta_filter/src/state.rs b/modules/stake_delta_filter/src/state.rs index 59dbb56f..df90cc38 100644 --- a/modules/stake_delta_filter/src/state.rs +++ b/modules/stake_delta_filter/src/state.rs @@ -7,8 +7,7 @@ use acropolis_common::{ AddressDeltasMessage, CardanoMessage, Message, StakeAddressDeltasMessage, TxCertificatesMessage, }, - Address, BlockInfo, ShelleyAddressPointer, StakeAddress, StakeAddressPayload, StakeCredential, - TxCertificate, + Address, BlockInfo, ShelleyAddressPointer, TxCertificate, }; use anyhow::Result; use serde_with::serde_as; @@ -93,17 +92,7 @@ impl State { cert_index: reg.cert_index, }; - let stake_address = StakeAddress { - network: self.params.network.clone(), - payload: match ®.stake_credential { - StakeCredential::ScriptHash(h) => { - StakeAddressPayload::ScriptHash(h.clone()) - } - StakeCredential::AddrKeyHash(k) => { - StakeAddressPayload::StakeKeyHash(k.clone()) - } - }, - }; + let stake_address = reg.stake_address.clone(); // Sets pointer; updates max processed slot self.pointer_cache.set_pointer(ptr, stake_address, block.slot); diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 7ce5b96e..d4919122 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -401,7 +401,7 @@ mod test { use crate::*; use acropolis_common::{ messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, - ByronAddress, Era, NetworkId, ShelleyAddress, ShelleyAddressDelegationPart, + ByronAddress, Era, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeAddressPayload, ValueDelta, }; @@ -542,7 +542,6 @@ mod test { epoch: 1, epoch_slot: 14243, new_epoch: true, - network_id: NetworkId::default(), timestamp: 2498243, era: Era::Conway, }; diff --git a/modules/tx_unpacker/src/map_parameters.rs b/modules/tx_unpacker/src/map_parameters.rs index 1439479e..74dfd557 100644 --- a/modules/tx_unpacker/src/map_parameters.rs +++ b/modules/tx_unpacker/src/map_parameters.rs @@ -93,6 +93,20 @@ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { } } +/// Map a PallasStakeCredential to our StakeAddress +pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> StakeAddress { + let payload = match cred { + PallasStakeCredential::AddrKeyhash(key_hash) => { + StakeAddressPayload::StakeKeyHash(key_hash.to_vec()) + } + PallasStakeCredential::ScriptHash(script_hash) => { + StakeAddressPayload::ScriptHash(script_hash.to_vec()) + } + }; + + StakeAddress::new(payload, network_id.into()) +} + /// Map a Pallas DRep to our DRepChoice pub fn map_drep(drep: &conway::DRep) -> DRepChoice { match drep { @@ -203,24 +217,25 @@ pub fn map_certificate( tx_hash: TxHash, tx_index: u16, cert_index: usize, + network_id: NetworkId, ) -> Result { match cert { MultiEraCert::NotApplicable => Err(anyhow!("Not applicable cert!")), MultiEraCert::AlonzoCompatible(cert) => match cert.as_ref().as_ref() { alonzo::Certificate::StakeRegistration(cred) => { - Ok(TxCertificate::StakeRegistration(StakeCredentialWithPos { - stake_credential: map_stake_credential(cred), + Ok(TxCertificate::StakeRegistration(StakeAddressWithPos { + stake_address: map_stake_address(cred, network_id), tx_index: tx_index.try_into().unwrap(), cert_index: cert_index.try_into().unwrap(), })) } alonzo::Certificate::StakeDeregistration(cred) => Ok( - TxCertificate::StakeDeregistration(map_stake_credential(cred)), + TxCertificate::StakeDeregistration(map_stake_address(cred, network_id)), ), alonzo::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), operator: pool_key_hash.to_vec(), })) } @@ -246,7 +261,15 @@ pub fn map_certificate( denominator: margin.denominator, }, reward_account: StakeAddress::from_binary(reward_account)?, - pool_owners: pool_owners.into_iter().map(|v| Credential::AddrKeyHash(v.to_vec())).collect(), + pool_owners: pool_owners + .into_iter() + .map(|v| { + StakeAddress::new( + StakeAddressPayload::StakeKeyHash(v.to_vec()), + network_id.clone().into(), + ) + }) + .collect(), relays: relays.into_iter().map(|relay| map_relay(relay)).collect(), pool_metadata: match pool_metadata { Nullable::Some(md) => Some(PoolMetadata { @@ -310,18 +333,18 @@ pub fn map_certificate( MultiEraCert::Conway(cert) => { match cert.as_ref().as_ref() { conway::Certificate::StakeRegistration(cred) => { - Ok(TxCertificate::StakeRegistration(StakeCredentialWithPos { - stake_credential: map_stake_credential(cred), + Ok(TxCertificate::StakeRegistration(StakeAddressWithPos { + stake_address: map_stake_address(cred, network_id), tx_index: tx_index.try_into().unwrap(), cert_index: cert_index.try_into().unwrap(), })) } conway::Certificate::StakeDeregistration(cred) => Ok( - TxCertificate::StakeDeregistration(map_stake_credential(cred)), + TxCertificate::StakeDeregistration(map_stake_address(cred, network_id)), ), conway::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), operator: pool_key_hash.to_vec(), })) } @@ -348,7 +371,15 @@ pub fn map_certificate( denominator: margin.denominator, }, reward_account: StakeAddress::from_binary(reward_account)?, - pool_owners: pool_owners.into_iter().map(|v| Credential::AddrKeyHash(v.to_vec())).collect(), + pool_owners: pool_owners + .into_iter() + .map(|v| { + StakeAddress::new( + StakeAddressPayload::StakeKeyHash(v.to_vec()), + network_id.clone().into(), + ) + }) + .collect(), relays: relays.into_iter().map(|relay| map_relay(relay)).collect(), pool_metadata: match pool_metadata { Nullable::Some(md) => Some(PoolMetadata { @@ -375,28 +406,28 @@ pub fn map_certificate( conway::Certificate::Reg(cred, coin) => { Ok(TxCertificate::Registration(Registration { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), deposit: *coin, })) } conway::Certificate::UnReg(cred, coin) => { Ok(TxCertificate::Deregistration(Deregistration { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), refund: *coin, })) } conway::Certificate::VoteDeleg(cred, drep) => { Ok(TxCertificate::VoteDelegation(VoteDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), drep: map_drep(drep), })) } conway::Certificate::StakeVoteDeleg(cred, pool_key_hash, drep) => Ok( TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), operator: pool_key_hash.to_vec(), drep: map_drep(drep), }), @@ -404,7 +435,7 @@ pub fn map_certificate( conway::Certificate::StakeRegDeleg(cred, pool_key_hash, coin) => Ok( TxCertificate::StakeRegistrationAndDelegation(StakeRegistrationAndDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), operator: pool_key_hash.to_vec(), deposit: *coin, }), @@ -413,7 +444,7 @@ pub fn map_certificate( conway::Certificate::VoteRegDeleg(cred, drep, coin) => { Ok(TxCertificate::StakeRegistrationAndVoteDelegation( StakeRegistrationAndVoteDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), drep: map_drep(drep), deposit: *coin, }, @@ -423,7 +454,7 @@ pub fn map_certificate( conway::Certificate::StakeVoteRegDeleg(cred, pool_key_hash, drep, coin) => { Ok(TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { - credential: map_stake_credential(cred), + stake_address: map_stake_address(cred, network_id), operator: pool_key_hash.to_vec(), drep: map_drep(drep), deposit: *coin, diff --git a/modules/tx_unpacker/src/tx_unpacker.rs b/modules/tx_unpacker/src/tx_unpacker.rs index 03f28759..6bd246a0 100644 --- a/modules/tx_unpacker/src/tx_unpacker.rs +++ b/modules/tx_unpacker/src/tx_unpacker.rs @@ -103,6 +103,9 @@ impl TxUnpacker { info!("Publishing block txs on '{topic}'"); } + let network_id: NetworkId = + config.get_string("network-id").unwrap_or("mainnet".to_string()).into(); + // Initialize UTxORegistry let mut utxo_registry = UTxORegistry::default(); @@ -267,7 +270,7 @@ impl TxUnpacker { if publish_certificates_topic.is_some() { let tx_hash = tx.hash(); for ( cert_index, cert) in certs.iter().enumerate() { - match map_parameters::map_certificate(&cert, *tx_hash, tx_index, cert_index) { + match map_parameters::map_certificate(&cert, *tx_hash, tx_index, cert_index, network_id.clone()) { Ok(tx_cert) => { certificates.push(tx_cert); }, diff --git a/modules/upstream_chain_fetcher/src/body_fetcher.rs b/modules/upstream_chain_fetcher/src/body_fetcher.rs index 21a2ed95..d84104c0 100644 --- a/modules/upstream_chain_fetcher/src/body_fetcher.rs +++ b/modules/upstream_chain_fetcher/src/body_fetcher.rs @@ -1,7 +1,7 @@ //! Acropolis Miniprotocols module for Caryatid //! Multi-connection, block body fetching part of the client (in separate thread). -use acropolis_common::{messages::{BlockBodyMessage, BlockHeaderMessage}, BlockInfo, BlockStatus, Era, NetworkId}; +use acropolis_common::{messages::{BlockBodyMessage, BlockHeaderMessage}, BlockInfo, BlockStatus, Era}; use anyhow::{bail, Result}; use crossbeam::channel::{Receiver, TryRecvError}; use pallas::{ @@ -108,7 +108,6 @@ impl BodyFetcher { None => true, }; let timestamp = self.cfg.slot_to_timestamp(slot); - let network_id = NetworkId::from(self.cfg.network_id.clone()); Ok(BlockInfo { status: if rolled_back { @@ -121,7 +120,6 @@ impl BodyFetcher { hash, epoch, epoch_slot, - network_id, new_epoch, timestamp, era, diff --git a/modules/upstream_chain_fetcher/src/upstream_cache.rs b/modules/upstream_chain_fetcher/src/upstream_cache.rs index 8be89694..022b13c7 100644 --- a/modules/upstream_chain_fetcher/src/upstream_cache.rs +++ b/modules/upstream_chain_fetcher/src/upstream_cache.rs @@ -151,8 +151,7 @@ impl Storage for FileStorage { let file = File::open(&name)?; let reader = BufReader::new(file); - match serde_json::from_reader::, Vec>(reader) - { + match serde_json::from_reader::, Vec>(reader) { Ok(res) => Ok(res.clone()), Err(err) => Err(anyhow!( "Error reading upstream cache chunk JSON from {name}: '{err}'" @@ -170,7 +169,10 @@ impl Storage for FileStorage { #[cfg(test)] mod test { use crate::upstream_cache::{Storage, UpstreamCacheImpl, UpstreamCacheRecord}; - use acropolis_common::{messages::{BlockBodyMessage, BlockHeaderMessage}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId}; + use acropolis_common::{ + messages::{BlockBodyMessage, BlockHeaderMessage}, + BlockHash, BlockInfo, BlockStatus, Era, + }; use anyhow::Result; use std::{collections::HashMap, sync::Arc}; @@ -183,7 +185,6 @@ mod test { epoch: 0, epoch_slot: n, new_epoch: false, - network_id: NetworkId::default(), timestamp: n, era: Era::default(), } diff --git a/modules/upstream_chain_fetcher/src/utils.rs b/modules/upstream_chain_fetcher/src/utils.rs index 1010a695..9ca3594c 100644 --- a/modules/upstream_chain_fetcher/src/utils.rs +++ b/modules/upstream_chain_fetcher/src/utils.rs @@ -1,7 +1,6 @@ use crate::UpstreamCacheRecord; use acropolis_common::genesis_values::GenesisValues; use acropolis_common::messages::{CardanoMessage, Message}; -use acropolis_common::NetworkId; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::Context; use config::Config; diff --git a/modules/utxo_state/src/state.rs b/modules/utxo_state/src/state.rs index 0c703a90..b3e03d55 100644 --- a/modules/utxo_state/src/state.rs +++ b/modules/utxo_state/src/state.rs @@ -373,7 +373,7 @@ impl State { mod tests { use super::*; use crate::InMemoryImmutableUTXOStore; - use acropolis_common::{AssetName, BlockHash, ByronAddress, Era, NativeAsset, NetworkId, Value}; + use acropolis_common::{AssetName, BlockHash, ByronAddress, Era, NativeAsset, Value}; use config::Config; use tokio::sync::Mutex; @@ -394,7 +394,6 @@ mod tests { epoch_slot: slot, new_epoch: false, timestamp: slot, - network_id: NetworkId::default(), era: Era::Byron, } } diff --git a/processes/golden_tests/src/test_module.rs b/processes/golden_tests/src/test_module.rs index f12e1ed6..f0fd85de 100644 --- a/processes/golden_tests/src/test_module.rs +++ b/processes/golden_tests/src/test_module.rs @@ -1,7 +1,7 @@ use acropolis_common::{ledger_state::LedgerState, messages::{ CardanoMessage, Message, RawTxsMessage, SnapshotDumpMessage, SnapshotMessage, SnapshotStateMessage, -}, BlockHash, BlockInfo, BlockStatus, Era, NetworkId}; +}, BlockHash, BlockInfo, BlockStatus, Era}; use anyhow::{Context as AnyhowContext, Result}; use caryatid_sdk::{module, Context, Module}; use config::Config; @@ -43,7 +43,6 @@ impl TestModule { slot: 1, number: 1, hash: BlockHash::default(), - network_id: NetworkId::default(), epoch: 1, epoch_slot: 1, new_epoch: false, diff --git a/processes/omnibus/omnibus.toml b/processes/omnibus/omnibus.toml index 6861a9c9..d4f96049 100644 --- a/processes/omnibus/omnibus.toml +++ b/processes/omnibus/omnibus.toml @@ -9,18 +9,15 @@ genesis-key = "5b3139312c36362c3134302c3138352c3133382c31312c3233372c3230372c323 download-max-age = "never" # Pause constraint E.g. "epoch:100", "block:1200" pause = "none" -network = "mainnet" [module.upstream-chain-fetcher] sync-point = "snapshot" node-address = "backbone.cardano.iog.io:3001" magic-number = 764824073 -network = "mainnet" [module.block-unpacker] [module.rest-blockfrost] -network = "mainnet" [module.tx-unpacker] publish-utxo-deltas-topic = "cardano.utxo.deltas" @@ -29,6 +26,7 @@ publish-withdrawals-topic = "cardano.withdrawals" publish-certificates-topic = "cardano.certificates" publish-governance-topic = "cardano.governance" publish-block-txs-topic = "cardano.block.txs" +network-name = "mainnet" [module.utxo-state] store = "memory" # "memory", "dashmap", "fjall", "fjall-async", "sled", "sled-async", "fake" From de08f0a0ba2dd8e8ba87ba0698498889a6dcf389 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 22 Oct 2025 12:59:18 -0700 Subject: [PATCH 3/4] Refactor: Replace `StakeCredentials` with `StakeAddresses` for MIR targets and simplify handling --- common/src/types.rs | 16 +-------------- modules/accounts_state/src/state.rs | 22 +++++++-------------- modules/tx_unpacker/src/map_parameters.rs | 4 ++-- modules/upstream_chain_fetcher/src/utils.rs | 12 +++-------- 4 files changed, 13 insertions(+), 41 deletions(-) diff --git a/common/src/types.rs b/common/src/types.rs index 592f6204..40cbb38f 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -623,20 +623,6 @@ impl Credential { pub type StakeCredential = Credential; -impl StakeCredential { - pub fn to_stake_address(&self, network: AddressNetwork) -> StakeAddress { - let payload = match self { - StakeCredential::AddrKeyHash(hash) => StakeAddressPayload::StakeKeyHash( - hash.clone().try_into().expect("Invalid hash length"), - ), - StakeCredential::ScriptHash(hash) => StakeAddressPayload::ScriptHash( - hash.clone().try_into().expect("Invalid hash length"), - ), - }; - StakeAddress::new(payload, network) - } -} - /// Relay single host address #[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] pub struct SingleHostAddr { @@ -887,7 +873,7 @@ pub enum InstantaneousRewardSource { /// Target of a MIR #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum InstantaneousRewardTarget { - StakeCredentials(Vec<(StakeCredential, i64)>), + StakeAddresses(Vec<(StakeAddress, i64)>), OtherAccountingPot(u64), } diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 51010c9d..5dbb0278 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -14,7 +14,7 @@ use acropolis_common::{ protocol_params::ProtocolParams, stake_addresses::{StakeAddressMap, StakeAddressState}, BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, - InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, NetworkId, + InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, TxCertificate, }; @@ -95,9 +95,6 @@ pub struct State { /// List of SPOs (by operator ID) retiring in the current epoch retiring_spos: Vec, - /// Network ID - network_id: NetworkId, - /// Map of staking address values /// Wrapped in an Arc so it doesn't get cloned in full by StateHistory stake_addresses: Arc>, @@ -549,13 +546,10 @@ impl State { }; match &mir.target { - InstantaneousRewardTarget::StakeCredentials(deltas) => { + InstantaneousRewardTarget::StakeAddresses(deltas) => { // Transfer to (in theory also from) stake addresses from (to) a pot let mut total_value: u64 = 0; - for (credential, value) in deltas.iter() { - let stake_address = - credential.to_stake_address(self.network_id.clone().into()); - + for (stake_address, value) in deltas.iter() { // Get old stake address state, or create one let mut stake_addresses = self.stake_addresses.lock().unwrap(); let sas = stake_addresses.entry(stake_address.clone()).or_default(); @@ -1217,7 +1211,6 @@ mod tests { fn mir_transfers_to_stake_addresses() { let mut state = State::default(); let stake_address = create_address(&STAKE_KEY_HASH); - let stake_credential = stake_address.get_credential(); // Bootstrap with some in reserves state.pots.reserves = 100; @@ -1244,9 +1237,9 @@ mod tests { // Send in a MIR reserves->{47,-5}->stake let mir = MoveInstantaneousReward { source: InstantaneousRewardSource::Reserves, - target: InstantaneousRewardTarget::StakeCredentials(vec![ - (stake_credential.clone(), 47), - (stake_credential, -5), + target: InstantaneousRewardTarget::StakeAddresses(vec![ + (stake_address.clone(), 47), + (stake_address.clone(), -5), ]), }; @@ -1266,7 +1259,6 @@ mod tests { fn withdrawal_transfers_from_stake_addresses() { let mut state = State::default(); let stake_address = create_address(&STAKE_KEY_HASH); - let stake_credential = stake_address.get_credential(); // Bootstrap with some in reserves state.pots.reserves = 100; @@ -1294,7 +1286,7 @@ mod tests { // Send in a MIR reserves->42->stake let mir = MoveInstantaneousReward { source: InstantaneousRewardSource::Reserves, - target: InstantaneousRewardTarget::StakeCredentials(vec![(stake_credential, 42)]), + target: InstantaneousRewardTarget::StakeAddresses(vec![(stake_address.clone(), 42)]), }; state.handle_mir(&mir).unwrap(); diff --git a/modules/tx_unpacker/src/map_parameters.rs b/modules/tx_unpacker/src/map_parameters.rs index 74dfd557..1bd4f23f 100644 --- a/modules/tx_unpacker/src/map_parameters.rs +++ b/modules/tx_unpacker/src/map_parameters.rs @@ -314,10 +314,10 @@ pub fn map_certificate( }, target: match &mir.target { alonzo::InstantaneousRewardTarget::StakeCredentials(creds) => { - InstantaneousRewardTarget::StakeCredentials( + InstantaneousRewardTarget::StakeAddresses( creds .iter() - .map(|(sc, v)| (map_stake_credential(&sc), *v)) + .map(|(sc, v)| (map_stake_address(&sc, network_id.clone()), *v)) .collect(), ) } diff --git a/modules/upstream_chain_fetcher/src/utils.rs b/modules/upstream_chain_fetcher/src/utils.rs index 9ca3594c..dd3ee50b 100644 --- a/modules/upstream_chain_fetcher/src/utils.rs +++ b/modules/upstream_chain_fetcher/src/utils.rs @@ -19,7 +19,6 @@ const DEFAULT_GENESIS_COMPLETION_TOPIC: (&str, &str) = const DEFAULT_NODE_ADDRESS: (&str, &str) = ("node-address", "backbone.cardano.iog.io:3001"); const DEFAULT_MAGIC_NUMBER: (&str, u64) = ("magic-number", 764824073); -const DEFAULT_NETWORK_ID: (&str, &str) = ("network-id", "mainnet"); const DEFAULT_SYNC_POINT: (&str, SyncPoint) = ("sync-point", SyncPoint::Snapshot); const DEFAULT_CACHE_DIR: (&str, &str) = ("cache-dir", "upstream-cache"); @@ -50,7 +49,6 @@ pub struct FetcherConfig { pub genesis_completion_topic: String, pub node_address: String, pub magic_number: u64, - pub network_id: String, pub cache_dir: String, pub genesis_values: Option, @@ -110,9 +108,6 @@ impl FetcherConfig { magic_number: config .get::(DEFAULT_MAGIC_NUMBER.0) .unwrap_or(DEFAULT_MAGIC_NUMBER.1), - network_id: config - .get_string(DEFAULT_NETWORK_ID.0) - .unwrap_or(DEFAULT_NETWORK_ID.1.to_string()), node_address: Self::conf(&config, DEFAULT_NODE_ADDRESS), cache_dir: Self::conf(&config, DEFAULT_CACHE_DIR), genesis_values: Self::conf_genesis(&config), @@ -145,8 +140,8 @@ pub async fn publish_message(cfg: Arc, record: &UpstreamCacheReco pub async fn peer_connect(cfg: Arc, role: &str) -> Result> { info!( - "Connecting {role} to {} ({})-({}) ...", - cfg.node_address, cfg.network_id, cfg.magic_number + "Connecting {role} to {} ({}) ...", + cfg.node_address, cfg.magic_number ); match PeerClient::connect(cfg.node_address.clone(), cfg.magic_number).await { @@ -161,9 +156,8 @@ pub async fn peer_connect(cfg: Arc, role: &str) -> Result bail!( - "Cannot connect {role} to {} ({})-({}): {e}", + "Cannot connect {role} to {} ({}): {e}", cfg.node_address, - cfg.network_id, cfg.magic_number ), } From 39e0f1375e9b5c1077451f88ca41f032084675fc Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 22 Oct 2025 14:19:33 -0700 Subject: [PATCH 4/4] Refactor: Standardize variable names (e.g., `cred` -> `delegator`) for clarity. --- common/src/state_history.rs | 2 +- common/src/types.rs | 1 - modules/drep_state/src/state.rs | 11 +++++------ .../src/handlers/governance.rs | 19 ++++++++++++++----- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/common/src/state_history.rs b/common/src/state_history.rs index c8cf2979..9e19a4c7 100644 --- a/common/src/state_history.rs +++ b/common/src/state_history.rs @@ -54,7 +54,7 @@ impl StateHistory { /// Get the current state assuming any rollback has been done /// Cloned for modification - call commit() when done - pub fn get_current_state(&self) -> S { + pub fn get_current_state(&self) -> S { self.history.back().map(|entry| entry.state.clone()).unwrap_or_default() } diff --git a/common/src/types.rs b/common/src/types.rs index 40cbb38f..c1708627 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -6,7 +6,6 @@ use crate::{ address::{Address, ShelleyAddress, StakeAddress}, protocol_params, rational_number::RationalNumber, - AddressNetwork, StakeAddressPayload, }; use anyhow::{anyhow, bail, Error, Result}; use bech32::{Bech32, Hrp}; diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index db7a89b1..a97ded4e 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -228,10 +228,10 @@ impl State { for tx_cert in tx_certs { if store_delegators { - if let Some((cred, drep)) = + if let Some((delegator, drep)) = Self::extract_delegation_fields(tx_cert) { - batched_delegators.push((cred, drep)); + batched_delegators.push((delegator, drep)); continue; } } @@ -477,9 +477,8 @@ impl State { delegators: Vec<(StakeAddress, &DRepChoice)>, ) -> Result<()> { let stake_addresses = delegators.iter().map(|(addr, _)| (addr).clone()).collect(); - let stake_key_to_input: HashMap = - delegators.iter().map(|(addr, drep)| (addr.get_hash().to_vec(), (addr, *drep))).collect(); + delegators.iter().map(|(addr, drep)| (addr.get_credential().get_hash(), (addr, *drep))).collect(); let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsDrepDelegationsMap { stake_addresses }, @@ -515,7 +514,7 @@ impl State { if old_drep_cred != new_drep_cred { self.update_historical(&old_drep_cred, false, |entry| { if let Some(delegators) = entry.delegators.as_mut() { - delegators.retain(|s| s.to_binary() != delegator.to_binary()); + delegators.retain(|s| s != delegator); } })?; } @@ -525,7 +524,7 @@ impl State { // Add delegator to new DRep match self.update_historical(&new_drep_cred, true, |entry| { if let Some(delegators) = entry.delegators.as_mut() { - if !delegators.contains(&delegator) { + if !delegators.contains(delegator) { delegators.push(delegator.clone()); } } diff --git a/modules/rest_blockfrost/src/handlers/governance.rs b/modules/rest_blockfrost/src/handlers/governance.rs index 241fb5e4..13beff49 100644 --- a/modules/rest_blockfrost/src/handlers/governance.rs +++ b/modules/rest_blockfrost/src/handlers/governance.rs @@ -191,18 +191,27 @@ pub async fn handle_drep_delegators_blockfrost( Message::StateQueryResponse(StateQueryResponse::Governance( GovernanceStateQueryResponse::DRepDelegators(delegators), )) => { - let stake_key_to_bech32: HashMap = delegators + let stake_key_to_bech32: HashMap = match delegators .addresses .iter() .map(|addr| { - let bech32 = addr - .get_credential() + let credential = addr.get_credential(); + let bech32 = credential .to_stake_bech32() .map_err(|_| anyhow!("Failed to encode stake address"))?; - let key_hash = addr.get_hash().to_vec(); + let key_hash = credential.get_hash(); Ok((key_hash, bech32)) }) - .collect::>>()?; + .collect::>>() + { + Ok(map) => map, + Err(e) => { + return Ok(RESTResponse::with_text( + 500, + &format!("Internal error: {e}"), + )); + } + }; let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetAccountsUtxoValuesMap {