From fb6432bc2c31e1974442dfe1e319774861c8361f Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Mon, 27 Oct 2025 11:44:32 -0700 Subject: [PATCH 01/20] Refactor: Replace `Vec` with `KeyHash` and introduce type-safe `Hash` utility across modules. Includes updates for serialization, type conversions, and tests. --- codec/src/map_parameters.rs | 61 ++-- common/src/address.rs | 119 ++++---- common/src/byte_array.rs | 178 +++++------ common/src/crypto.rs | 5 +- common/src/hash.rs | 277 +++++++++++++++++- common/src/queries/accounts.rs | 8 +- common/src/snapshot/streaming_snapshot.rs | 33 ++- common/src/stake_addresses.rs | 262 ++++++++--------- common/src/types.rs | 68 +++-- .../src/spo_distribution_store.rs | 48 +-- modules/drep_state/src/state.rs | 4 +- modules/governance_state/src/state.rs | 6 +- modules/stake_delta_filter/src/utils.rs | 10 +- 13 files changed, 684 insertions(+), 395 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index b46d5c69..150276c9 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -18,6 +18,7 @@ use acropolis_common::{ *, }; use std::collections::{HashMap, HashSet}; +use acropolis_common::snapshot::streaming_snapshot::PoolId; /// Map Pallas Network to our NetworkId pub fn map_network(network: addresses::Network) -> Result { @@ -70,8 +71,8 @@ pub fn map_address(address: &addresses::Address) -> Result
{ addresses::Address::Stake(stake_address) => Ok(Address::Stake(StakeAddress { network: map_network(stake_address.network())?, credential: match stake_address.payload() { - addresses::StakePayload::Stake(hash) => StakeCredential::AddrKeyHash(hash.to_vec()), - addresses::StakePayload::Script(hash) => StakeCredential::ScriptHash(hash.to_vec()), + addresses::StakePayload::Stake(hash) => StakeCredential::AddrKeyHash(hash), + addresses::StakePayload::Script(hash) => StakeCredential::ScriptHash(hash), }, })), } @@ -81,10 +82,10 @@ pub fn map_address(address: &addresses::Address) -> Result
{ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(key_hash.to_vec()) + StakeCredential::AddrKeyHash(key_hash) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(script_hash.to_vec()) + StakeCredential::ScriptHash(script_hash) } } } @@ -93,10 +94,10 @@ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> StakeAddress { let payload = match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(key_hash.to_vec()) + StakeCredential::AddrKeyHash(key_hash) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(script_hash.to_vec()) + StakeCredential::ScriptHash(script_hash) } }; @@ -106,8 +107,8 @@ pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> /// Map a Pallas DRep to our DRepChoice pub fn map_drep(drep: &conway::DRep) -> DRepChoice { match drep { - conway::DRep::Key(key_hash) => DRepChoice::Key(key_hash.to_vec()), - conway::DRep::Script(script_hash) => DRepChoice::Script(script_hash.to_vec()), + conway::DRep::Key(key_hash) => DRepChoice::Key(key_hash), + conway::DRep::Script(script_hash) => DRepChoice::Script(script_hash), conway::DRep::Abstain => DRepChoice::Abstain, conway::DRep::NoConfidence => DRepChoice::NoConfidence, } @@ -169,7 +170,7 @@ pub fn map_nullable_gov_action_id( fn map_constitution(constitution: &conway::Constitution) -> Constitution { Constitution { anchor: map_anchor(&constitution.anchor), - guardrail_script: map_nullable(|x| x.to_vec(), &constitution.guardrail_script), + guardrail_script: map_nullable(|x| x, &constitution.guardrail_script), } } @@ -232,7 +233,7 @@ pub fn map_certificate( alonzo::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: pool_key_hash, })) } alonzo::Certificate::PoolRegistration { @@ -248,8 +249,8 @@ pub fn map_certificate( } => Ok(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { reg: PoolRegistration { - operator: operator.to_vec(), - vrf_key_hash: vrf_keyhash.to_vec(), + operator: operator, + vrf_key_hash: vrf_keyhash, pledge: *pledge, cost: *cost, margin: Ratio { @@ -261,7 +262,7 @@ pub fn map_certificate( .iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v.to_vec()), + StakeCredential::AddrKeyHash(v), network_id.clone().into(), ) }) @@ -282,7 +283,7 @@ pub fn map_certificate( alonzo::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok( TxCertificate::PoolRetirementWithPos(PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: pool_key_hash, epoch: *epoch, }, tx_hash, @@ -294,9 +295,9 @@ pub fn map_certificate( genesis_delegate_hash, vrf_key_hash, ) => Ok(TxCertificate::GenesisKeyDelegation(GenesisKeyDelegation { - genesis_hash: genesis_hash.to_vec(), - genesis_delegate_hash: genesis_delegate_hash.to_vec(), - vrf_key_hash: vrf_key_hash.to_vec(), + genesis_hash: genesis_hash, + genesis_delegate_hash: genesis_delegate_hash, + vrf_key_hash: vrf_key_hash, })), alonzo::Certificate::MoveInstantaneousRewardsCert(mir) => Ok( TxCertificate::MoveInstantaneousReward(MoveInstantaneousReward { @@ -341,7 +342,7 @@ pub fn map_certificate( conway::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: PoolId::from(pool_key_hash) })) } conway::Certificate::PoolRegistration { @@ -358,8 +359,8 @@ pub fn map_certificate( } => Ok(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { reg: PoolRegistration { - operator: operator.to_vec(), - vrf_key_hash: vrf_keyhash.to_vec(), + operator: operator, + vrf_key_hash: vrf_keyhash, pledge: *pledge, cost: *cost, margin: Ratio { @@ -371,7 +372,7 @@ pub fn map_certificate( .into_iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v.to_vec()), + StakeCredential::AddrKeyHash(v), network_id.clone().into(), ) }) @@ -392,7 +393,7 @@ pub fn map_certificate( conway::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok( TxCertificate::PoolRetirementWithPos(PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: pool_key_hash.into(), epoch: *epoch, }, tx_hash, @@ -424,7 +425,7 @@ pub fn map_certificate( conway::Certificate::StakeVoteDeleg(cred, pool_key_hash, drep) => Ok( TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: pool_key_hash, drep: map_drep(drep), }), ), @@ -432,7 +433,7 @@ pub fn map_certificate( conway::Certificate::StakeRegDeleg(cred, pool_key_hash, coin) => Ok( TxCertificate::StakeRegistrationAndDelegation(StakeRegistrationAndDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: pool_key_hash, deposit: *coin, }), ), @@ -451,7 +452,7 @@ pub fn map_certificate( Ok(TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: pool_key_hash, drep: map_drep(drep), deposit: *coin, }, @@ -841,14 +842,14 @@ pub fn map_governance_proposals_procedures( fn map_voter(voter: &conway::Voter) -> Voter { match voter { conway::Voter::ConstitutionalCommitteeKey(key_hash) => { - Voter::ConstitutionalCommitteeKey(key_hash.to_vec()) + Voter::ConstitutionalCommitteeKey(key_hash) } conway::Voter::ConstitutionalCommitteeScript(script_hash) => { - Voter::ConstitutionalCommitteeScript(script_hash.to_vec()) + Voter::ConstitutionalCommitteeScript(script_hash) } - conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(addr_key_hash.to_vec()), - conway::Voter::DRepScript(script_hash) => Voter::DRepScript(script_hash.to_vec()), - conway::Voter::StakePoolKey(key_hash) => Voter::StakePoolKey(key_hash.to_vec()), + conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(addr_key_hash), + conway::Voter::DRepScript(script_hash) => Voter::DRepScript(script_hash), + conway::Voter::StakePoolKey(key_hash) => Voter::StakePoolKey(key_hash), } } diff --git a/common/src/address.rs b/common/src/address.rs index 7c5e6b3a..a5eb161e 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -3,8 +3,7 @@ #![allow(dead_code)] use crate::cip19::{VarIntDecoder, VarIntEncoder}; -use crate::types::{KeyHash, ScriptHash}; -use crate::{Credential, NetworkId, StakeCredential}; +use crate::{Credential, KeyHash, NetworkId, StakeCredential}; use anyhow::{anyhow, bail, Result}; use crc::{Crc, CRC_32_ISO_HDLC}; use minicbor::data::IanaTag; @@ -101,12 +100,12 @@ pub enum ShelleyAddressPaymentPart { /// Payment to a script #[n(1)] - ScriptHash(#[n(0)] ScriptHash), + ScriptHash(#[n(0)] KeyHash), } impl Default for ShelleyAddressPaymentPart { fn default() -> Self { - Self::PaymentKeyHash(Vec::new()) + Self::PaymentKeyHash(KeyHash::new([0u8; 28])) } } @@ -156,11 +155,11 @@ pub enum ShelleyAddressDelegationPart { /// Delegation to stake key #[n(1)] - StakeKeyHash(#[n(0)] Vec), + StakeKeyHash(#[n(0)] KeyHash), /// Delegation to script key hash #[n(2)] - ScriptHash(#[n(0)] ScriptHash), + ScriptHash(#[n(0)] KeyHash), /// Delegation to pointer #[n(3)] @@ -213,14 +212,22 @@ impl ShelleyAddress { let header = *header; let payment_part = match (header >> 4) & 0x01 { - 0 => ShelleyAddressPaymentPart::PaymentKeyHash(data[1..29].to_vec()), - 1 => ShelleyAddressPaymentPart::ScriptHash(data[1..29].to_vec()), + 0 => ShelleyAddressPaymentPart::PaymentKeyHash( + data[1..29].try_into().map_err(|_| anyhow!("Invalid payment key hash size"))? + ), + 1 => ShelleyAddressPaymentPart::ScriptHash( + data[1..29].try_into().map_err(|_| anyhow!("Invalid script hash size"))? + ), _ => panic!(), }; let delegation_part = match (header >> 5) & 0x03 { - 0 => ShelleyAddressDelegationPart::StakeKeyHash(data[29..57].to_vec()), - 1 => ShelleyAddressDelegationPart::ScriptHash(data[29..57].to_vec()), + 0 => ShelleyAddressDelegationPart::StakeKeyHash( + data[29..57].try_into().map_err(|_| anyhow!("Invalid stake key hash size"))? + ), + 1 => ShelleyAddressDelegationPart::ScriptHash( + data[29..57].try_into().map_err(|_| anyhow!("Invalid delegation script hash size"))? + ), 2 => { let mut decoder = VarIntDecoder::new(&data[29..]); let slot = decoder.read()?; @@ -254,27 +261,27 @@ impl ShelleyAddress { NetworkId::Testnet => (bech32::Hrp::parse("addr_test")?, 0u8), }; - let (payment_hash, payment_bits): (&Vec, u8) = match &self.payment { + let (payment_hash, payment_bits): (&KeyHash, u8) = match &self.payment { ShelleyAddressPaymentPart::PaymentKeyHash(data) => (data, 0), ShelleyAddressPaymentPart::ScriptHash(data) => (data, 1), }; - let (delegation_hash, delegation_bits): (&Vec, u8) = match &self.delegation { - ShelleyAddressDelegationPart::None => (&Vec::new(), 3), - ShelleyAddressDelegationPart::StakeKeyHash(hash) => (hash, 0), - ShelleyAddressDelegationPart::ScriptHash(hash) => (hash, 1), + let (delegation_hash, delegation_bits): (Vec, u8) = match &self.delegation { + ShelleyAddressDelegationPart::None => (Vec::new(), 3), + ShelleyAddressDelegationPart::StakeKeyHash(hash) => (hash.to_vec(), 0), + ShelleyAddressDelegationPart::ScriptHash(hash) => (hash.to_vec(), 1), ShelleyAddressDelegationPart::Pointer(pointer) => { let mut encoder = VarIntEncoder::new(); encoder.push(pointer.slot); encoder.push(pointer.tx_index); encoder.push(pointer.cert_index); - (&encoder.to_vec(), 2) + (encoder.to_vec(), 2) } }; let mut data = vec![network_bits | (payment_bits << 4) | (delegation_bits << 5)]; - data.extend(payment_hash); - data.extend(delegation_hash); + data.extend(payment_hash.as_ref()); + data.extend(&delegation_hash); Ok(bech32::encode::(hrp, &data)?) } @@ -284,7 +291,7 @@ impl ShelleyAddress { NetworkId::Testnet => 0u8, }; - let (payment_hash, payment_bits): (&Vec, u8) = match &self.payment { + let (payment_hash, payment_bits): (&KeyHash, u8) = match &self.payment { ShelleyAddressPaymentPart::PaymentKeyHash(data) => (data, 0), ShelleyAddressPaymentPart::ScriptHash(data) => (data, 1), }; @@ -298,24 +305,24 @@ impl ShelleyAddress { ShelleyAddressDelegationPart::None => { let header = build_header(3); data.push(header); - data.extend(payment_hash); + data.extend(payment_hash.as_ref()); } ShelleyAddressDelegationPart::StakeKeyHash(hash) => { let header = build_header(0); data.push(header); - data.extend(payment_hash); - data.extend(hash); + data.extend(payment_hash.as_ref()); + data.extend(hash.as_ref()); } ShelleyAddressDelegationPart::ScriptHash(hash) => { let header = build_header(1); data.push(header); - data.extend(payment_hash); - data.extend(hash); + data.extend(payment_hash.as_ref()); + data.extend(hash.as_ref()); } ShelleyAddressDelegationPart::Pointer(pointer) => { let header = build_header(2); data.push(header); - data.extend(payment_hash); + data.extend(payment_hash.as_ref()); let mut encoder = VarIntEncoder::new(); encoder.push(pointer.slot); @@ -338,14 +345,14 @@ impl ShelleyAddress { ShelleyAddressDelegationPart::StakeKeyHash(key_hash) => { let mut data = Vec::with_capacity(29); data.push(network_bit | (0b1110 << 4)); - data.extend_from_slice(key_hash); + data.extend_from_slice(key_hash.as_ref()); let stake = StakeAddress::from_binary(&data)?.to_string()?; Ok(Some(stake)) } ShelleyAddressDelegationPart::ScriptHash(script_hash) => { let mut data = Vec::with_capacity(29); data.push(network_bit | (0b1111 << 4)); - data.extend_from_slice(script_hash); + data.extend_from_slice(script_hash.as_ref()); let stake = StakeAddress::from_binary(&data)?.to_string()?; Ok(Some(stake)) } @@ -363,7 +370,7 @@ pub struct StakeAddress { pub network: NetworkId, /// Credential - pub credential: StakeCredential, // payload: StakePayload? + pub credential: StakeCredential, } impl StakeAddress { @@ -374,7 +381,7 @@ impl StakeAddress { } } - pub fn get_hash(&self) -> &[u8] { + pub fn get_hash(&self) -> &KeyHash { match &self.credential { StakeCredential::AddrKeyHash(hash) => hash, StakeCredential::ScriptHash(hash) => hash, @@ -395,8 +402,8 @@ impl StakeAddress { NetworkId::Testnet => bech32::Hrp::parse("stake_test")?, }; - let data = self.to_binary(); - Ok(bech32::encode::(hrp, &data)?) + let data = self.to_binary()?; + Ok(bech32::encode::(hrp, &data.as_slice())?) } /// Read from a string format ("stake1xxx...") @@ -409,8 +416,8 @@ impl StakeAddress { }; let credential = match (header >> 4) & 0x0Fu8 { - 0b1110 => StakeCredential::AddrKeyHash(data[1..].to_vec()), - 0b1111 => StakeCredential::ScriptHash(data[1..].to_vec()), + 0b1110 => StakeCredential::AddrKeyHash(data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?), + 0b1111 => StakeCredential::ScriptHash(data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?), _ => return Err(anyhow!("Unknown header {header} in stake address")), }; @@ -424,22 +431,23 @@ impl StakeAddress { } /// Convert to binary format (29 bytes) - pub fn to_binary(&self) -> Vec { + pub fn to_binary(&self) -> Result { let network_bits = match self.network { NetworkId::Mainnet => 0b1u8, NetworkId::Testnet => 0b0u8, }; - let (stake_bits, stake_hash): (u8, &Vec) = match &self.credential { + let (stake_bits, stake_hash): (u8, &KeyHash) = match &self.credential { StakeCredential::AddrKeyHash(data) => (0b1110, data), StakeCredential::ScriptHash(data) => (0b1111, data), }; let mut data = vec![network_bits | (stake_bits << 4)]; - data.extend(stake_hash); - data + data.extend(stake_hash.as_ref()); + data.try_into().map_err(|_| anyhow!("Invalid hash size for stake address")) } + /// Read from binary format (29 bytes) pub fn from_binary(data: &[u8]) -> Result { if data.len() != 29 { @@ -452,8 +460,8 @@ impl StakeAddress { }; let credential = match (data[0] >> 4) & 0x0F { - 0b1110 => StakeCredential::AddrKeyHash(data[1..].to_vec()), - 0b1111 => StakeCredential::ScriptHash(data[1..].to_vec()), + 0b1110 => StakeCredential::AddrKeyHash(data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?), + 0b1111 => StakeCredential::ScriptHash(data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?), _ => bail!("Unknown header byte {:x} in stake address", data[0]), }; @@ -466,8 +474,8 @@ impl StakeAddress { pub fn to_bytes_key(&self) -> Result> { let mut out = Vec::new(); let (bits, hash): (u8, &[u8]) = match &self.credential { - StakeCredential::AddrKeyHash(h) => (0b1110, h), - StakeCredential::ScriptHash(h) => (0b1111, h), + StakeCredential::AddrKeyHash(h) => (0b1110, h.as_slice()), + StakeCredential::ScriptHash(h) => (0b1111, h.as_slice()), }; let net_bit = match self.network { @@ -494,7 +502,8 @@ impl minicbor::Encode for StakeAddress { e: &mut minicbor::Encoder, _ctx: &mut C, ) -> Result<(), minicbor::encode::Error> { - e.bytes(&self.to_binary())?; + let data = self.to_binary().map_err(|_| minicbor::encode::Error::message("Failed to convert to binary"))?; + e.bytes(&data.as_slice())?; Ok(()) } } @@ -514,7 +523,7 @@ impl Default for StakeAddress { fn default() -> Self { StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(vec![0u8; 28]), + credential: StakeCredential::AddrKeyHash(KeyHash::new([0u8; 28])), } } } @@ -640,32 +649,32 @@ mod tests { } // Standard keys from CIP-19 - fn test_payment_key_hash() -> Vec { + fn test_payment_key_hash() -> KeyHash { let payment_key = "addr_vk1w0l2sr2zgfm26ztc6nl9xy8ghsk5sh6ldwemlpmp9xylzy4dtf7st80zhd"; let (_, pubkey) = bech32::decode(payment_key).expect("Invalid Bech32 string"); // pubkey is the raw key - we need the Blake2B hash let hash = keyhash_224(&pubkey); assert_eq!(28, hash.len()); - hash + hash.as_slice().try_into().expect("Invalid hash size") } - fn test_stake_key_hash() -> Vec { + fn test_stake_key_hash() -> KeyHash { let stake_key = "stake_vk1px4j0r2fk7ux5p23shz8f3y5y2qam7s954rgf3lg5merqcj6aetsft99wu"; let (_, pubkey) = bech32::decode(stake_key).expect("Invalid Bech32 string"); // pubkey is the raw key - we need the Blake2B hash let hash = keyhash_224(&pubkey); assert_eq!(28, hash.len()); - hash + hash.as_slice().try_into().expect("Invalid hash size") } - fn test_script_hash() -> Vec { + fn test_script_hash() -> KeyHash { let script_hash = "script1cda3khwqv60360rp5m7akt50m6ttapacs8rqhn5w342z7r35m37"; let (_, hash) = bech32::decode(script_hash).expect("Invalid Bech32 string"); // This is already a hash assert_eq!(28, hash.len()); - hash + hash.as_slice().try_into().expect("Invalid hash size") } fn test_pointer() -> ShelleyAddressPointer { @@ -813,7 +822,7 @@ mod tests { fn shelley_type_14() { let address = Address::Stake(StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(test_stake_key_hash()), + credential: StakeCredential::AddrKeyHash(KeyHash::from(test_stake_key_hash())) }); let text = address.to_string().unwrap(); @@ -830,7 +839,7 @@ mod tests { fn shelley_type_15() { let address = Address::Stake(StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::ScriptHash(test_script_hash()), + credential: StakeCredential::ScriptHash(KeyHash::from(test_script_hash())), }); let text = address.to_string().unwrap(); @@ -930,14 +939,14 @@ mod tests { #[test] fn stake_addresses_encode_mainnet_stake() { let address = mainnet_stake_address(); - let binary = address.to_binary(); + let binary = address.to_binary().unwrap(); // CBOR encoding wraps the raw 29-byte stake address in a byte string: // - 0x58: CBOR major type 2 (byte string) with 1-byte length follows // - 0x1d: Length of 29 bytes (the stake address data) // - [29 bytes]: The actual stake address (network header + 28-byte hash) // Total: 31 bytes (2-byte CBOR framing + 29-byte payload) - let expected = [[0x58, 0x1d].as_slice(), &binary].concat(); + let expected = [[0x58, 0x1d].as_slice(), &binary.as_slice()].concat(); let mut actual = Vec::new(); let mut encoder = minicbor::Encoder::new(&mut actual); @@ -951,7 +960,7 @@ mod tests { fn stake_addresses_decode_mainnet_stake() { let binary = { let mut v = vec![0x58, 0x1d]; - v.extend_from_slice(&mainnet_stake_address().to_binary()); + v.extend_from_slice(&mainnet_stake_address().to_binary().unwrap().as_slice()); v }; @@ -1020,4 +1029,4 @@ mod tests { let result = StakeAddress::decode(&mut decoder, &mut ()); assert!(result.is_err()); } -} +} \ No newline at end of file diff --git a/common/src/byte_array.rs b/common/src/byte_array.rs index 048a6849..36524c61 100644 --- a/common/src/byte_array.rs +++ b/common/src/byte_array.rs @@ -1,89 +1,89 @@ -use crate::serialization::{Bech32Conversion, Bech32WithHrp}; -use anyhow::Error; -use hex::{FromHex, FromHexError}; -use serde_with::{hex::Hex, serde_as}; -use std::ops::Deref; - -macro_rules! declare_byte_array_type { - ($name:ident, $size:expr) => { - /// $name - #[serde_as] - #[derive( - Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, - )] - pub struct $name(#[serde_as(as = "Hex")] pub [u8; $size]); - - impl From<[u8; $size]> for $name { - fn from(bytes: [u8; $size]) -> Self { - Self(bytes) - } - } - - impl FromHex for $name { - type Error = FromHexError; - - fn from_hex>(hex: T) -> Result { - match Self::try_from(Vec::::from_hex(hex)?) { - Ok(b) => Ok(b), - Err(_) => Err(FromHexError::InvalidStringLength), - } - } - } - - impl TryFrom> for $name { - type Error = Vec; - fn try_from(vec: Vec) -> Result { - Ok($name(vec.try_into()?)) - } - } - - impl TryFrom<&[u8]> for $name { - type Error = std::array::TryFromSliceError; - fn try_from(arr: &[u8]) -> Result { - Ok($name(arr.try_into()?)) - } - } - - impl AsRef<[u8]> for $name { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl Deref for $name { - type Target = [u8; $size]; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - }; -} - -macro_rules! declare_byte_array_type_with_bech32 { - ($name:ident, $size:expr, $hrp:expr) => { - declare_byte_array_type!($name, $size); - impl Bech32Conversion for $name { - fn to_bech32(&self) -> Result { - self.0.to_vec().to_bech32_with_hrp($hrp) - } - fn from_bech32(s: &str) -> Result { - match Vec::::from_bech32_with_hrp(s, $hrp) { - Ok(v) => match Self::try_from(v) { - Ok(s) => Ok(s), - Err(_) => Err(Error::msg(format!( - "Bad vector input to {}", - stringify!($name) - ))), - }, - Err(e) => Err(e), - } - } - } - }; -} - -declare_byte_array_type!(BlockHash, 32); - -declare_byte_array_type!(TxHash, 32); - -declare_byte_array_type_with_bech32!(VRFKey, 32, "vrf_vk"); +// use crate::serialization::{Bech32Conversion, Bech32WithHrp}; +// use anyhow::Error; +// use hex::{FromHex, FromHexError}; +// use serde_with::{hex::Hex, serde_as}; +// use std::ops::Deref; +// +// macro_rules! declare_byte_array_type { +// ($name:ident, $size:expr) => { +// /// $name +// #[serde_as] +// #[derive( +// Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, +// )] +// pub struct $name(#[serde_as(as = "Hex")] pub [u8; $size]); +// +// impl From<[u8; $size]> for $name { +// fn from(bytes: [u8; $size]) -> Self { +// Self(bytes) +// } +// } +// +// impl FromHex for $name { +// type Error = FromHexError; +// +// fn from_hex>(hex: T) -> Result { +// match Self::try_from(Vec::::from_hex(hex)?) { +// Ok(b) => Ok(b), +// Err(_) => Err(FromHexError::InvalidStringLength), +// } +// } +// } +// +// impl TryFrom> for $name { +// type Error = Vec; +// fn try_from(vec: Vec) -> Result { +// Ok($name(vec.try_into()?)) +// } +// } +// +// impl TryFrom<&[u8]> for $name { +// type Error = std::array::TryFromSliceError; +// fn try_from(arr: &[u8]) -> Result { +// Ok($name(arr.try_into()?)) +// } +// } +// +// impl AsRef<[u8]> for $name { +// fn as_ref(&self) -> &[u8] { +// &self.0 +// } +// } +// +// impl Deref for $name { +// type Target = [u8; $size]; +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } +// }; +// } +// +// macro_rules! declare_byte_array_type_with_bech32 { +// ($name:ident, $size:expr, $hrp:expr) => { +// declare_byte_array_type!($name, $size); +// impl Bech32Conversion for $name { +// fn to_bech32(&self) -> Result { +// self.0.to_vec().to_bech32_with_hrp($hrp) +// } +// fn from_bech32(s: &str) -> Result { +// match Vec::::from_bech32_with_hrp(s, $hrp) { +// Ok(v) => match Self::try_from(v) { +// Ok(s) => Ok(s), +// Err(_) => Err(Error::msg(format!( +// "Bad vector input to {}", +// stringify!($name) +// ))), +// }, +// Err(e) => Err(e), +// } +// } +// } +// }; +// } +// +// // declare_byte_array_type!(BlockHash, 32); +// // +// // declare_byte_array_type!(TxHash, 32); +// // +// // declare_byte_array_type_with_bech32!(VRFKey, 32, "vrf_vk"); diff --git a/common/src/crypto.rs b/common/src/crypto.rs index 0e66038e..7e301c66 100644 --- a/common/src/crypto.rs +++ b/common/src/crypto.rs @@ -1,17 +1,16 @@ //! Common cryptography helper functions for Acropolis -use crate::types::KeyHash; use cryptoxide::hashing::blake2b::Blake2b; /// Get a Blake2b-256 hash of a key -pub fn keyhash_256(key: &[u8]) -> KeyHash { +pub fn keyhash_256(key: &[u8]) -> Vec { let mut context = Blake2b::<256>::new(); context.update_mut(key); context.finalize().to_vec() } /// Get a Blake2b-224 hash of a key -pub fn keyhash_224(key: &[u8]) -> KeyHash { +pub fn keyhash_224(key: &[u8]) -> Vec { let mut context = Blake2b::<224>::new(); context.update_mut(key); context.finalize().to_vec() diff --git a/common/src/hash.rs b/common/src/hash.rs index ab22e961..533c65df 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -1,13 +1,45 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{fmt, ops::Deref, str::FromStr}; -/// data that is a cryptographic [`struct@Hash`] of `BYTES` long. +/// Data that is a cryptographic hash of `BYTES` long. /// -/// Possible values with Cardano are 32 bytes long (block hash or transaction -/// hash). Or 28 bytes long (as used in addresses) +/// This is a generic wrapper around a fixed-size byte array that provides: +/// - Hexadecimal serialization/deserialization +/// - CBOR encoding/decoding via minicbor +/// - Type-safe conversions from various byte representations +/// - Display and debug formatting +/// +/// # Common Hash Sizes in Cardano +/// +/// - **32 bytes**: Block hashes, transaction hashes +/// - **28 bytes**: Script hashes, address key hashes +/// +/// # Examples +/// +/// ``` +/// use your_crate::Hash; +/// +/// // Parse from hex string +/// let hash: Hash<32> = "0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21" +/// .parse() +/// .unwrap(); +/// +/// // Create from byte array +/// let bytes = [0u8; 28]; +/// let hash = Hash::new(bytes); +/// +/// // Convert to hex string +/// let hex_string = hash.to_string(); +/// ``` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Hash([u8; BYTES]); +impl Default for Hash { + fn default() -> Self { + Self::new([0u8; BYTES]) + } +} + // Implement Serialize/Deserialize manually since generic const arrays don't auto-derive impl Serialize for Hash { fn serialize(&self, serializer: S) -> Result @@ -28,15 +60,53 @@ impl<'de, const BYTES: usize> Deserialize<'de> for Hash { } } -// Type aliases for common hash sizes -pub type ScriptHash = Hash<28>; -pub type AddrKeyhash = Hash<28>; - impl Hash { + /// Creates a new hash from a byte array. + /// + /// This is a const function, allowing hashes to be created at compile time. + /// + /// # Examples + /// + /// ``` + /// use your_crate::Hash; + /// + /// const MY_HASH: Hash<32> = Hash::new([0u8; 32]); + /// ``` #[inline] pub const fn new(bytes: [u8; BYTES]) -> Self { Self(bytes) } + + /// Converts the hash to a `Vec`. + /// + /// # Examples + /// + /// ``` + /// use your_crate::Hash; + /// + /// let hash = Hash::new([1u8; 28]); + /// let vec = hash.to_vec(); + /// assert_eq!(vec.len(), 28); + /// ``` + #[inline] + pub fn to_vec(&self) -> Vec { + self.0.to_vec() + } + + /// Consumes the hash and returns the inner byte array. + /// + /// # Examples + /// + /// ``` + /// use your_crate::Hash; + /// + /// let hash = Hash::new([1u8; 28]); + /// let bytes: [u8; 28] = hash.into_inner(); + /// ``` + #[inline] + pub fn into_inner(self) -> [u8; BYTES] { + self.0 + } } impl From<[u8; BYTES]> for Hash { @@ -46,11 +116,43 @@ impl From<[u8; BYTES]> for Hash { } } -impl From<&[u8]> for Hash { - fn from(value: &[u8]) -> Self { - let mut hash = [0; BYTES]; - hash.copy_from_slice(value); - Self::new(hash) +impl TryFrom<&[u8]> for Hash { + type Error = std::array::TryFromSliceError; + + /// Attempts to create a hash from a byte slice. + /// + /// # Errors + /// + /// Returns an error if the slice length does not match `BYTES`. + fn try_from(value: &[u8]) -> Result { + let hash: [u8; BYTES] = value.try_into()?; + Ok(Self::new(hash)) + } +} + +impl TryFrom> for Hash { + type Error = Vec; + + /// Attempts to create a hash from a `Vec`. + /// + /// # Errors + /// + /// Returns the original vector if its length does not match `BYTES`. + fn try_from(value: Vec) -> Result { + let hash: [u8; BYTES] = value.try_into()?; + Ok(Self::new(hash)) + } +} + +impl From> for Vec { + fn from(hash: Hash) -> Self { + hash.0.to_vec() + } +} + +impl From> for [u8; BYTES] { + fn from(hash: Hash) -> Self { + hash.0 } } @@ -83,6 +185,7 @@ impl fmt::Debug for Hash { } impl fmt::Display for Hash { + /// Formats the hash as a lowercase hexadecimal string. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&hex::encode(self)) } @@ -90,6 +193,24 @@ impl fmt::Display for Hash { impl FromStr for Hash { type Err = hex::FromHexError; + + /// Parses a hash from a hexadecimal string. + /// + /// # Errors + /// + /// Returns an error if: + /// - The string is not valid hexadecimal + /// - The decoded bytes do not match the expected length `BYTES` + /// + /// # Examples + /// + /// ``` + /// use your_crate::Hash; + /// + /// let hash: Hash<28> = "276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3" + /// .parse() + /// .unwrap(); + /// ``` fn from_str(s: &str) -> Result { let mut bytes = [0; BYTES]; hex::decode_to_slice(s, &mut bytes)?; @@ -97,6 +218,22 @@ impl FromStr for Hash { } } +impl hex::FromHex for Hash { + type Error = hex::FromHexError; + + /// Decodes a hash from hexadecimal bytes. + /// + /// # Errors + /// + /// Returns an error if the decoded length does not match `BYTES`. + fn from_hex>(hex: T) -> Result { + match Self::try_from(Vec::::from_hex(hex)?) { + Ok(h) => Ok(h), + Err(_) => Err(hex::FromHexError::InvalidStringLength), + } + } +} + impl minicbor::Encode for Hash { fn encode( &self, @@ -125,6 +262,93 @@ impl<'a, C, const BYTES: usize> minicbor::Decode<'a, C> for Hash { } } +// Type aliases for common hash sizes in Cardano +/// A 28-byte hash used for scripts in Cardano addresses. +pub type ScriptHash = Hash<28>; + +/// A 28-byte hash of an address key in Cardano. +pub type AddrKeyhash = Hash<28>; + +/// Declares a type alias for a hash with optional documentation. +/// +/// # Examples +/// +/// ``` +/// declare_hash_type!(BlockHash, 32); +/// declare_hash_type!(TxHash, 32); +/// ``` +#[macro_export] +macro_rules! declare_hash_type { + ($name:ident, $size:expr) => { + #[doc = concat!(stringify!($name), " - a ", stringify!($size), "-byte hash.")] + pub type $name = Hash<$size>; + }; + ($(#[$meta:meta])* $name:ident, $size:expr) => { + $(#[$meta])* + pub type $name = Hash<$size>; + }; +} + +/// Declares a type alias for a hash with Bech32 encoding support. +/// +/// This macro creates a type alias and implements the `Bech32Conversion` trait +/// for encoding/decoding the hash using a specified human-readable part (HRP). +/// +/// # Examples +/// +/// ``` +/// declare_hash_type_with_bech32!(VRFKey, 32, "vrf_vk"); +/// +/// let key: VRFKey = // ... get key +/// let bech32_string = key.to_bech32().unwrap(); +/// let decoded = VRFKey::from_bech32(&bech32_string).unwrap(); +/// ``` +#[macro_export] +macro_rules! declare_hash_type_with_bech32 { + ($name:ident, $size:expr, $hrp:expr) => { + declare_hash_type!($name, $size); + + impl crate::serialization::Bech32Conversion for $name { + fn to_bech32(&self) -> Result { + use crate::serialization::Bech32WithHrp; + self.to_vec().to_bech32_with_hrp($hrp) + } + + fn from_bech32(s: &str) -> Result { + use crate::serialization::Bech32WithHrp; + let v = Vec::::from_bech32_with_hrp(s, $hrp)?; + Self::try_from(v).map_err(|_| { + anyhow::Error::msg(format!( + "Bad vector input to {}", + stringify!($name) + )) + }) + } + } + }; + ($(#[$meta:meta])* $name:ident, $size:expr, $hrp:expr) => { + declare_hash_type!($(#[$meta])* $name, $size); + + impl crate::serialization::Bech32Conversion for $name { + fn to_bech32(&self) -> Result { + use crate::serialization::Bech32WithHrp; + self.to_vec().to_bech32_with_hrp($hrp) + } + + fn from_bech32(s: &str) -> Result { + use crate::serialization::Bech32WithHrp; + let v = Vec::::from_bech32_with_hrp(s, $hrp)?; + Self::try_from(v).map_err(|_| { + anyhow::Error::msg(format!( + "Bad vector input to {}", + stringify!($name) + )) + }) + } + } + }; +} + #[cfg(test)] mod tests { use super::*; @@ -149,4 +373,33 @@ mod tests { fn from_str_fail_2() { let _digest: Hash<32> = "0d8d00cdd465".parse().unwrap(); } + + #[test] + fn try_from_slice() { + let bytes = vec![0u8; 28]; + let hash: Hash<28> = bytes.as_slice().try_into().unwrap(); + assert_eq!(hash.as_ref(), bytes.as_slice()); + } + + #[test] + fn try_from_vec() { + let bytes = vec![0u8; 28]; + let hash: Hash<28> = bytes.clone().try_into().unwrap(); + assert_eq!(hash.as_ref(), bytes.as_slice()); + } + + #[test] + fn into_vec() { + let bytes = [0u8; 28]; + let hash = Hash::new(bytes); + let vec: Vec = hash.into(); + assert_eq!(vec, bytes.to_vec()); + } + + #[test] + #[should_panic] + fn try_from_wrong_size() { + let bytes = vec![0u8; 27]; // Wrong size + let _hash: Hash<28> = bytes.as_slice().try_into().unwrap(); + } } diff --git a/common/src/queries/accounts.rs b/common/src/queries/accounts.rs index 31394cfe..dae55e81 100644 --- a/common/src/queries/accounts.rs +++ b/common/src/queries/accounts.rs @@ -35,7 +35,7 @@ pub enum AccountsStateQuery { // Pools related queries GetOptimalPoolSizing, - GetPoolsLiveStakes { pools_operators: Vec> }, + GetPoolsLiveStakes { pools_operators: Vec }, GetPoolDelegators { pool_operator: KeyHash }, GetPoolLiveStake { pool_operator: KeyHash }, @@ -57,9 +57,9 @@ pub enum AccountsStateQueryResponse { AccountAssets(AccountAssets), AccountAssetsTotals(AccountAssetsTotals), AccountUTxOs(AccountUTxOs), - AccountsUtxoValuesMap(HashMap, u64>), + AccountsUtxoValuesMap(HashMap), AccountsUtxoValuesSum(u64), - AccountsBalancesMap(HashMap, u64>), + AccountsBalancesMap(HashMap), AccountsBalancesSum(u64), // Epochs-related responses @@ -77,7 +77,7 @@ pub enum AccountsStateQueryResponse { // DReps-related responses DrepDelegators(DrepDelegators), - AccountsDrepDelegationsMap(HashMap, Option>), + AccountsDrepDelegationsMap(HashMap>), NotFound, Error(String), diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index 1c6760ff..c6bb1cde 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -66,13 +66,21 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential { 0 => { // ScriptHash variant (first in enum) - decode bytes directly let bytes = d.bytes()?; - let key_hash = bytes.to_vec(); + let key_hash = KeyHash::try_from(bytes).map_err(|_| { + minicbor::decode::Error::message( + "invalid length for ScriptHash in StakeCredential", + ) + })?; Ok(StakeCredential::ScriptHash(key_hash)) } 1 => { // AddrKeyHash variant (second in enum) - decode bytes directly let bytes = d.bytes()?; - let key_hash = bytes.to_vec(); + let key_hash = KeyHash::try_from(bytes).map_err(|_| { + minicbor::decode::Error::message( + "invalid length for AddrKeyHash in StakeCredential", + ) + })?; Ok(StakeCredential::AddrKeyHash(key_hash)) } _ => Err(minicbor::decode::Error::message( @@ -299,6 +307,7 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { // Type aliases for pool_params compatibility // ----------------------------------------------------------------------------- +use crate::KeyHash; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; @@ -1076,15 +1085,19 @@ impl StreamingSnapshotParser { // Convert SPO delegation from StrictMaybe to Option // PoolId is Hash<28>, we need to convert to Vec let delegated_spo = match &account.pool { - StrictMaybe::Just(pool_id) => Some(pool_id.as_ref().to_vec()), + StrictMaybe::Just(pool_id) => Some(*pool_id), StrictMaybe::Nothing => None, }; // Convert DRep delegation from StrictMaybe to Option let delegated_drep = match &account.drep { StrictMaybe::Just(drep) => Some(match drep { - DRep::Key(hash) => crate::DRepChoice::Key(hash.as_ref().to_vec()), - DRep::Script(hash) => crate::DRepChoice::Script(hash.as_ref().to_vec()), + DRep::Key(hash) => crate::DRepChoice::Key( + KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), + ), + DRep::Script(hash) => crate::DRepChoice::Script( + KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), + ), DRep::Abstain => crate::DRepChoice::Abstain, DRep::NoConfidence => crate::DRepChoice::NoConfidence, }), @@ -1442,15 +1455,19 @@ impl StreamingSnapshotParser { // Convert SPO delegation from StrictMaybe to Option let delegated_spo = match &account.pool { - StrictMaybe::Just(pool_id) => Some(pool_id.as_ref().to_vec()), + StrictMaybe::Just(pool_id) => Some(*pool_id), StrictMaybe::Nothing => None, }; // Convert DRep delegation from StrictMaybe to Option let delegated_drep = match &account.drep { StrictMaybe::Just(drep) => Some(match drep { - DRep::Key(hash) => crate::DRepChoice::Key(hash.as_ref().to_vec()), - DRep::Script(hash) => crate::DRepChoice::Script(hash.as_ref().to_vec()), + DRep::Key(hash) => crate::DRepChoice::Key( + KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), + ), + DRep::Script(hash) => crate::DRepChoice::Script( + KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), + ), DRep::Abstain => crate::DRepChoice::Abstain, DRep::NoConfidence => crate::DRepChoice::NoConfidence, }), diff --git a/common/src/stake_addresses.rs b/common/src/stake_addresses.rs index b4daf076..975e4b0e 100644 --- a/common/src/stake_addresses.rs +++ b/common/src/stake_addresses.rs @@ -6,11 +6,7 @@ use std::{ sync::atomic::AtomicU64, }; -use crate::{ - math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, - DRepCredential, DelegatedStake, KeyHash, Lovelace, PoolLiveStakeInfo, StakeAddress, - StakeAddressDelta, Withdrawal, -}; +use crate::{math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, DRepCredential, DelegatedStake, KeyHash, Lovelace, PoolLiveStakeInfo, StakeAddress, StakeAddressDelta, Withdrawal}; use anyhow::Result; use dashmap::DashMap; use rayon::prelude::*; @@ -175,7 +171,8 @@ impl StakeAddressMap { .filter_map(|(stake_key, sas)| match sas.delegated_spo.as_ref() { Some(delegated_spo) => { if delegated_spo.eq(pool_operator) { - Some((stake_key.to_binary().clone(), sas.utxo_value + sas.rewards)) + // to_binary() now returns Result + stake_key.to_binary().ok().map(|key_hash| (key_hash, sas.utxo_value + sas.rewards)) } else { None } @@ -196,7 +193,8 @@ impl StakeAddressMap { .filter_map(|(stake_address, sas)| match sas.delegated_drep.as_ref() { Some(delegated_drep) => { if delegated_drep.eq(drep) { - Some((stake_address.to_binary(), sas.utxo_value)) + // to_binary() now returns Result + stake_address.to_binary().ok().map(|key_hash| (key_hash, sas.utxo_value)) } else { None } @@ -213,13 +211,14 @@ impl StakeAddressMap { pub fn get_accounts_utxo_values_map( &self, stake_addresses: &[StakeAddress], - ) -> Option, u64>> { + ) -> Option> { let mut map = HashMap::new(); for stake_address in stake_addresses { let account = self.get(stake_address)?; let utxo_value = account.utxo_value; - map.insert(stake_address.to_binary().clone(), utxo_value); + let key_hash = stake_address.to_binary().ok()?; + map.insert(key_hash, utxo_value); } Some(map) @@ -230,13 +229,14 @@ impl StakeAddressMap { pub fn get_accounts_balances_map( &self, stake_addresses: &[StakeAddress], - ) -> Option, u64>> { + ) -> Option> { let mut map = HashMap::new(); for stake_address in stake_addresses { let account = self.get(stake_address)?; let balance = account.utxo_value + account.rewards; - map.insert(stake_address.to_binary().clone(), balance); + let key_hash = stake_address.to_binary().ok()?; + map.insert(key_hash, balance); } Some(map) @@ -247,13 +247,14 @@ impl StakeAddressMap { pub fn get_drep_delegations_map( &self, stake_addresses: &[StakeAddress], - ) -> Option, Option>> { + ) -> Option>> { let mut map = HashMap::new(); for stake_address in stake_addresses { let account = self.get(stake_address)?; let maybe_drep = account.delegated_drep.clone(); - map.insert(stake_address.to_binary().clone(), maybe_drep); + let key_hash = stake_address.to_binary().ok()?; + map.insert(key_hash, maybe_drep); } Some(map) @@ -544,21 +545,20 @@ impl StakeAddressMap { #[cfg(test)] mod tests { - use crate::{NetworkId, StakeAddress, StakeCredential}; - use super::*; + use crate::{NetworkId, StakeAddress, StakeCredential}; - const STAKE_KEY_HASH: [u8; 28] = [0x99; 28]; - const STAKE_KEY_HASH_2: [u8; 28] = [0xaa; 28]; - const STAKE_KEY_HASH_3: [u8; 28] = [0xbb; 28]; + const STAKE_KEY_HASH: KeyHash = KeyHash::new([0x99; 28]); + const STAKE_KEY_HASH_2: KeyHash = KeyHash::new([0xaa; 28]); + const STAKE_KEY_HASH_3: KeyHash = KeyHash::new([0xbb; 28]); - const SPO_HASH: [u8; 28] = [0x01; 28]; - const SPO_HASH_2: [u8; 28] = [0x02; 28]; - const DREP_HASH: [u8; 28] = [0xca; 28]; + const SPO_HASH: KeyHash = KeyHash::new([0x01; 28]); + const SPO_HASH_2: KeyHash = KeyHash::new([0x02; 28]); + const DREP_HASH: KeyHash = KeyHash::new([0xca; 28]); - fn create_stake_address(hash: &[u8]) -> StakeAddress { + fn create_stake_address(hash: KeyHash) -> StakeAddress { StakeAddress::new( - StakeCredential::AddrKeyHash(hash.to_vec().try_into().expect("Invalid hash length")), + StakeCredential::AddrKeyHash(hash), NetworkId::Mainnet, ) } @@ -569,7 +569,7 @@ mod tests { #[test] fn test_register_success() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.register_stake_address(&stake_address)); assert_eq!(stake_addresses.len(), 1); @@ -579,7 +579,7 @@ mod tests { #[test] fn test_double_registration_fails() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.register_stake_address(&stake_address)); assert!(!stake_addresses.register_stake_address(&stake_address)); @@ -589,7 +589,7 @@ mod tests { #[test] fn test_deregister_success() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); assert!(stake_addresses.deregister_stake_address(&stake_address)); @@ -599,7 +599,7 @@ mod tests { #[test] fn test_deregister_unregistered_fails() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); // Create an entry but don't register stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -613,7 +613,7 @@ mod tests { #[test] fn test_deregister_unknown_fails() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(!stake_addresses.deregister_stake_address(&stake_address)); } @@ -621,14 +621,14 @@ mod tests { #[test] fn test_stake_address_lifecycle() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); // Register assert!(stake_addresses.register_stake_address(&stake_address)); // Delegate - stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH.to_vec()); - let drep_choice = DRepChoice::Key(DREP_HASH.to_vec()); + stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH); + let drep_choice = DRepChoice::Key(DREP_HASH); stake_addresses.record_drep_delegation(&stake_address, &drep_choice); // Deregister @@ -643,23 +643,23 @@ mod tests { #[test] fn test_spo_delegation_success() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); - assert!(stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH.to_vec())); + assert!(stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH)); assert_eq!( stake_addresses.get(&stake_address).unwrap().delegated_spo, - Some(SPO_HASH.to_vec()) + Some(SPO_HASH) ); } #[test] fn test_drep_delegation_success() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); - let drep_choice = DRepChoice::Key(DREP_HASH.to_vec()); + let drep_choice = DRepChoice::Key(DREP_HASH); assert!(stake_addresses.record_drep_delegation(&stake_address, &drep_choice)); assert_eq!( stake_addresses.get(&stake_address).unwrap().delegated_drep, @@ -670,12 +670,12 @@ mod tests { #[test] fn test_delegation_requires_registration() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); // Test unknown address - assert!(!stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH.to_vec())); + assert!(!stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH)); assert!(!stake_addresses - .record_drep_delegation(&stake_address, &DRepChoice::Key(DREP_HASH.to_vec()))); + .record_drep_delegation(&stake_address, &DRepChoice::Key(DREP_HASH))); // Create an unregistered entry with UTXO value stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -684,30 +684,30 @@ mod tests { }); // Delegation should still fail for unregistered address - assert!(!stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH.to_vec())); + assert!(!stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH)); assert!(!stake_addresses - .record_drep_delegation(&stake_address, &DRepChoice::Key(DREP_HASH.to_vec()))); + .record_drep_delegation(&stake_address, &DRepChoice::Key(DREP_HASH))); } #[test] fn test_re_delegation() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); // First SPO delegation - stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH.to_vec()); + stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH); assert_eq!( stake_addresses.get(&stake_address).unwrap().delegated_spo, - Some(SPO_HASH.to_vec()) + Some(SPO_HASH) ); // Re-delegate to different pool - stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH_2.to_vec()); + stake_addresses.record_stake_delegation(&stake_address, &SPO_HASH_2); assert_eq!( stake_addresses.get(&stake_address).unwrap().delegated_spo, - Some(SPO_HASH_2.to_vec()) + Some(SPO_HASH_2) ); // First DRep delegation @@ -732,7 +732,7 @@ mod tests { #[test] fn test_positive_delta_accumulates() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); @@ -750,7 +750,7 @@ mod tests { #[test] fn test_negative_delta_reduces() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); @@ -770,7 +770,7 @@ mod tests { #[test] fn test_negative_delta_underflow_prevented() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); @@ -796,7 +796,7 @@ mod tests { #[test] fn test_utxo_and_rewards_tracked_independently() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); @@ -814,7 +814,7 @@ mod tests { #[test] fn test_add_to_reward() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); stake_addresses.add_to_reward(&stake_address, 100); @@ -827,7 +827,7 @@ mod tests { #[test] fn test_update_reward_positive_delta() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.update_reward(&stake_address, 100).is_ok()); assert_eq!(stake_addresses.get(&stake_address).unwrap().rewards, 100); @@ -836,7 +836,7 @@ mod tests { #[test] fn test_update_reward_negative_delta() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.update_reward(&stake_address, 100).unwrap(); assert!(stake_addresses.update_reward(&stake_address, -50).is_ok()); @@ -846,7 +846,7 @@ mod tests { #[test] fn test_update_reward_underflow() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.update_reward(&stake_address, 50).unwrap(); @@ -858,7 +858,7 @@ mod tests { #[test] fn test_update_reward_creates_entry_if_missing() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.update_reward(&stake_address, 100).is_ok()); assert_eq!(stake_addresses.len(), 1); @@ -872,7 +872,7 @@ mod tests { #[test] fn test_withdrawal_success() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); stake_addresses.add_to_reward(&stake_address, 100); @@ -889,7 +889,7 @@ mod tests { #[test] fn test_withdrawal_prevents_underflow() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); stake_addresses.add_to_reward(&stake_address, 12); @@ -914,7 +914,7 @@ mod tests { #[test] fn test_zero_withdrawal() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&stake_address); stake_addresses.add_to_reward(&stake_address, 100); @@ -931,7 +931,7 @@ mod tests { #[test] fn test_withdrawal_unknown_address() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); let withdrawal = Withdrawal { address: stake_address.clone(), @@ -949,7 +949,7 @@ mod tests { #[test] fn test_update_utxo_value_positive_delta() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.update_utxo_value(&stake_address, 500).is_ok()); assert_eq!(stake_addresses.get(&stake_address).unwrap().utxo_value, 500); @@ -958,7 +958,7 @@ mod tests { #[test] fn test_update_utxo_value_negative_delta() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.update_utxo_value(&stake_address, 500).unwrap(); assert!(stake_addresses.update_utxo_value(&stake_address, -200).is_ok()); @@ -968,7 +968,7 @@ mod tests { #[test] fn test_update_utxo_value_underflow() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); stake_addresses.update_utxo_value(&stake_address, 100).unwrap(); @@ -980,7 +980,7 @@ mod tests { #[test] fn test_update_utxo_value_creates_entry_if_missing() { let mut stake_addresses = StakeAddressMap::new(); - let stake_address = create_stake_address(&STAKE_KEY_HASH); + let stake_address = create_stake_address(STAKE_KEY_HASH); assert!(stake_addresses.update_utxo_value(&stake_address, 500).is_ok()); assert_eq!(stake_addresses.len(), 1); @@ -995,13 +995,13 @@ mod tests { fn test_generate_spdd_single_pool() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); - stake_addresses.record_stake_delegation(&addr1, &SPO_HASH.to_vec()); - stake_addresses.record_stake_delegation(&addr2, &SPO_HASH.to_vec()); + stake_addresses.record_stake_delegation(&addr1, &SPO_HASH); + stake_addresses.record_stake_delegation(&addr2, &SPO_HASH); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1017,7 +1017,7 @@ mod tests { let spdd = stake_addresses.generate_spdd(); - let pool_stake = spdd.get(&SPO_HASH.to_vec()).unwrap(); + let pool_stake = spdd.get(&SPO_HASH).unwrap(); assert_eq!(pool_stake.active, 3000); // utxo only assert_eq!(pool_stake.live, 3150); // utxo + rewards assert_eq!(pool_stake.active_delegators_count, 2); @@ -1027,13 +1027,13 @@ mod tests { fn test_generate_spdd_multiple_pools() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); - stake_addresses.record_stake_delegation(&addr1, &SPO_HASH.to_vec()); - stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2.to_vec()); + stake_addresses.record_stake_delegation(&addr1, &SPO_HASH); + stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1047,14 +1047,14 @@ mod tests { let spdd = stake_addresses.generate_spdd(); assert_eq!(spdd.len(), 2); - assert_eq!(spdd.get(&SPO_HASH.to_vec()).unwrap().active, 1000); - assert_eq!(spdd.get(&SPO_HASH_2.to_vec()).unwrap().active, 2000); + assert_eq!(spdd.get(&SPO_HASH).unwrap().active, 1000); + assert_eq!(spdd.get(&SPO_HASH_2).unwrap().active, 2000); } #[test] fn test_generate_spdd_no_delegations() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); + let addr1 = create_stake_address(STAKE_KEY_HASH); stake_addresses.register_stake_address(&addr1); stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -1070,9 +1070,9 @@ mod tests { fn test_generate_drdd_with_special_choices() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); - let addr3 = create_stake_address(&STAKE_KEY_HASH_3); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); + let addr3 = create_stake_address(STAKE_KEY_HASH_3); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); @@ -1080,7 +1080,7 @@ mod tests { stake_addresses.record_drep_delegation(&addr1, &DRepChoice::Abstain); stake_addresses.record_drep_delegation(&addr2, &DRepChoice::NoConfidence); - stake_addresses.record_drep_delegation(&addr3, &DRepChoice::Key(DREP_HASH.to_vec())); + stake_addresses.record_drep_delegation(&addr3, &DRepChoice::Key(DREP_HASH)); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1100,13 +1100,13 @@ mod tests { }); stake_addresses.add_to_reward(&addr3, 150); - let dreps = vec![(DRepCredential::AddrKeyHash(DREP_HASH.to_vec()), 500)]; + let dreps = vec![(DRepCredential::AddrKeyHash(DREP_HASH), 500)]; let drdd = stake_addresses.generate_drdd(&dreps); assert_eq!(drdd.abstain, 1050); // 1000 + 50 assert_eq!(drdd.no_confidence, 2100); // 2000 + 100 - let drep_cred = DRepCredential::AddrKeyHash(DREP_HASH.to_vec()); + let drep_cred = DRepCredential::AddrKeyHash(DREP_HASH); let drep_stake = drdd .dreps .iter() @@ -1125,13 +1125,13 @@ mod tests { fn test_get_pool_live_stake_info() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); - stake_addresses.record_stake_delegation(&addr1, &SPO_HASH.to_vec()); - stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2.to_vec()); + stake_addresses.record_stake_delegation(&addr1, &SPO_HASH); + stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1145,7 +1145,7 @@ mod tests { }); stake_addresses.add_to_reward(&addr2, 100); - let info = stake_addresses.get_pool_live_stake_info(&SPO_HASH.to_vec()); + let info = stake_addresses.get_pool_live_stake_info(&SPO_HASH); assert_eq!(info.live_stake, 1050); // utxo + rewards for pool 1 assert_eq!(info.live_delegators, 1); @@ -1156,13 +1156,13 @@ mod tests { fn test_get_pools_live_stakes() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); - stake_addresses.record_stake_delegation(&addr1, &SPO_HASH.to_vec()); - stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2.to_vec()); + stake_addresses.record_stake_delegation(&addr1, &SPO_HASH); + stake_addresses.record_stake_delegation(&addr2, &SPO_HASH_2); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1173,7 +1173,7 @@ mod tests { delta: 2000, }); - let pools = vec![SPO_HASH.to_vec(), SPO_HASH_2.to_vec()]; + let pools = vec![SPO_HASH, SPO_HASH_2]; let stakes = stake_addresses.get_pools_live_stakes(&pools); assert_eq!(stakes, vec![1000, 2000]); @@ -1183,13 +1183,13 @@ mod tests { fn test_get_pool_delegators() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); - stake_addresses.record_stake_delegation(&addr1, &SPO_HASH.to_vec()); - stake_addresses.record_stake_delegation(&addr2, &SPO_HASH.to_vec()); + stake_addresses.record_stake_delegation(&addr1, &SPO_HASH); + stake_addresses.record_stake_delegation(&addr2, &SPO_HASH); stake_addresses.process_stake_delta(&StakeAddressDelta { address: addr1.clone(), @@ -1202,7 +1202,7 @@ mod tests { delta: 2000, }); - let delegators = stake_addresses.get_pool_delegators(&SPO_HASH.to_vec()); + let delegators = stake_addresses.get_pool_delegators(&SPO_HASH); assert_eq!(delegators.len(), 2); assert!(delegators.iter().any(|(_, stake)| *stake == 1050)); @@ -1217,8 +1217,8 @@ mod tests { fn test_get_accounts_utxo_values_map_success() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); @@ -1238,15 +1238,15 @@ mod tests { let map = stake_addresses.get_accounts_utxo_values_map(&keys).unwrap(); assert_eq!(map.len(), 2); - assert_eq!(map.get(&addr1.to_binary()).copied().unwrap(), 1000); - assert_eq!(map.get(&addr2.to_binary()).copied().unwrap(), 2000); + assert_eq!(map.get(&addr1.to_binary().unwrap()).copied().unwrap(), 1000); + assert_eq!(map.get(&addr2.to_binary().unwrap()).copied().unwrap(), 2000); } #[test] fn test_get_accounts_utxo_values_map_missing_account() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -1273,8 +1273,8 @@ mod tests { fn test_get_accounts_utxo_values_sum_success() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); @@ -1299,8 +1299,8 @@ mod tests { #[test] fn test_get_accounts_utxo_values_sum_missing_account() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -1331,8 +1331,8 @@ mod tests { fn test_get_accounts_balances_map_includes_rewards() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); @@ -1352,15 +1352,15 @@ mod tests { let map = stake_addresses.get_accounts_balances_map(&addresses).unwrap(); assert_eq!(map.len(), 2); - assert_eq!(map.get(&addr1.to_binary()).copied().unwrap(), 1100); - assert_eq!(map.get(&addr2.to_binary()).copied().unwrap(), 2000); + assert_eq!(map.get(&addr1.to_binary().unwrap()).copied().unwrap(), 1100); + assert_eq!(map.get(&addr2.to_binary().unwrap()).copied().unwrap(), 2000); } #[test] fn test_get_accounts_balances_map_missing_account() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -1387,8 +1387,8 @@ mod tests { fn test_get_account_balances_sum_includes_rewards() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); @@ -1413,8 +1413,8 @@ mod tests { #[test] fn test_get_account_balances_sum_missing_account() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.process_stake_delta(&StakeAddressDelta { @@ -1445,37 +1445,37 @@ mod tests { fn test_get_drep_delegations_map_various_choices() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); - let addr3 = create_stake_address(&STAKE_KEY_HASH_3); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); + let addr3 = create_stake_address(STAKE_KEY_HASH_3); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); stake_addresses.register_stake_address(&addr3); stake_addresses.record_drep_delegation(&addr1, &DRepChoice::Abstain); - stake_addresses.record_drep_delegation(&addr2, &DRepChoice::Key(DREP_HASH.to_vec())); + stake_addresses.record_drep_delegation(&addr2, &DRepChoice::Key(DREP_HASH)); let addresses = vec![addr1.clone(), addr2.clone(), addr3.clone()]; let map = stake_addresses.get_drep_delegations_map(&addresses).unwrap(); assert_eq!(map.len(), 3); assert_eq!( - map.get(&addr1.to_binary()).unwrap(), + map.get(&addr1.to_binary().unwrap()).unwrap(), &Some(DRepChoice::Abstain) ); assert_eq!( - map.get(&addr2.to_binary()).unwrap(), - &Some(DRepChoice::Key(DREP_HASH.to_vec())) + map.get(&addr2.to_binary().unwrap()).unwrap(), + &Some(DRepChoice::Key(DREP_HASH)) ); - assert_eq!(map.get(&addr3.to_binary()).unwrap(), &None); + assert_eq!(map.get(&addr3.to_binary().unwrap()).unwrap(), &None); } #[test] fn test_get_drep_delegations_map_missing_account() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); stake_addresses.register_stake_address(&addr1); stake_addresses.record_drep_delegation(&addr1, &DRepChoice::NoConfidence); @@ -1499,15 +1499,15 @@ mod tests { fn test_get_drep_delegators() { let mut stake_addresses = StakeAddressMap::new(); - let addr1 = create_stake_address(&STAKE_KEY_HASH); - let addr2 = create_stake_address(&STAKE_KEY_HASH_2); - let addr3 = create_stake_address(&STAKE_KEY_HASH_3); + let addr1 = create_stake_address(STAKE_KEY_HASH); + let addr2 = create_stake_address(STAKE_KEY_HASH_2); + let addr3 = create_stake_address(STAKE_KEY_HASH_3); stake_addresses.register_stake_address(&addr1); stake_addresses.register_stake_address(&addr2); stake_addresses.register_stake_address(&addr3); - let drep_choice = DRepChoice::Key(DREP_HASH.to_vec()); + let drep_choice = DRepChoice::Key(DREP_HASH); stake_addresses.record_drep_delegation(&addr1, &drep_choice); stake_addresses.record_drep_delegation(&addr2, &drep_choice); stake_addresses.record_drep_delegation(&addr3, &DRepChoice::Abstain); @@ -1532,4 +1532,4 @@ mod tests { assert!(delegators.iter().any(|(_, stake)| *stake == 2000)); } } -} +} \ No newline at end of file diff --git a/common/src/types.rs b/common/src/types.rs index 5030fcbd..61be7035 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -2,11 +2,12 @@ // We don't use these types in the acropolis_common crate itself #![allow(dead_code)] +use crate::hash::{AddrKeyhash, Hash, ScriptHash}; +use crate::snapshot::streaming_snapshot::PoolId; use crate::{ address::{Address, ShelleyAddress, StakeAddress}, - protocol_params, + declare_hash_type, declare_hash_type_with_bech32, protocol_params, rational_number::RationalNumber, - BlockHash, TxHash, }; use anyhow::{anyhow, bail, Error, Result}; use bech32::{Bech32, Hrp}; @@ -434,19 +435,16 @@ impl Default for UTXODelta { } } -/// Key hash used for pool IDs etc. -pub type KeyHash = Vec; - -pub type PoolId = Vec; +pub type KeyHash = Hash<28>; +pub type PoolKeyHash = Hash<28>; /// Script identifier -pub type ScriptHash = KeyHash; - -/// Address key hash -pub type AddrKeyhash = KeyHash; - pub type GenesisKeyhash = Vec; +declare_hash_type!(BlockHash, 32); +declare_hash_type!(TxHash, 32); +declare_hash_type_with_bech32!(VRFKey, 32, "vrf_vk"); + /// Data hash used for metadata, anchors (SHA256) pub type DataHash = Vec; @@ -646,7 +644,8 @@ impl Credential { hex_str )) } else { - Ok(key_hash) + KeyHash::try_from(key_hash.as_slice()) + .map_err(|_| anyhow!("Failed to convert to KeyHash")) } } @@ -678,7 +677,7 @@ impl Credential { .clone() } - pub fn from_drep_bech32(bech32_str: &str) -> Result { + pub fn from_drep_bech32(bech32_str: &str) -> Result { let (hrp, data) = bech32::decode(bech32_str)?; if data.len() != 28 { return Err(anyhow!( @@ -687,7 +686,12 @@ impl Credential { )); } - let hash: KeyHash = data; + let hash = KeyHash::try_from(data).map_err(|v| { + anyhow!( + "Failed to convert to KeyHash: expected 28 bytes, got {}", + v.len() + ) + })?; match hrp.as_str() { "drep" => Ok(Credential::AddrKeyHash(hash)), @@ -726,7 +730,7 @@ impl Credential { let mut address_bytes = [0u8; 29]; address_bytes[0] = header; - address_bytes[1..].copy_from_slice(&hash); + address_bytes[1..].copy_from_slice(hash.as_ref()); let hrp = Hrp::parse("stake").map_err(|e| anyhow!("HRP parse error: {e}"))?; bech32::encode::(hrp, &address_bytes) @@ -739,8 +743,8 @@ pub type StakeCredential = Credential; impl StakeCredential { pub fn to_string(&self) -> Result { let (hrp, data) = match &self { - Self::AddrKeyHash(data) => (Hrp::parse("stake_vkh")?, data), - Self::ScriptHash(data) => (Hrp::parse("script")?, data), + Self::AddrKeyHash(data) => (Hrp::parse("stake_vkh")?, data.as_slice()), + Self::ScriptHash(data) => (Hrp::parse("script")?, data.as_slice()), }; Ok(bech32::encode::(hrp, data)?) @@ -881,7 +885,7 @@ pub struct PoolRetirementWithPos { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PoolRetirement { /// Operator pool key hash - used as ID - pub operator: KeyHash, + pub operator: PoolKeyHash, /// Epoch it will retire at the end of pub epoch: u64, @@ -947,7 +951,7 @@ pub struct StakeDelegation { pub stake_address: StakeAddress, /// Pool ID to delegate to - pub operator: KeyHash, + pub operator: PoolId, } /// SPO total delegation data (for SPDD) @@ -1667,13 +1671,15 @@ impl Voter { impl Display for Voter { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Voter::ConstitutionalCommitteeKey(h) => write!(f, "{}", self.to_bech32("cc_hot", h)), + Voter::ConstitutionalCommitteeKey(h) => { + write!(f, "{}", self.to_bech32("cc_hot", h.as_ref())) + } Voter::ConstitutionalCommitteeScript(s) => { - write!(f, "{}", self.to_bech32("cc_hot_script", s)) + write!(f, "{}", self.to_bech32("cc_hot_script", s.as_ref())) } - Voter::DRepKey(k) => write!(f, "{}", self.to_bech32("drep", k)), - Voter::DRepScript(s) => write!(f, "{}", self.to_bech32("drep_script", s)), - Voter::StakePoolKey(k) => write!(f, "{}", self.to_bech32("pool", k)), + Voter::DRepKey(k) => write!(f, "{}", self.to_bech32("drep", k.as_ref())), + Voter::DRepScript(s) => write!(f, "{}", self.to_bech32("drep_script", s.as_ref())), + Voter::StakePoolKey(k) => write!(f, "{}", self.to_bech32("pool", k.as_ref())), } } } @@ -1958,6 +1964,7 @@ impl AddressTotals { #[cfg(test)] mod tests { use super::*; + use crate::hash::Hash; use anyhow::Result; #[test] @@ -1988,10 +1995,12 @@ mod tests { } fn make_committee_credential(addr_key_hash: bool, val: u8) -> CommitteeCredential { + // Create a 28-byte array filled with the value + let hash_bytes = [val; 28]; if addr_key_hash { - Credential::AddrKeyHash(vec![val]) + Credential::AddrKeyHash(KeyHash::from(hash_bytes)) } else { - Credential::ScriptHash(vec![val]) + Credential::ScriptHash(KeyHash::from(hash_bytes)) } } @@ -2000,8 +2009,11 @@ mod tests { let gov_action_id = GovActionId::default(); let mut voting = VotingProcedures::default(); + // Create a test hash with pattern [1, 2, 3, 4, 0, 0, ...] + let mut test_hash_bytes = [0u8; 28]; + test_hash_bytes[0..4].copy_from_slice(&[1, 2, 3, 4]); voting.votes.insert( - Voter::StakePoolKey(vec![1, 2, 3, 4]), + Voter::StakePoolKey(Hash::new(test_hash_bytes)), SingleVoterVotes::default(), ); @@ -2015,7 +2027,7 @@ mod tests { }, ); voting.votes.insert( - Voter::StakePoolKey(vec![1, 2, 3, 4]), + Voter::StakePoolKey(Hash::new(test_hash_bytes)), SingleVoterVotes::default(), ); println!("Json: {}", serde_json::to_string(&voting)?); diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index 9ae3a783..dc6515b4 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -1,39 +1,40 @@ use std::collections::HashMap; -use acropolis_common::{AddrKeyhash, PoolId}; +use acropolis_common::{PoolKeyHash}; use anyhow::Result; use fjall::{Config, Keyspace, PartitionCreateOptions}; +use acropolis_common::hash::AddrKeyhash; -const POOL_ID_LEN: usize = 28; +const POOL_KEY_LENGTH: usize = 28; const STAKE_KEY_LEN: usize = 28; const EPOCH_LEN: usize = 8; -const TOTAL_KEY_LEN: usize = EPOCH_LEN + POOL_ID_LEN + STAKE_KEY_LEN; +const TOTAL_KEY_LEN: usize = EPOCH_LEN + POOL_KEY_LENGTH + STAKE_KEY_LEN; // Batch size balances commit overhead vs memory usage // ~720KB per batch (72 bytes × 10,000) // ~130 commits for typical epoch (~1.3M delegations) const BATCH_SIZE: usize = 10_000; -fn encode_key(epoch: u64, pool_id: &PoolId, stake_key: &AddrKeyhash) -> Vec { +fn encode_key(epoch: u64, pool_key: &PoolKeyHash, stake_key: &AddrKeyhash) -> Vec { let mut key = Vec::with_capacity(TOTAL_KEY_LEN); key.extend_from_slice(&epoch.to_be_bytes()); - key.extend_from_slice(pool_id); + key.extend_from_slice(pool_key); key.extend_from_slice(stake_key); key } -fn encode_epoch_pool_prefix(epoch: u64, pool_id: &PoolId) -> Vec { - let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_ID_LEN); +fn encode_epoch_pool_prefix(epoch: u64, pool_key: &PoolKeyHash) -> Vec { + let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_KEY_LENGTH); prefix.extend_from_slice(&epoch.to_be_bytes()); - prefix.extend_from_slice(pool_id); + prefix.extend_from_slice(pool_key); prefix } -fn decode_key(key: &[u8]) -> Result<(u64, PoolId, AddrKeyhash)> { +fn decode_key(key: &[u8]) -> Result<(u64, PoolKeyHash, AddrKeyhash)> { let epoch = u64::from_be_bytes(key[..EPOCH_LEN].try_into()?); - let pool_id = key[EPOCH_LEN..EPOCH_LEN + POOL_ID_LEN].to_vec(); - let stake_key = key[EPOCH_LEN + POOL_ID_LEN..].to_vec(); - Ok((epoch, pool_id, stake_key)) + let pool_key = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].iter().into(); + let stake_key = key[EPOCH_LEN + POOL_KEY_LENGTH..].iter().into(); + Ok((epoch, pool_key, stake_key)) } /// Encode epoch completion marker key @@ -44,7 +45,7 @@ fn encode_epoch_marker(epoch: u64) -> Vec { pub struct SPDDStore { keyspace: Keyspace, /// Partition for all SPDD data - /// Key format: epoch(8 bytes) + pool_id + stake_key + /// Key format: epoch(8 bytes) + pool_key + stake_key /// Value: amount(8 bytes) spdd: fjall::PartitionHandle, /// Partition for epoch completion markers @@ -100,7 +101,7 @@ impl SPDDStore { pub fn store_spdd( &mut self, epoch: u64, - spdd_state: HashMap>, + spdd_state: HashMap>, ) -> fjall::Result<()> { if self.is_epoch_complete(epoch)? { return Ok(()); @@ -109,9 +110,9 @@ impl SPDDStore { let mut batch = self.keyspace.batch(); let mut count = 0; - for (pool_id, delegations) in spdd_state { + for (pool_key, delegations) in spdd_state { for (stake_key, amount) in delegations { - let key = encode_key(epoch, &pool_id, &stake_key); + let key = encode_key(epoch, &pool_key, &stake_key); let value = amount.to_be_bytes(); batch.insert(&self.spdd, key, value); @@ -182,7 +183,7 @@ impl SPDDStore { Ok(deleted_epochs) } - pub fn query_by_epoch(&self, epoch: u64) -> Result> { + pub fn query_by_epoch(&self, epoch: u64) -> Result> { if !self.is_epoch_complete(epoch)? { return Err(anyhow::anyhow!("Epoch SPDD Data is not complete")); } @@ -191,9 +192,9 @@ impl SPDDStore { let mut result = Vec::new(); for item in self.spdd.prefix(prefix) { let (key, value) = item?; - let (_, pool_id, stake_key) = decode_key(&key)?; + let (_, pool_key, stake_key) = decode_key(&key)?; let amount = u64::from_be_bytes(value.as_ref().try_into()?); - result.push((pool_id, stake_key, amount)); + result.push((pool_key, stake_key, amount)); } Ok(result) } @@ -201,13 +202,13 @@ impl SPDDStore { pub fn query_by_epoch_and_pool( &self, epoch: u64, - pool_id: &PoolId, + pool_key: &PoolKeyHash, ) -> Result> { if !self.is_epoch_complete(epoch)? { return Err(anyhow::anyhow!("Epoch SPDD Data is not complete")); } - let prefix = encode_epoch_pool_prefix(epoch, pool_id); + let prefix = encode_epoch_pool_prefix(epoch, pool_key); let mut result = Vec::new(); for item in self.spdd.prefix(prefix) { let (key, value) = item?; @@ -221,6 +222,7 @@ impl SPDDStore { #[cfg(test)] mod tests { + use acropolis_common::hash::AddrKeyhash; use super::*; const DB_PATH: &str = "spdd_db"; @@ -229,7 +231,7 @@ mod tests { fn test_store_spdd_state() { let mut spdd_store = SPDDStore::new(std::path::Path::new(DB_PATH), 1).expect("Failed to create SPDD store"); - let mut spdd_state: HashMap> = HashMap::new(); + let mut spdd_state: HashMap> = HashMap::new(); spdd_state.insert( vec![0x01; 28], vec![(vec![0x10; 28], 100), (vec![0x11; 28], 150)], @@ -254,7 +256,7 @@ mod tests { .expect("Failed to create SPDD store"); for epoch in 1..=3 { - let mut spdd_state: HashMap> = HashMap::new(); + let mut spdd_state: HashMap> = HashMap::new(); spdd_state.insert( vec![epoch as u8; 28], vec![(vec![0x10; 28], epoch * 100), (vec![0x11; 28], epoch * 150)], diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index 740e0403..de3b7c1d 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -261,8 +261,8 @@ impl State { for (tx_hash, voting_procedures) in voting_procedures { for (voter, single_votes) in &voting_procedures.votes { let drep_cred = match voter { - Voter::DRepKey(k) => DRepCredential::AddrKeyHash(k.to_vec()), - Voter::DRepScript(s) => DRepCredential::ScriptHash(s.to_vec()), + Voter::DRepKey(k) => DRepCredential::AddrKeyHash(*k), + Voter::DRepScript(s) => DRepCredential::ScriptHash(*s), _ => continue, }; diff --git a/modules/governance_state/src/state.rs b/modules/governance_state/src/state.rs index dcb0dc27..e0e9b55b 100644 --- a/modules/governance_state/src/state.rs +++ b/modules/governance_state/src/state.rs @@ -239,16 +239,16 @@ impl State { Voter::ConstitutionalCommitteeScript(_) => votes.committee += 1, Voter::DRepKey(key) => { self.drep_stake - .get(&DRepCredential::AddrKeyHash(key.clone())) + .get(&DRepCredential::AddrKeyHash(key.into())) .inspect(|v| votes.drep += *v); } Voter::DRepScript(script) => { self.drep_stake - .get(&DRepCredential::ScriptHash(script.clone())) + .get(&DRepCredential::ScriptHash(script.into())) .inspect(|v| votes.drep += *v); } Voter::StakePoolKey(pool) => { - self.spo_stake.get(pool).inspect(|ds| votes.pool += ds.live); + self.spo_stake.get(pool.into()).inspect(|ds| votes.pool += ds.live); } } } diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 41431f1b..6c26923f 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -401,11 +401,7 @@ pub fn process_message( #[cfg(test)] mod test { use crate::*; - use acropolis_common::{ - messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, - ByronAddress, Era, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, - ShelleyAddressPointer, StakeAddress, StakeCredential, UTxOIdentifier, ValueDelta, - }; + use acropolis_common::{messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, KeyHash, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeCredential, UTxOIdentifier, ValueDelta}; use bech32::{Bech32, Hrp}; fn parse_addr(s: &str) -> Result { @@ -471,10 +467,10 @@ mod test { network: map_network(stake_address.network())?, credential: match stake_address.payload() { addresses::StakePayload::Stake(hash) => { - StakeCredential::AddrKeyHash(hash.to_vec()) + StakeCredential::AddrKeyHash(KeyHash::from(hash)) } addresses::StakePayload::Script(hash) => { - StakeCredential::ScriptHash(hash.to_vec()) + StakeCredential::ScriptHash(KeyHash::from(hash)) } }, })), From 5f65e4f34918a623dc98382f1a8330cc06c99697 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Mon, 27 Oct 2025 17:11:14 -0700 Subject: [PATCH 02/20] Continue coercing types and defining clearer names for the keys in use --- codec/src/block.rs | 2 +- codec/src/map_parameters.rs | 61 ++++--- common/src/crypto.rs | 13 +- common/src/hash.rs | 138 +++++++++++++++ common/src/lib.rs | 1 - common/src/messages.rs | 1 - common/src/snapshot/pool_params.rs | 3 +- common/src/snapshot/streaming_snapshot.rs | 7 +- common/src/stake_addresses.rs | 6 +- common/src/types.rs | 21 +-- modules/accounts_state/src/snapshot.rs | 2 +- .../src/spo_distribution_store.rs | 49 ++++-- modules/accounts_state/src/state.rs | 69 ++++++-- modules/accounts_state/src/verifier.rs | 2 +- modules/chain_store/src/chain_store.rs | 16 +- modules/drep_state/src/state.rs | 16 +- modules/epochs_state/src/state.rs | 2 +- .../src/genesis_bootstrapper.rs | 2 +- modules/governance_state/src/state.rs | 4 +- .../src/immutable_historical_account_store.rs | 16 +- .../historical_accounts_state/src/state.rs | 9 +- .../src/mithril_snapshot_fetcher.rs | 2 +- .../parameters_state/src/genesis_params.rs | 5 +- .../rest_blockfrost/src/handlers/accounts.rs | 6 +- .../rest_blockfrost/src/handlers/epochs.rs | 25 ++- modules/spdd_state/src/rest.rs | 4 +- modules/spdd_state/src/state.rs | 2 +- modules/spo_state/src/state.rs | 160 ++++++++++++------ modules/stake_delta_filter/src/utils.rs | 8 +- .../src/body_fetcher.rs | 4 +- 30 files changed, 453 insertions(+), 203 deletions(-) diff --git a/codec/src/block.rs b/codec/src/block.rs index b898534c..f0b3b440 100644 --- a/codec/src/block.rs +++ b/codec/src/block.rs @@ -16,7 +16,7 @@ pub fn map_to_block_issuer( let digest = keyhash_224(vkey); if let Some(issuer) = shelley_genesis_delegates .values() - .find(|v| v.delegate == digest) + .find(|v| v.delegate == digest.to_vec()) .map(|i| BlockIssuer::GenesisDelegate(i.clone())) { Some(issuer) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 150276c9..75e0cffc 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -12,13 +12,14 @@ use pallas::ledger::{ *, }; +use acropolis_common::hash::Hash; use acropolis_common::{ protocol_params::{Nonce, NonceVariant, ProtocolVersion}, rational_number::RationalNumber, *, }; +use pallas_primitives::Bytes; use std::collections::{HashMap, HashSet}; -use acropolis_common::snapshot::streaming_snapshot::PoolId; /// Map Pallas Network to our NetworkId pub fn map_network(network: addresses::Network) -> Result { @@ -29,6 +30,20 @@ pub fn map_network(network: addresses::Network) -> Result { } } +/// Convert from Pallas Hash to Acropolis Hash +pub fn pallas_hash_to_acropolis( + pallas_hash: &pallas_primitives::Hash +) -> Hash { + Hash::new(**pallas_hash) +} + +/// Convert from Acropolis Hash to Pallas Hash +pub fn acropolis_hash_to_pallas( + our_hash: &Hash +) -> pallas_primitives::Hash { + pallas_primitives::Hash::new(**our_hash) +} + /// Derive our Address from a Pallas address // This is essentially a 1:1 mapping but makes the Message definitions independent // of Pallas @@ -43,20 +58,20 @@ pub fn map_address(address: &addresses::Address) -> Result
{ payment: match shelley_address.payment() { addresses::ShelleyPaymentPart::Key(hash) => { - ShelleyAddressPaymentPart::PaymentKeyHash(hash.to_vec()) + ShelleyAddressPaymentPart::PaymentKeyHash(hash.to_vec().try_into().unwrap()) } addresses::ShelleyPaymentPart::Script(hash) => { - ShelleyAddressPaymentPart::ScriptHash(hash.to_vec()) + ShelleyAddressPaymentPart::ScriptHash(hash.to_vec().try_into().unwrap()) } }, delegation: match shelley_address.delegation() { addresses::ShelleyDelegationPart::Null => ShelleyAddressDelegationPart::None, addresses::ShelleyDelegationPart::Key(hash) => { - ShelleyAddressDelegationPart::StakeKeyHash(hash.to_vec()) + ShelleyAddressDelegationPart::StakeKeyHash(hash.to_vec().try_into().unwrap()) } addresses::ShelleyDelegationPart::Script(hash) => { - ShelleyAddressDelegationPart::ScriptHash(hash.to_vec()) + ShelleyAddressDelegationPart::ScriptHash(hash.to_vec().try_into().unwrap()) } addresses::ShelleyDelegationPart::Pointer(pointer) => { ShelleyAddressDelegationPart::Pointer(ShelleyAddressPointer { @@ -71,8 +86,12 @@ pub fn map_address(address: &addresses::Address) -> Result
{ addresses::Address::Stake(stake_address) => Ok(Address::Stake(StakeAddress { network: map_network(stake_address.network())?, credential: match stake_address.payload() { - addresses::StakePayload::Stake(hash) => StakeCredential::AddrKeyHash(hash), - addresses::StakePayload::Script(hash) => StakeCredential::ScriptHash(hash), + addresses::StakePayload::Stake(hash) => { + StakeCredential::AddrKeyHash(pallas_hash_to_acropolis(hash)) + } + addresses::StakePayload::Script(hash) => { + StakeCredential::ScriptHash(pallas_hash_to_acropolis(hash)) + } }, })), } @@ -82,10 +101,10 @@ pub fn map_address(address: &addresses::Address) -> Result
{ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(key_hash) + StakeCredential::AddrKeyHash(KeyHash::try_from(key_hash.to_vec()).unwrap()) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(script_hash) + StakeCredential::ScriptHash(KeyHash::try_from(script_hash.to_vec()).unwrap()) } } } @@ -94,10 +113,10 @@ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> StakeAddress { let payload = match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(key_hash) + StakeCredential::AddrKeyHash(KeyHash::try_from(key_hash.to_vec()).unwrap()) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(script_hash) + StakeCredential::ScriptHash(KeyHash::try_from(script_hash.to_vec()).unwrap()) } }; @@ -107,8 +126,8 @@ pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> /// Map a Pallas DRep to our DRepChoice pub fn map_drep(drep: &conway::DRep) -> DRepChoice { match drep { - conway::DRep::Key(key_hash) => DRepChoice::Key(key_hash), - conway::DRep::Script(script_hash) => DRepChoice::Script(script_hash), + conway::DRep::Key(key_hash) => DRepChoice::Key(pallas_hash_to_acropolis(key_hash)), + conway::DRep::Script(script_hash) => DRepChoice::Script(pallas_hash_to_acropolis(script_hash)), conway::DRep::Abstain => DRepChoice::Abstain, conway::DRep::NoConfidence => DRepChoice::NoConfidence, } @@ -156,7 +175,7 @@ pub fn map_gov_action_id(pallas_action_id: &conway::GovActionId) -> Result { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash, + operator: PoolId::from(pallas_hash_to_acropolis(pool_key_hash)), })) } alonzo::Certificate::PoolRegistration { @@ -249,8 +268,8 @@ pub fn map_certificate( } => Ok(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { reg: PoolRegistration { - operator: operator, - vrf_key_hash: vrf_keyhash, + operator: pallas_hash_to_acropolis(operator), + vrf_key_hash: VRFKey::from(pallas_hash_to_acropolis(vrf_keyhash)), pledge: *pledge, cost: *cost, margin: Ratio { @@ -283,7 +302,7 @@ pub fn map_certificate( alonzo::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok( TxCertificate::PoolRetirementWithPos(PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_key_hash, + operator: pallas_hash_to_acropolis(pool_key_hash), epoch: *epoch, }, tx_hash, @@ -295,8 +314,8 @@ pub fn map_certificate( genesis_delegate_hash, vrf_key_hash, ) => Ok(TxCertificate::GenesisKeyDelegation(GenesisKeyDelegation { - genesis_hash: genesis_hash, - genesis_delegate_hash: genesis_delegate_hash, + genesis_hash: pallas_hash_to_acropolis(genesis_hash), + genesis_delegate_hash: pallas_hash_to_acropolis(genesis_delegate_hash), vrf_key_hash: vrf_key_hash, })), alonzo::Certificate::MoveInstantaneousRewardsCert(mir) => Ok( @@ -342,7 +361,7 @@ pub fn map_certificate( conway::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: PoolId::from(pool_key_hash) + operator: PoolId::from(pool_key_hash), })) } conway::Certificate::PoolRegistration { diff --git a/common/src/crypto.rs b/common/src/crypto.rs index 7e301c66..f5a0d2cf 100644 --- a/common/src/crypto.rs +++ b/common/src/crypto.rs @@ -1,17 +1,22 @@ //! Common cryptography helper functions for Acropolis +use crate::hash::Hash; use cryptoxide::hashing::blake2b::Blake2b; /// Get a Blake2b-256 hash of a key -pub fn keyhash_256(key: &[u8]) -> Vec { +/// +/// Returns a 32-byte hash. +pub fn keyhash_256(key: &[u8]) -> Hash<32> { let mut context = Blake2b::<256>::new(); context.update_mut(key); - context.finalize().to_vec() + Hash::new(context.finalize().into()) } /// Get a Blake2b-224 hash of a key -pub fn keyhash_224(key: &[u8]) -> Vec { +/// +/// Returns a 28-byte hash. +pub fn keyhash_224(key: &[u8]) -> Hash<28> { let mut context = Blake2b::<224>::new(); context.update_mut(key); - context.finalize().to_vec() + Hash::new(context.finalize().into()) } diff --git a/common/src/hash.rs b/common/src/hash.rs index 533c65df..7a7b2af8 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -294,6 +294,10 @@ macro_rules! declare_hash_type { /// This macro creates a type alias and implements the `Bech32Conversion` trait /// for encoding/decoding the hash using a specified human-readable part (HRP). /// +/// **WARNING**: You can only use this macro once per hash size, as it implements +/// a trait on `Hash`. If you need multiple distinct types with different +/// Bech32 HRPs for the same hash size, use `declare_hash_newtype_with_bech32!` instead. +/// /// # Examples /// /// ``` @@ -349,6 +353,140 @@ macro_rules! declare_hash_type_with_bech32 { }; } +/// Declares a newtype wrapper around Hash with Bech32 encoding support. +/// +/// Unlike `declare_hash_type_with_bech32!`, this creates a distinct type (not an alias), +/// allowing you to have multiple types of the same hash size with different Bech32 HRPs. +/// +/// # Examples +/// +/// ``` +/// // Both are 28 bytes but have different Bech32 encodings +/// declare_hash_newtype_with_bech32!(PoolId, 28, "pool"); +/// declare_hash_newtype_with_bech32!(DrepId, 28, "drep"); +/// ``` +#[macro_export] +macro_rules! declare_hash_newtype_with_bech32 { + ($name:ident, $size:expr, $hrp:expr) => { + #[doc = concat!(stringify!($name), " - a ", stringify!($size), "-byte hash.")] + #[derive( + Default, + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + serde::Serialize, + serde::Deserialize, + )] + #[serde(transparent)] + pub struct $name(Hash<$size>); + + impl $name { + pub const fn new(hash: Hash<$size>) -> Self { + Self(hash) + } + + pub fn to_vec(&self) -> Vec { + self.0.to_vec() + } + + pub fn into_inner(self) -> Hash<$size> { + self.0 + } + } + + impl From> for $name { + fn from(hash: Hash<$size>) -> Self { + Self(hash) + } + } + + impl From<[u8; $size]> for $name { + fn from(bytes: [u8; $size]) -> Self { + Self(Hash::new(bytes)) + } + } + + impl TryFrom> for $name { + type Error = Vec; + fn try_from(vec: Vec) -> Result { + Ok(Self(Hash::try_from(vec)?)) + } + } + + impl TryFrom<&[u8]> for $name { + type Error = std::array::TryFromSliceError; + fn try_from(arr: &[u8]) -> Result { + Ok(Self(Hash::try_from(arr)?)) + } + } + + impl AsRef<[u8]> for $name { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } + } + + impl std::ops::Deref for $name { + type Target = Hash<$size>; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::str::FromStr for $name { + type Err = hex::FromHexError; + fn from_str(s: &str) -> Result { + Ok(Self(s.parse()?)) + } + } + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } + } + + impl minicbor::Encode for $name { + fn encode( + &self, + e: &mut minicbor::Encoder, + ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + self.0.encode(e, ctx) + } + } + + impl<'a, C> minicbor::Decode<'a, C> for $name { + fn decode( + d: &mut minicbor::Decoder<'a>, + ctx: &mut C, + ) -> Result { + Ok(Self(Hash::decode(d, ctx)?)) + } + } + + impl crate::serialization::Bech32Conversion for $name { + fn to_bech32(&self) -> Result { + use crate::serialization::Bech32WithHrp; + self.0.to_vec().to_bech32_with_hrp($hrp) + } + + fn from_bech32(s: &str) -> Result { + use crate::serialization::Bech32WithHrp; + let v = Vec::::from_bech32_with_hrp(s, $hrp)?; + Self::try_from(v).map_err(|_| { + anyhow::Error::msg(format!("Bad vector input to {}", stringify!($name))) + }) + } + } + }; +} + #[cfg(test)] mod tests { use super::*; diff --git a/common/src/lib.rs b/common/src/lib.rs index a9cf24c3..239e7a83 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -26,5 +26,4 @@ pub mod validation; // Flattened re-exports pub use self::address::*; -pub use self::byte_array::*; pub use self::types::*; diff --git a/common/src/messages.rs b/common/src/messages.rs index 8ed9856e..7a4a233f 100644 --- a/common/src/messages.rs +++ b/common/src/messages.rs @@ -26,7 +26,6 @@ use crate::queries::{ transactions::{TransactionsStateQuery, TransactionsStateQueryResponse}, }; -use crate::byte_array::*; use crate::types::*; use crate::validation::ValidationStatus; diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index 9385a557..3d0a6881 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::PoolId; use super::streaming_snapshot::{ - cbor, AddrKeyhash, Coin, Nullable, PoolId, PoolMetadata, Relay, RewardAccount, Set, + cbor, AddrKeyhash, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, VrfKeyhash, }; diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index c6bb1cde..58cfc30c 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -287,7 +287,7 @@ impl minicbor::Encode for DRep { pub struct Account { pub rewards_and_deposit: StrictMaybe<(Lovelace, Lovelace)>, pub pointers: Set<(u64, u64, u64)>, - pub pool: StrictMaybe, + pub pool: StrictMaybe, pub drep: StrictMaybe, } @@ -307,16 +307,13 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { // Type aliases for pool_params compatibility // ----------------------------------------------------------------------------- -use crate::KeyHash; +use crate::{KeyHash}; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; /// Coin amount (Lovelace) pub type Coin = u64; -/// Pool ID (28-byte hash) -pub type PoolId = Hash<28>; - /// VRF key hash (32-byte hash) pub type VrfKeyhash = Hash<32>; diff --git a/common/src/stake_addresses.rs b/common/src/stake_addresses.rs index 975e4b0e..f10c5689 100644 --- a/common/src/stake_addresses.rs +++ b/common/src/stake_addresses.rs @@ -6,7 +6,7 @@ use std::{ sync::atomic::AtomicU64, }; -use crate::{math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, DRepCredential, DelegatedStake, KeyHash, Lovelace, PoolLiveStakeInfo, StakeAddress, StakeAddressDelta, Withdrawal}; +use crate::{math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, DRepCredential, DelegatedStake, Lovelace, KeyHash, PoolLiveStakeInfo, StakeAddress, StakeAddressDelta, Withdrawal}; use anyhow::Result; use dashmap::DashMap; use rayon::prelude::*; @@ -285,7 +285,7 @@ impl StakeAddressMap { /// Derive the Stake Pool Delegation Distribution (SPDD) - a map of total stake values /// (both with and without rewards) for each active SPO /// And Stake Pool Reward State (rewards and delegators_count for each pool) - /// DelegatedStake>;Key of returned map is the SPO 'operator' ID + /// DelegatedStake>;Key of returned map is the SPO 'operator' ID pub fn generate_spdd(&self) -> BTreeMap { // Shareable Dashmap with referenced keys let spo_stakes = DashMap::::new(); @@ -324,7 +324,7 @@ impl StakeAddressMap { } /// Dump current Stake Pool Delegation Distribution State - /// (Stake Key, Active Stakes Amount)> + /// (Stake Key, Active Stakes Amount)> pub fn dump_spdd_state(&self) -> HashMap> { let entries: Vec<_> = self .inner diff --git a/common/src/types.rs b/common/src/types.rs index 61be7035..b420bd48 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -3,12 +3,7 @@ #![allow(dead_code)] use crate::hash::{AddrKeyhash, Hash, ScriptHash}; -use crate::snapshot::streaming_snapshot::PoolId; -use crate::{ - address::{Address, ShelleyAddress, StakeAddress}, - declare_hash_type, declare_hash_type_with_bech32, protocol_params, - rational_number::RationalNumber, -}; +use crate::{address::{Address, ShelleyAddress, StakeAddress}, declare_hash_newtype_with_bech32, declare_hash_type, declare_hash_type_with_bech32, protocol_params, rational_number::RationalNumber}; use anyhow::{anyhow, bail, Error, Result}; use bech32::{Bech32, Hrp}; use bitmask_enum::bitmask; @@ -436,14 +431,16 @@ impl Default for UTXODelta { } pub type KeyHash = Hash<28>; -pub type PoolKeyHash = Hash<28>; /// Script identifier pub type GenesisKeyhash = Vec; declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); -declare_hash_type_with_bech32!(VRFKey, 32, "vrf_vk"); +declare_hash_newtype_with_bech32!(VRFKey, 32, "vrf_vk"); +declare_hash_newtype_with_bech32!(PoolId, 28, "pool"); +declare_hash_newtype_with_bech32!(DrepKey, 28, "drep"); +declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); /// Data hash used for metadata, anchors (SHA256) pub type DataHash = Vec; @@ -842,7 +839,7 @@ pub struct PoolRegistration { /// VRF key hash #[serde_as(as = "Hex")] #[n(1)] - pub vrf_key_hash: KeyHash, + pub vrf_key_hash: VRFKey, /// Pledged Ada #[n(2)] @@ -885,7 +882,7 @@ pub struct PoolRetirementWithPos { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PoolRetirement { /// Operator pool key hash - used as ID - pub operator: PoolKeyHash, + pub operator: PoolId, /// Epoch it will retire at the end of pub epoch: u64, @@ -1038,10 +1035,10 @@ pub struct Deregistration { #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum DRepChoice { /// Address key - Key(KeyHash), + Key(DrepKey), /// Script key - Script(KeyHash), + Script(DrepScriptKey), /// Abstain Abstain, diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index 8d1a9d3d..ac191df1 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -203,7 +203,7 @@ mod tests { fn create_test_spo_hash(id: u8) -> KeyHash { let mut hash = vec![0u8; 28]; hash[0] = id; - hash + KeyHash::try_from(hash).unwrap() } #[test] diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index dc6515b4..8ccc4915 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use acropolis_common::{PoolKeyHash}; +use acropolis_common::hash::AddrKeyhash; +use acropolis_common::PoolKeyHash; use anyhow::Result; use fjall::{Config, Keyspace, PartitionCreateOptions}; -use acropolis_common::hash::AddrKeyhash; const POOL_KEY_LENGTH: usize = 28; const STAKE_KEY_LEN: usize = 28; @@ -18,22 +18,22 @@ const BATCH_SIZE: usize = 10_000; fn encode_key(epoch: u64, pool_key: &PoolKeyHash, stake_key: &AddrKeyhash) -> Vec { let mut key = Vec::with_capacity(TOTAL_KEY_LEN); key.extend_from_slice(&epoch.to_be_bytes()); - key.extend_from_slice(pool_key); - key.extend_from_slice(stake_key); + key.extend_from_slice(pool_key.as_ref()); + key.extend_from_slice(stake_key.as_ref()); key } fn encode_epoch_pool_prefix(epoch: u64, pool_key: &PoolKeyHash) -> Vec { let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_KEY_LENGTH); prefix.extend_from_slice(&epoch.to_be_bytes()); - prefix.extend_from_slice(pool_key); + prefix.extend_from_slice(pool_key.as_ref()); prefix } fn decode_key(key: &[u8]) -> Result<(u64, PoolKeyHash, AddrKeyhash)> { let epoch = u64::from_be_bytes(key[..EPOCH_LEN].try_into()?); - let pool_key = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].iter().into(); - let stake_key = key[EPOCH_LEN + POOL_KEY_LENGTH..].iter().into(); + let pool_key: PoolKeyHash = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].try_into()?; + let stake_key: AddrKeyhash = key[EPOCH_LEN + POOL_KEY_LENGTH..].try_into()?; Ok((epoch, pool_key, stake_key)) } @@ -222,31 +222,44 @@ impl SPDDStore { #[cfg(test)] mod tests { - use acropolis_common::hash::AddrKeyhash; use super::*; + use acropolis_common::crypto::keyhash_224; + // ADDED + use acropolis_common::hash::AddrKeyhash; const DB_PATH: &str = "spdd_db"; + // ADDED: Helper to create test hashes + fn test_pool_hash(byte: u8) -> PoolKeyHash { + keyhash_224(&vec![byte]) + } + + fn test_addr_hash(byte: u8) -> AddrKeyhash { + keyhash_224(&vec![byte]) + } + #[test] fn test_store_spdd_state() { let mut spdd_store = SPDDStore::new(std::path::Path::new(DB_PATH), 1).expect("Failed to create SPDD store"); let mut spdd_state: HashMap> = HashMap::new(); + spdd_state.insert( - vec![0x01; 28], - vec![(vec![0x10; 28], 100), (vec![0x11; 28], 150)], + test_pool_hash(0x01), + vec![(test_addr_hash(0x10), 100), (test_addr_hash(0x11), 150)], ); spdd_state.insert( - vec![0x02; 28], - vec![(vec![0x20; 28], 200), (vec![0x21; 28], 250)], + test_pool_hash(0x02), + vec![(test_addr_hash(0x20), 200), (test_addr_hash(0x21), 250)], ); assert!(spdd_store.store_spdd(1, spdd_state).is_ok()); let result = spdd_store.query_by_epoch(1).unwrap(); assert_eq!(result.len(), 4); - let result = spdd_store.query_by_epoch_and_pool(1, &vec![0x01; 28]).unwrap(); + + let result = spdd_store.query_by_epoch_and_pool(1, &test_pool_hash(0x01)).unwrap(); assert_eq!(result.len(), 2); - let result = spdd_store.query_by_epoch_and_pool(1, &vec![0x02; 28]).unwrap(); + let result = spdd_store.query_by_epoch_and_pool(1, &test_pool_hash(0x02)).unwrap(); assert_eq!(result.len(), 2); } @@ -257,9 +270,13 @@ mod tests { for epoch in 1..=3 { let mut spdd_state: HashMap> = HashMap::new(); + spdd_state.insert( - vec![epoch as u8; 28], - vec![(vec![0x10; 28], epoch * 100), (vec![0x11; 28], epoch * 150)], + test_pool_hash(epoch as u8), + vec![ + (test_addr_hash(0x10), epoch * 100), + (test_addr_hash(0x11), epoch * 150), + ], ); spdd_store.store_spdd(epoch, spdd_state).expect("Failed to store SPDD state"); } diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 79c03c40..a47c9b37 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -187,7 +187,7 @@ impl State { pub fn get_accounts_utxo_values_map( &self, stake_keys: &[StakeAddress], - ) -> Option, u64>> { + ) -> Option> { let stake_addresses = self.stake_addresses.lock().ok()?; // If lock fails, return None stake_addresses.get_accounts_utxo_values_map(stake_keys) } @@ -202,7 +202,7 @@ impl State { pub fn get_accounts_balances_map( &self, stake_keys: &[StakeAddress], - ) -> Option, u64>> { + ) -> Option> { let stake_addresses = self.stake_addresses.lock().ok()?; // If lock fails, return None stake_addresses.get_accounts_balances_map(stake_keys) } @@ -785,7 +785,7 @@ impl State { // Schedule to retire - we need them to still be in place when we count // blocks for the previous epoch - self.retiring_spos.push(id.to_vec()); + self.retiring_spos.push(*id); } self.spos = new_spos; @@ -990,11 +990,28 @@ impl State { mod tests { use super::*; use acropolis_common::{ - protocol_params::ConwayParams, rational_number::RationalNumber, Anchor, Committee, - Constitution, CostModel, DRepVotingThresholds, NetworkId, PoolVotingThresholds, Pot, - PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAndVoteDelegation, - StakeCredential, StakeRegistrationAndStakeAndVoteDelegation, - StakeRegistrationAndVoteDelegation, VoteDelegation, Withdrawal, + crypto::keyhash_224, // ADDED: Import keyhash function + protocol_params::ConwayParams, + rational_number::RationalNumber, + Anchor, + Committee, + Constitution, + CostModel, + DRepVotingThresholds, + NetworkId, + PoolVotingThresholds, + Pot, + PotDelta, + Ratio, + Registration, + StakeAddress, + StakeAddressDelta, + StakeAndVoteDelegation, + StakeCredential, + StakeRegistrationAndStakeAndVoteDelegation, + StakeRegistrationAndVoteDelegation, + VoteDelegation, + Withdrawal, }; // Helper to create a StakeAddress from a byte slice @@ -1003,10 +1020,20 @@ mod tests { full_hash[..hash.len().min(28)].copy_from_slice(&hash[..hash.len().min(28)]); StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(full_hash), + credential: StakeCredential::AddrKeyHash(KeyHash::try_from(full_hash).unwrap()), } } + // ADDED: Helper to create KeyHash for testing + fn test_keyhash(byte: u8) -> KeyHash { + keyhash_224(&vec![byte]) + } + + // ADDED: Helper to create KeyHash from byte array + fn test_keyhash_from_bytes(bytes: &[u8]) -> KeyHash { + keyhash_224(bytes) + } + const STAKE_KEY_HASH: [u8; 3] = [0x99, 0x0f, 0x00]; const DREP_HASH: [u8; 4] = [0xca, 0xfe, 0xd0, 0x0d]; @@ -1060,8 +1087,8 @@ mod tests { fn spdd_from_delegation_with_utxo_values_and_pledge() { let mut state = State::default(); - let spo1: KeyHash = vec![0x01]; - let spo2: KeyHash = vec![0x02]; + let spo1: KeyHash = test_keyhash(0x01); // CHANGED + let spo2: KeyHash = test_keyhash(0x02); // CHANGED // Create the SPOs state @@ -1331,7 +1358,7 @@ mod tests { fn drdd_includes_initial_deposit() { let mut state = State::default(); - let drep_addr_cred = DRepCredential::AddrKeyHash(DREP_HASH.to_vec()); + let drep_addr_cred = DRepCredential::AddrKeyHash(test_keyhash_from_bytes(&DREP_HASH)); state.handle_drep_state(&DRepStateMessage { epoch: 1337, dreps: vec![(drep_addr_cred.clone(), 1_000_000)], @@ -1352,8 +1379,8 @@ mod tests { fn drdd_respects_different_delegations() -> Result<()> { let mut state = State::default(); - let drep_addr_cred = DRepCredential::AddrKeyHash(DREP_HASH.to_vec()); - let drep_script_cred = DRepCredential::ScriptHash(DREP_HASH.to_vec()); + let drep_addr_cred = DRepCredential::AddrKeyHash(test_keyhash_from_bytes(&DREP_HASH)); + let drep_script_cred = DRepCredential::ScriptHash(test_keyhash_from_bytes(&DREP_HASH)); state.handle_drep_state(&DRepStateMessage { epoch: 1337, dreps: vec![ @@ -1367,6 +1394,12 @@ mod tests { let spo3 = create_address(&[0x03]); let spo4 = create_address(&[0x04]); + // Get the KeyHash once + let spo1_hash = spo1.get_hash(); + + let drep_key_hash = test_keyhash_from_bytes(&DREP_HASH); + let drep_script_hash = test_keyhash_from_bytes(&DREP_HASH); + let certificates = vec![ // register the first two SPOs separately from their delegation TxCertificate::Registration(Registration { @@ -1379,12 +1412,12 @@ mod tests { }), TxCertificate::VoteDelegation(VoteDelegation { stake_address: spo1.clone(), - drep: DRepChoice::Key(DREP_HASH.to_vec()), + drep: DRepChoice::Key(drep_key_hash.clone()), // CHANGED }), TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: spo2.clone(), - operator: spo1.get_hash().to_vec(), - drep: DRepChoice::Script(DREP_HASH.to_vec()), + operator: spo1_hash.clone(), + drep: DRepChoice::Script(drep_script_hash.clone()), // CHANGED }), TxCertificate::StakeRegistrationAndVoteDelegation(StakeRegistrationAndVoteDelegation { stake_address: spo3.clone(), @@ -1394,7 +1427,7 @@ mod tests { TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: spo4.clone(), - operator: spo1.get_hash().to_vec(), + operator: spo1_hash.clone(), drep: DRepChoice::NoConfidence, deposit: 1, }, diff --git a/modules/accounts_state/src/verifier.rs b/modules/accounts_state/src/verifier.rs index f34924af..9cb55955 100644 --- a/modules/accounts_state/src/verifier.rs +++ b/modules/accounts_state/src/verifier.rs @@ -166,7 +166,7 @@ impl Verifier { continue; }; - expected_rewards.entry(spo).or_default().push(RewardDetail { + expected_rewards.entry(KeyHash::try_from(spo).unwrap()).or_default().push(RewardDetail { account: stake_address, rtype, amount, diff --git a/modules/chain_store/src/chain_store.rs b/modules/chain_store/src/chain_store.rs index 9a6ae144..c2385831 100644 --- a/modules/chain_store/src/chain_store.rs +++ b/modules/chain_store/src/chain_store.rs @@ -310,7 +310,7 @@ impl ChainStore { } fn get_block_hash(block: &Block) -> Result { - Ok(BlockHash( + Ok(BlockHash::from( *pallas_traverse::MultiEraBlock::decode(&block.bytes)?.hash(), )) } @@ -400,7 +400,7 @@ impl ChainStore { block_info.push(BlockInfo { timestamp: block.extra.timestamp, number: header.number(), - hash: BlockHash(*header.hash()), + hash: *header.hash().into(), slot: header.slot(), epoch: block.extra.epoch, epoch_slot: block.extra.epoch_slot, @@ -416,8 +416,8 @@ impl ChainStore { block_vrf: header.vrf_vkey().map(|key| VRFKey::try_from(key).ok().unwrap()), op_cert, op_cert_counter, - previous_block: header.previous_hash().map(|h| BlockHash(*h)), - next_block: next_hash.map(|h| BlockHash(*h)), + previous_block: header.previous_hash().map(|h| *h.into()), + next_block: next_hash.map(|h| *h.into()), confirmations: latest_number - header.number(), }); @@ -431,7 +431,7 @@ impl ChainStore { fn to_block_transaction_hashes(block: &Block) -> Result> { let decoded = pallas_traverse::MultiEraBlock::decode(&block.bytes)?; let txs = decoded.txs(); - Ok(txs.iter().map(|tx| TxHash(*tx.hash())).collect()) + Ok(txs.iter().map(|tx| TxHash::from(*tx.hash())).collect()) } fn to_block_transactions( @@ -449,7 +449,7 @@ impl ChainStore { let hashes = txs_iter .skip(*skip as usize) .take(*limit as usize) - .map(|tx| TxHash(*tx.hash())) + .map(|tx| TxHash::from(*tx.hash())) .collect(); Ok(BlockTransactions { hashes }) } @@ -470,7 +470,7 @@ impl ChainStore { .skip(*skip as usize) .take(*limit as usize) .map(|tx| { - let hash = TxHash(*tx.hash()); + let hash = TxHash::from(*tx.hash()); let cbor = tx.encode(); BlockTransaction { hash, cbor } }) @@ -486,7 +486,7 @@ impl ChainStore { let decoded = pallas_traverse::MultiEraBlock::decode(&block.bytes)?; let mut addresses = BTreeMap::new(); for tx in decoded.txs() { - let hash = TxHash(*tx.hash()); + let hash = TxHash::from(*tx.hash()); for output in tx.outputs() { if let Ok(pallas_address) = output.address() { if let Ok(address) = map_parameters::map_address(&pallas_address) { diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index de3b7c1d..c5bc649e 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -584,7 +584,7 @@ mod tests { #[test] fn test_drep_process_one_certificate() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -609,7 +609,7 @@ mod tests { #[test] fn test_drep_do_not_replace_existing_certificate() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -646,7 +646,7 @@ mod tests { #[test] fn test_drep_update_certificate() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -690,7 +690,7 @@ mod tests { #[test] fn test_drep_do_not_update_nonexistent_certificate() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -709,7 +709,7 @@ mod tests { }; let update_anchor_tx_cert = TxCertificate::DRepUpdate(DRepUpdateWithPos { reg: DRepUpdate { - credential: Credential::AddrKeyHash(CRED_2.to_vec()), + credential: Credential::AddrKeyHash(CRED_2.into()), anchor: Some(anchor.clone()), }, tx_hash: TxHash::default(), @@ -730,7 +730,7 @@ mod tests { #[test] fn test_drep_deregister() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(acropolis_common::DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -761,7 +761,7 @@ mod tests { #[test] fn test_drep_do_not_deregister_nonexistent_cert() { - let tx_cred = Credential::AddrKeyHash(CRED_1.to_vec()); + let tx_cred = Credential::AddrKeyHash(CRED_1.into()); let tx_cert = TxCertificate::DRepRegistration(acropolis_common::DRepRegistrationWithPos { reg: DRepRegistration { credential: tx_cred.clone(), @@ -776,7 +776,7 @@ mod tests { let unregister_tx_cert = TxCertificate::DRepDeregistration(DRepDeregistrationWithPos { reg: DRepDeregistration { - credential: Credential::AddrKeyHash(CRED_2.to_vec()), + credential: Credential::AddrKeyHash(CRED_2.into()), refund: 500000000, }, tx_hash: TxHash::default(), diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 408e4998..1b370a35 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -134,7 +134,7 @@ impl State { let evolving = Nonces::evolve(¤t_nonces.evolving, &nonce_vrf_output)?; // there must be parent hash - let Some(parent_hash) = header.previous_hash().map(|h| BlockHash(*h)) else { + let Some(parent_hash) = header.previous_hash().map(|h| BlockHash::new(*h)) else { return Err(anyhow::anyhow!("Header Parent hash error")); }; diff --git a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs index 9207c825..2c1e3f84 100644 --- a/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs +++ b/modules/genesis_bootstrapper/src/genesis_bootstrapper.rs @@ -141,7 +141,7 @@ impl GenesisBootstrapper { let mut total_allocated: u64 = 0; for (tx_index, (hash, address, amount)) in gen_utxos.iter().enumerate() { let tx_identifier = TxIdentifier::new(0, tx_index as u16); - let tx_ref = TxOutRef::new(TxHash(**hash), 0); + let tx_ref = TxOutRef::new(TxHash::new(**hash), 0); gen_utxo_identifiers.push((tx_ref, tx_identifier)); diff --git a/modules/governance_state/src/state.rs b/modules/governance_state/src/state.rs index e0e9b55b..5c6ed00f 100644 --- a/modules/governance_state/src/state.rs +++ b/modules/governance_state/src/state.rs @@ -239,12 +239,12 @@ impl State { Voter::ConstitutionalCommitteeScript(_) => votes.committee += 1, Voter::DRepKey(key) => { self.drep_stake - .get(&DRepCredential::AddrKeyHash(key.into())) + .get(&DRepCredential::AddrKeyHash(*key)) .inspect(|v| votes.drep += *v); } Voter::DRepScript(script) => { self.drep_stake - .get(&DRepCredential::ScriptHash(script.into())) + .get(&DRepCredential::ScriptHash(*script)) .inspect(|v| votes.drep += *v); } Voter::StakePoolKey(pool) => { diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index bae28a5c..1e2ce786 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -156,7 +156,7 @@ impl ImmutableHistoricalAccountStore { account: &StakeCredential, ) -> Result>> { let mut immutable_rewards = - self.collect_partition::(&self.rewards_history, &account.get_hash())?; + self.collect_partition::(&self.rewards_history, &account.get_hash().into_inner())?; self.merge_pending( account, @@ -174,7 +174,7 @@ impl ImmutableHistoricalAccountStore { ) -> Result>> { let mut immutable_active_stake = self.collect_partition::( &self.active_stake_history, - &account.get_hash(), + &account.get_hash().into_inner(), )?; self.merge_pending( @@ -192,7 +192,7 @@ impl ImmutableHistoricalAccountStore { account: &StakeCredential, ) -> Result>> { let mut immutable_delegations = self - .collect_partition::(&self.delegation_history, &account.get_hash())?; + .collect_partition::(&self.delegation_history, &account.get_hash().into_inner())?; self.merge_pending( account, @@ -210,7 +210,7 @@ impl ImmutableHistoricalAccountStore { ) -> Result>> { let mut immutable_registrations = self.collect_partition::( &self.registration_history, - &account.get_hash(), + &account.get_hash().into_inner(), )?; self.merge_pending( @@ -229,7 +229,7 @@ impl ImmutableHistoricalAccountStore { ) -> Result>> { let mut immutable_withdrawals = self.collect_partition::( &self.withdrawal_history, - &account.get_hash(), + &account.get_hash().into_inner(), )?; self.merge_pending( @@ -247,7 +247,7 @@ impl ImmutableHistoricalAccountStore { account: &StakeCredential, ) -> Result>> { let mut immutable_mirs = - self.collect_partition::(&self.mir_history, &account.get_hash())?; + self.collect_partition::(&self.mir_history, &account.get_hash().into_inner())?; self.merge_pending(account, |e| e.mir_history.as_ref(), &mut immutable_mirs).await; @@ -259,7 +259,7 @@ impl ImmutableHistoricalAccountStore { account: &StakeCredential, ) -> Result>> { let mut immutable_addresses = - self.collect_partition::(&self.addresses, &account.get_hash())?; + self.collect_partition::(&self.addresses, &account.get_hash().into_inner())?; self.merge_pending(account, |e| e.addresses.as_ref(), &mut immutable_addresses).await; @@ -322,7 +322,7 @@ impl ImmutableHistoricalAccountStore { fn make_epoch_key(account: &StakeCredential, epoch: u32) -> [u8; 32] { let mut key = [0u8; 32]; - key[..28].copy_from_slice(&account.get_hash()); + key[..28].copy_from_slice(&account.get_hash().into_inner()); key[28..32].copy_from_slice(&epoch.to_be_bytes()); key } diff --git a/modules/historical_accounts_state/src/state.rs b/modules/historical_accounts_state/src/state.rs index e0bbb547..07a81bfd 100644 --- a/modules/historical_accounts_state/src/state.rs +++ b/modules/historical_accounts_state/src/state.rs @@ -3,12 +3,9 @@ use std::{ sync::Arc, }; -use acropolis_common::{ - messages::{ - AddressDeltasMessage, StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, - }, - BlockInfo, PoolId, ShelleyAddress, StakeAddress, StakeCredential, TxIdentifier, -}; +use acropolis_common::{messages::{ + AddressDeltasMessage, StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, +}, BlockInfo, PoolId, ShelleyAddress, StakeAddress, StakeCredential, TxIdentifier}; use crate::{ immutable_historical_account_store::ImmutableHistoricalAccountStore, diff --git a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs index 84c10703..ffeff5e7 100644 --- a/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs +++ b/modules/mithril_snapshot_fetcher/src/mithril_snapshot_fetcher.rs @@ -325,7 +325,7 @@ impl MithrilSnapshotFetcher { status: BlockStatus::Immutable, slot, number, - hash: BlockHash(*block.hash()), + hash: BlockHash::new(*block.hash()), epoch, epoch_slot, new_epoch, diff --git a/modules/parameters_state/src/genesis_params.rs b/modules/parameters_state/src/genesis_params.rs index d8327c8f..98bade3a 100644 --- a/modules/parameters_state/src/genesis_params.rs +++ b/modules/parameters_state/src/genesis_params.rs @@ -1,4 +1,5 @@ use crate::alonzo_genesis; +use acropolis_common::hash::ScriptHash; use acropolis_common::{ protocol_params::{AlonzoParams, BabbageParams, ByronParams, ConwayParams, ShelleyParams}, rational_number::{rational_number_from_f32, RationalNumber}, @@ -107,7 +108,9 @@ fn map_drep_thresholds(thresholds: &conway::DRepVotingThresholds) -> Result Result { Ok(Constitution { anchor: map_anchor(&constitution.anchor)?, - guardrail_script: Some(decode_hex_string(&constitution.script, 28)?), + guardrail_script: Some( + ScriptHash::try_from(decode_hex_string(&constitution.script, 28)?).unwrap(), + ), }) } diff --git a/modules/rest_blockfrost/src/handlers/accounts.rs b/modules/rest_blockfrost/src/handlers/accounts.rs index 7ae84995..09ff6e08 100644 --- a/modules/rest_blockfrost/src/handlers/accounts.rs +++ b/modules/rest_blockfrost/src/handlers/accounts.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use acropolis_common::messages::{Message, RESTResponse, StateQuery, StateQueryResponse}; use acropolis_common::queries::accounts::{AccountsStateQuery, AccountsStateQueryResponse}; use acropolis_common::queries::utils::query_state; -use acropolis_common::serialization::Bech32WithHrp; +use acropolis_common::serialization::{Bech32Conversion, Bech32WithHrp}; use acropolis_common::{DRepChoice, StakeAddress}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; @@ -128,7 +128,7 @@ fn map_drep_choice(drep: &DRepChoice) -> Result { match drep { DRepChoice::Key(hash) => { let val = hash - .to_bech32_with_hrp("drep") + .to_bech32() .map_err(|e| anyhow!("Bech32 encoding failed for DRep Key: {e}"))?; Ok(DRepChoiceRest { drep_type: "Key".to_string(), @@ -137,7 +137,7 @@ fn map_drep_choice(drep: &DRepChoice) -> Result { } DRepChoice::Script(hash) => { let val = hash - .to_bech32_with_hrp("drep_script") + .to_bech32() .map_err(|e| anyhow!("Bech32 encoding failed for DRep Script: {e}"))?; Ok(DRepChoiceRest { drep_type: "Script".to_string(), diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index 94b4a30d..75cf555c 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -4,19 +4,14 @@ use crate::{ EpochActivityRest, ProtocolParamsRest, SPDDByEpochAndPoolItemRest, SPDDByEpochItemRest, }, }; -use acropolis_common::{ - messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, - queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse}, - epochs::{EpochsStateQuery, EpochsStateQueryResponse}, - parameters::{ParametersStateQuery, ParametersStateQueryResponse}, - pools::{PoolsStateQuery, PoolsStateQueryResponse}, - spdd::{SPDDStateQuery, SPDDStateQueryResponse}, - utils::query_state, - }, - serialization::Bech32WithHrp, - NetworkId, StakeAddress, StakeCredential, -}; +use acropolis_common::{messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse}, + epochs::{EpochsStateQuery, EpochsStateQueryResponse}, + parameters::{ParametersStateQuery, ParametersStateQueryResponse}, + pools::{PoolsStateQuery, PoolsStateQueryResponse}, + spdd::{SPDDStateQuery, SPDDStateQueryResponse}, + utils::query_state, +}, serialization::Bech32WithHrp, KeyHash, NetworkId, StakeAddress, StakeCredential}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; use std::sync::Arc; @@ -618,7 +613,7 @@ pub async fn handle_epoch_pool_stakes_blockfrost( let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetSPDDByEpochAndPool { epoch: epoch_number, - pool_id, + pool_id: pool_id.try_into().unwrap(), }, ))); let spdd = query_state( @@ -708,7 +703,7 @@ pub async fn handle_epoch_pool_blocks_blockfrost( // query Pool's Blocks by epoch from spo-state let msg = Arc::new(Message::StateQuery(StateQuery::Pools( PoolsStateQuery::GetBlocksByPoolAndEpoch { - pool_id: spo.clone(), + pool_id: KeyHash::try_from(spo.clone()).unwrap(), epoch: epoch_number, }, ))); diff --git a/modules/spdd_state/src/rest.rs b/modules/spdd_state/src/rest.rs index 4cc059dd..b26d488b 100644 --- a/modules/spdd_state/src/rest.rs +++ b/modules/spdd_state/src/rest.rs @@ -1,5 +1,5 @@ use crate::state::State; -use acropolis_common::serialization::Bech32WithHrp; +use acropolis_common::serialization::{Bech32Conversion, Bech32WithHrp}; use acropolis_common::DelegatedStake; use acropolis_common::{extract_strict_query_params, messages::RESTResponse}; use anyhow::Result; @@ -35,7 +35,7 @@ pub async fn handle_spdd( .iter() .map(|(k, v)| { ( - k.to_bech32_with_hrp("pool").unwrap_or_else(|_| hex::encode(k)), + k.to_bech32().unwrap_or_else(|_| hex::encode(k)), *v, ) }) diff --git a/modules/spdd_state/src/state.rs b/modules/spdd_state/src/state.rs index 178e12b0..c071dc69 100644 --- a/modules/spdd_state/src/state.rs +++ b/modules/spdd_state/src/state.rs @@ -35,7 +35,7 @@ impl State { } let to_remove: Vec<_> = - next.keys().filter(|k| !present.contains::<[u8]>((**k).as_slice())).cloned().collect(); + next.keys().filter(|k| !present.contains(*k)).cloned().collect(); for k in to_remove { next.remove(&k); } diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 195edf9d..24a90c7d 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -1,19 +1,9 @@ //! 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, 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, PoolId, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, TxCertificate, TxHash, Voter, VotingProcedures}; use anyhow::Result; use imbl::HashMap; use std::sync::{Arc, Mutex}; @@ -30,11 +20,11 @@ pub struct State { epoch: u64, - spos: HashMap, PoolRegistration>, + spos: HashMap, - pending_updates: HashMap, PoolRegistration>, + pending_updates: HashMap, - pending_deregistrations: HashMap>>, + pending_deregistrations: HashMap>, // Total blocks minted till block number // Keyed by pool_id @@ -134,7 +124,7 @@ impl From<&State> for SPOState { key_hashes .iter() .map(|key_hash| (key_hash.clone(), *epoch)) - .collect::, u64)>>() + .collect::>() }) .flatten() .collect(), @@ -149,7 +139,7 @@ impl State { } /// Get total blocks minted by pools - pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { + pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { pools_operators .iter() .map(|pool_operator| *self.total_blocks_minted.get(pool_operator).unwrap_or(&0)) @@ -157,12 +147,12 @@ impl State { } /// Get total blocks minted by pool - pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &KeyHash) -> u64 { + pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &PoolId) -> u64 { *self.total_blocks_minted.get(pool_operator).unwrap_or(&0) } /// Get all Stake Pool operators' operator hashes - pub fn list_pool_operators(&self) -> Vec { + pub fn list_pool_operators(&self) -> Vec { self.spos.keys().cloned().collect() } @@ -674,24 +664,29 @@ impl State { } } -// -- Tests -- #[cfg(test)] mod tests { use super::*; use crate::test_utils::*; - use acropolis_common::{ - state_history::{StateHistory, StateHistoryStore}, - PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, - }; + use acropolis_common::{state_history::{StateHistory, StateHistoryStore}, PoolId, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey}; use tokio::sync::Mutex; + fn test_pool_id(byte: u8) -> PoolId { + PoolId::from(keyhash_224(&vec![byte])) + } + + fn test_keyhash_from_bytes(bytes: &[u8]) -> KeyHash { + keyhash_224(bytes) + } + + fn default_pool_registration( - operator: Vec, - vrf_key_hash: Option>, + operator: KeyHash, + vrf_key_hash: Option, ) -> PoolRegistration { PoolRegistration { operator: operator.clone(), - vrf_key_hash: vrf_key_hash.unwrap_or_else(|| vec![0]), + vrf_key_hash: vrf_key_hash.unwrap_or_else(|| VRFKey::default()), pledge: 0, cost: 0, margin: Ratio { @@ -708,7 +703,8 @@ mod tests { #[test] fn get_returns_none_on_empty_state() { let state = State::default(); - assert!(state.get(&vec![0]).is_none()); + let pool_id = test_pool_id(0); // Changed + assert!(state.get(&pool_id).is_none()); // Changed } #[test] @@ -730,9 +726,10 @@ mod tests { async fn spo_gets_registered() { let mut state = State::default(); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id.clone(), None) tx_hash: TxHash::default(), cert_index: 1, }, @@ -740,7 +737,7 @@ mod tests { let block = new_block(1); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0]); + let spo = state.spos.get(&pool_id); // Changed assert!(!spo.is_none()); } @@ -748,10 +745,11 @@ mod tests { async fn pending_deregistration_gets_queued() { let mut state = State::default(); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id.clone() epoch: 1, }, tx_hash: TxHash::default(), @@ -765,7 +763,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&vec![0])); + assert!(drs.contains(&pool_id)); // Changed } } @@ -774,10 +772,13 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); // Changed + let pool_id_1 = test_pool_id(1); // Changed + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0.clone() epoch: 2, }, tx_hash: TxHash::default(), @@ -791,7 +792,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1.clone() epoch: 2, }, tx_hash: TxHash::default(), @@ -805,8 +806,8 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(2, drs.len()); - assert!(drs.contains(&vec![0u8])); - assert!(drs.contains(&vec![1u8])); + assert!(drs.contains(&pool_id_0)); // Changed + assert!(drs.contains(&pool_id_1)); // Changed } } @@ -819,10 +820,13 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); // Changed + let pool_id_1 = test_pool_id(1); // Changed + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0.clone() epoch: 2, }, tx_hash: TxHash::default(), @@ -838,7 +842,43 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1.clone() + epoch: 2, + }, + tx_hash: TxHash::default(), + cert_index: 0, + }, + )); + assert!(state.handle_tx_certs(&block, &msg).is_ok()); + history.lock().await.commit(block.number, state); + + block.number = 1; + let mut state = history.lock().await.get_rolled_back_state(block.number); + msg = new_certs_msg(); + assert!(state.handle_tx_certs(&block, &msg).is_ok()); + assert_eq!(1, state.pending_deregistrations.len()); + let drs = state.pending_deregistrations.get(&2); + assert!(!drs.is_none()); + if let Some(drs) = drs { + assert_eq!(1, drs.len()); + assert!(drs.contains(&pool_id_0)); // Changed + } + } + + #[tokio::test] + async fn spo_gets_deregistered_on_deregistration() { + let history = Arc::new(Mutex::new(StateHistory::::new( + "spo_state", + StateHistoryStore::default_block_store(), + ))); + let mut state = history.lock().await.get_current_state(); + let mut block = new_block(0); + let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); // Changed + msg.certificates.push(TxCertificate::PoolRetirementWithPos( + PoolRetirementWithPos { + ret: PoolRetirement { + operator: pool_id.clone() epoch: 2, }, tx_hash: TxHash::default(), @@ -857,7 +897,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&vec![0])); + assert!(drs.contains(&pool_id)); // Changed } } @@ -866,9 +906,10 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id.clone(), None) tx_hash: TxHash::default(), cert_index: 0, }, @@ -876,7 +917,7 @@ mod tests { assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0u8]); + let spo = state.spos.get(&pool_id); // Changed assert!(!spo.is_none()); block.number = 1; @@ -884,7 +925,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id.clone() epoch: 1, }, tx_hash: TxHash::default(), @@ -909,16 +950,17 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id.clone(), None) tx_hash: TxHash::default(), cert_index: 0, }, )); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0u8]); + let spo = state.spos.get(&pool_id); // Changed assert!(!spo.is_none()); history.lock().await.commit(block.number, state); @@ -928,7 +970,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id.clone() epoch: 1, }, tx_hash: TxHash::default(), @@ -952,7 +994,7 @@ mod tests { let mut state = history.lock().await.get_rolled_back_state(block.number); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0]); + let spo = state.spos.get(&pool_id); // Changed assert!(!spo.is_none()); } @@ -967,10 +1009,13 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); // Changed + let pool_id_1 = test_pool_id(1); // Changed + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0.clone() epoch: 2, }, tx_hash: TxHash::default(), @@ -984,7 +1029,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1.clone() epoch: 3, }, tx_hash: TxHash::default(), @@ -995,17 +1040,21 @@ mod tests { let mut retiring_pools = state.get_retiring_pools(); retiring_pools.sort_by_key(|p| p.epoch); assert_eq!(2, retiring_pools.len()); - assert_eq!(vec![0], retiring_pools[0].operator); + assert_eq!(pool_id_0, retiring_pools[0].operator); // Changed assert_eq!(2, retiring_pools[0].epoch); - assert_eq!(vec![1], retiring_pools[1].operator); + assert_eq!(pool_id_1, retiring_pools[1].operator); // Changed assert_eq!(3, retiring_pools[1].epoch); } #[test] fn get_total_blocks_minted_returns_zeros_when_state_is_new() { let state = State::default(); - assert_eq!(0, state.get_total_blocks_minted_by_pools(&vec![vec![0]])[0]); - assert_eq!(0, state.get_total_blocks_minted_by_pool(&vec![0])); + let pool_id = test_pool_id(0); // Changed + assert_eq!( + 0, + state.get_total_blocks_minted_by_pools(&vec![pool_id.clone()])[0] + ); // Changed + assert_eq!(0, state.get_total_blocks_minted_by_pool(&pool_id)); // Changed } #[test] @@ -1035,7 +1084,8 @@ mod tests { #[test] fn get_blocks_returns_none_when_blocks_not_enabled() { let state = State::default(); - assert!(state.get_blocks_by_pool(&vec![0]).is_none()); + let pool_id = test_pool_id(0); // Changed + assert!(state.get_blocks_by_pool(&pool_id).is_none()); // Changed } #[test] diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 6c26923f..2e960d3f 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -438,20 +438,20 @@ mod test { payment: match shelley_address.payment() { addresses::ShelleyPaymentPart::Key(hash) => { - ShelleyAddressPaymentPart::PaymentKeyHash(hash.to_vec()) + ShelleyAddressPaymentPart::PaymentKeyHash(hash) } addresses::ShelleyPaymentPart::Script(hash) => { - ShelleyAddressPaymentPart::ScriptHash(hash.to_vec()) + ShelleyAddressPaymentPart::ScriptHash(hash) } }, delegation: match shelley_address.delegation() { addresses::ShelleyDelegationPart::Null => ShelleyAddressDelegationPart::None, addresses::ShelleyDelegationPart::Key(hash) => { - ShelleyAddressDelegationPart::StakeKeyHash(hash.to_vec()) + ShelleyAddressDelegationPart::StakeKeyHash(hash) } addresses::ShelleyDelegationPart::Script(hash) => { - ShelleyAddressDelegationPart::ScriptHash(hash.to_vec()) + ShelleyAddressDelegationPart::ScriptHash(hash) } addresses::ShelleyDelegationPart::Pointer(pointer) => { ShelleyAddressDelegationPart::Pointer(ShelleyAddressPointer { diff --git a/modules/upstream_chain_fetcher/src/body_fetcher.rs b/modules/upstream_chain_fetcher/src/body_fetcher.rs index 038d8497..3ce93105 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::RawBlockMessage, BlockHash, BlockInfo, BlockStatus, Era}; +use acropolis_common::{messages::RawBlockMessage, BlockInfo, BlockStatus, Era}; use anyhow::{bail, Result}; use crossbeam::channel::{Receiver, TryRecvError}; use pallas::{ @@ -117,7 +117,7 @@ impl BodyFetcher { }, // TODO vary with 'k' slot, number, - hash: BlockHash(hash), + hash: hash.into(), epoch, epoch_slot, new_epoch, From df9580978eb9cbbffaeda5c6e76a88b41a04a7fd Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Mon, 27 Oct 2025 18:22:18 -0700 Subject: [PATCH 03/20] Refactor: Replace `KeyHash` with `PoolId` for stronger type safety across pool-related operations and update associated tests --- common/src/ledger_state.rs | 10 +- common/src/messages.rs | 2 +- common/src/queries/accounts.rs | 10 +- common/src/queries/pools.rs | 35 +++-- common/src/snapshot/pool_params.rs | 6 +- common/src/snapshot/streaming_snapshot.rs | 7 +- common/src/stake_addresses.rs | 47 ++++--- common/src/types.rs | 4 +- .../src/spo_distribution_store.rs | 25 ++-- modules/accounts_state/src/state.rs | 24 ++-- .../rest_blockfrost/src/handlers/accounts.rs | 2 +- .../rest_blockfrost/src/handlers/epochs.rs | 23 +-- modules/rest_blockfrost/src/handlers/pools.rs | 54 ++++---- modules/rest_blockfrost/src/types.rs | 13 +- modules/spo_state/src/epochs_history.rs | 15 +- modules/spo_state/src/state.rs | 131 +++++------------- 16 files changed, 164 insertions(+), 244 deletions(-) diff --git a/common/src/ledger_state.rs b/common/src/ledger_state.rs index d44c1fab..3ccb0d5a 100644 --- a/common/src/ledger_state.rs +++ b/common/src/ledger_state.rs @@ -1,6 +1,4 @@ -use crate::{ - KeyHash, MultiHostName, PoolRegistration, Ratio, Relay, SingleHostAddr, SingleHostName, -}; +use crate::{MultiHostName, PoolId, PoolRegistration, Ratio, Relay, SingleHostAddr, SingleHostName}; use anyhow::{bail, Context, Result}; use minicbor::data::Tag; use std::{collections::BTreeMap, fs, path::Path}; @@ -31,11 +29,11 @@ pub struct ParametersState {} )] pub struct SPOState { #[n(0)] - pub pools: BTreeMap, + pub pools: BTreeMap, #[n(1)] - pub updates: BTreeMap, + pub updates: BTreeMap, #[n(2)] - pub retiring: BTreeMap, + pub retiring: BTreeMap, } pub struct DRepState {} diff --git a/common/src/messages.rs b/common/src/messages.rs index 7a4a233f..c095bbfe 100644 --- a/common/src/messages.rs +++ b/common/src/messages.rs @@ -272,7 +272,7 @@ pub struct SPOStateMessage { pub spos: Vec, /// SPOs in the above list which retired at the start of this epoch, by operator ID - pub retired_spos: Vec, + pub retired_spos: Vec, } /// Cardano message enum diff --git a/common/src/queries/accounts.rs b/common/src/queries/accounts.rs index dae55e81..de2dd726 100644 --- a/common/src/queries/accounts.rs +++ b/common/src/queries/accounts.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{DRepChoice, KeyHash, PoolLiveStakeInfo, StakeAddress}; +use crate::{DRepChoice, KeyHash, PoolId, PoolLiveStakeInfo, StakeAddress}; pub const DEFAULT_ACCOUNTS_QUERY_TOPIC: (&str, &str) = ("accounts-state-query-topic", "cardano.query.accounts"); @@ -35,9 +35,9 @@ pub enum AccountsStateQuery { // Pools related queries GetOptimalPoolSizing, - GetPoolsLiveStakes { pools_operators: Vec }, - GetPoolDelegators { pool_operator: KeyHash }, - GetPoolLiveStake { pool_operator: KeyHash }, + GetPoolsLiveStakes { pools_operators: Vec }, + GetPoolDelegators { pool_operator: PoolId }, + GetPoolLiveStake { pool_operator: PoolId }, // Dreps related queries GetDrepDelegators { drep: DRepChoice }, @@ -87,7 +87,7 @@ pub enum AccountsStateQueryResponse { pub struct AccountInfo { pub utxo_value: u64, pub rewards: u64, - pub delegated_spo: Option, + pub delegated_spo: Option, pub delegated_drep: Option, } diff --git a/common/src/queries/pools.rs b/common/src/queries/pools.rs index 0cf53e78..a715b74e 100644 --- a/common/src/queries/pools.rs +++ b/common/src/queries/pools.rs @@ -1,7 +1,4 @@ -use crate::{ - queries::governance::VoteRecord, rational_number::RationalNumber, KeyHash, PoolEpochState, - PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, Relay, -}; +use crate::{queries::governance::VoteRecord, rational_number::RationalNumber, KeyHash, PoolEpochState, PoolId, PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, Relay}; pub const DEFAULT_POOLS_QUERY_TOPIC: (&str, &str) = ("pools-state-query-topic", "cardano.query.pools"); @@ -13,52 +10,52 @@ pub enum PoolsStateQuery { GetPoolsRetiredList, GetPoolsRetiringList, GetPoolActiveStakeInfo { - pool_operator: KeyHash, + pool_operator: PoolId, epoch: u64, }, GetPoolsActiveStakes { - pools_operators: Vec, + pools_operators: Vec, epoch: u64, }, GetPoolsTotalBlocksMinted { - pools_operators: Vec, + pools_operators: Vec, }, GetPoolInfo { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolHistory { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolMetadata { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolRelays { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolDelegators { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolTotalBlocksMinted { - pool_id: KeyHash, + pool_id: PoolId, }, GetBlocksByPool { - pool_id: KeyHash, + pool_id: PoolId, }, GetBlocksByPoolAndEpoch { - pool_id: KeyHash, + pool_id: PoolId, epoch: u64, }, GetPoolUpdates { - pool_id: KeyHash, + pool_id: PoolId, }, GetPoolVotes { - pool_id: KeyHash, + pool_id: PoolId, }, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum PoolsStateQueryResponse { - PoolsList(Vec), + PoolsList(Vec), PoolsListWithInfo(PoolsListWithInfo), PoolsRetiredList(Vec), PoolsRetiringList(Vec), @@ -83,7 +80,7 @@ pub enum PoolsStateQueryResponse { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PoolsListWithInfo { - pub pools: Vec<(KeyHash, PoolRegistration)>, + pub pools: Vec<(PoolId, PoolRegistration)>, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index 3d0a6881..2febc7e4 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::PoolId; +use crate::{PoolId, VRFKey}; use super::streaming_snapshot::{ cbor, AddrKeyhash, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, - UnitInterval, VrfKeyhash, + UnitInterval, }; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PoolParams { pub id: PoolId, - pub vrf: VrfKeyhash, + pub vrf: VRFKey, pub pledge: Coin, pub cost: Coin, pub margin: UnitInterval, diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index 58cfc30c..dd727410 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -287,7 +287,7 @@ impl minicbor::Encode for DRep { pub struct Account { pub rewards_and_deposit: StrictMaybe<(Lovelace, Lovelace)>, pub pointers: Set<(u64, u64, u64)>, - pub pool: StrictMaybe, + pub pool: StrictMaybe, pub drep: StrictMaybe, } @@ -307,16 +307,13 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { // Type aliases for pool_params compatibility // ----------------------------------------------------------------------------- -use crate::{KeyHash}; +use crate::{KeyHash, PoolId}; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; /// Coin amount (Lovelace) pub type Coin = u64; -/// VRF key hash (32-byte hash) -pub type VrfKeyhash = Hash<32>; - /// Reward account (stake address bytes) - wrapper to handle CBOR bytes encoding #[derive(Debug, Clone, PartialEq, Eq)] pub struct RewardAccount(pub Vec); diff --git a/common/src/stake_addresses.rs b/common/src/stake_addresses.rs index f10c5689..0d49089c 100644 --- a/common/src/stake_addresses.rs +++ b/common/src/stake_addresses.rs @@ -6,7 +6,11 @@ use std::{ sync::atomic::AtomicU64, }; -use crate::{math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, DRepCredential, DelegatedStake, Lovelace, KeyHash, PoolLiveStakeInfo, StakeAddress, StakeAddressDelta, Withdrawal}; +use crate::{ + math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, + DRepCredential, DelegatedStake, KeyHash, Lovelace, PoolId, PoolLiveStakeInfo, StakeAddress, + StakeAddressDelta, Withdrawal, +}; use anyhow::Result; use dashmap::DashMap; use rayon::prelude::*; @@ -28,7 +32,7 @@ pub struct StakeAddressState { /// SPO ID they are delegated to ("operator" ID) #[serde_as(as = "Option")] - pub delegated_spo: Option, + pub delegated_spo: Option, /// DRep they are delegated to pub delegated_drep: Option, @@ -112,7 +116,7 @@ impl StakeAddressMap { } /// Get Pool's Live Stake Info - pub fn get_pool_live_stake_info(&self, spo: &KeyHash) -> PoolLiveStakeInfo { + pub fn get_pool_live_stake_info(&self, spo: &PoolId) -> PoolLiveStakeInfo { let total_live_stakes = AtomicU64::new(0); let live_stake = AtomicU64::new(0); let live_delegators = AtomicU64::new(0); @@ -140,11 +144,11 @@ impl StakeAddressMap { } /// Get Pool's Live Stake (same order as spos) - pub fn get_pools_live_stakes(&self, spos: &[KeyHash]) -> Vec { - let mut live_stakes_map = HashMap::::new(); + pub fn get_pools_live_stakes(&self, spos: &[PoolId]) -> Vec { + let mut live_stakes_map = HashMap::::new(); // Collect the SPO keys and UTXO - let sas_data: Vec<(KeyHash, u64)> = self + let sas_data: Vec<(PoolId, u64)> = self .inner .values() .filter_map(|sas| sas.delegated_spo.as_ref().map(|spo| (spo.clone(), sas.utxo_value))) @@ -163,7 +167,7 @@ impl StakeAddressMap { } /// Get Pool Delegators with live_stakes - pub fn get_pool_delegators(&self, pool_operator: &KeyHash) -> Vec<(KeyHash, u64)> { + pub fn get_pool_delegators(&self, pool_operator: &PoolId) -> Vec<(KeyHash, u64)> { // Find stake addresses delegated to pool_operator let delegators: Vec<(KeyHash, u64)> = self .inner @@ -172,7 +176,10 @@ impl StakeAddressMap { Some(delegated_spo) => { if delegated_spo.eq(pool_operator) { // to_binary() now returns Result - stake_key.to_binary().ok().map(|key_hash| (key_hash, sas.utxo_value + sas.rewards)) + stake_key + .to_binary() + .ok() + .map(|key_hash| (key_hash, sas.utxo_value + sas.rewards)) } else { None } @@ -286,14 +293,14 @@ impl StakeAddressMap { /// (both with and without rewards) for each active SPO /// And Stake Pool Reward State (rewards and delegators_count for each pool) /// DelegatedStake>;Key of returned map is the SPO 'operator' ID - pub fn generate_spdd(&self) -> BTreeMap { + pub fn generate_spdd(&self) -> BTreeMap { // Shareable Dashmap with referenced keys - let spo_stakes = DashMap::::new(); + let spo_stakes = DashMap::::new(); // Total stake across all addresses in parallel, first collecting into a vector // because imbl::OrdMap doesn't work in Rayon // Collect the SPO keys and UTXO, reward values - let sas_data: Vec<(KeyHash, (u64, u64))> = self + let sas_data: Vec<(PoolId, (u64, u64))> = self .inner .values() .filter_map(|sas| { @@ -325,7 +332,7 @@ impl StakeAddressMap { /// Dump current Stake Pool Delegation Distribution State /// (Stake Key, Active Stakes Amount)> - pub fn dump_spdd_state(&self) -> HashMap> { + pub fn dump_spdd_state(&self) -> HashMap> { let entries: Vec<_> = self .inner .par_iter() @@ -334,7 +341,7 @@ impl StakeAddressMap { }) .collect(); - let mut result: HashMap> = HashMap::new(); + let mut result: HashMap> = HashMap::new(); for (spo, entry) in entries { result.entry(spo).or_default().push((entry.0.get_credential().get_hash(), entry.1)); } @@ -432,7 +439,7 @@ impl StakeAddressMap { } /// Record a stake delegation - pub fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &KeyHash) -> bool { + pub fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &PoolId) -> bool { if let Some(sas) = self.get_mut(stake_address) { if sas.registered { sas.delegated_spo = Some(spo.clone()); @@ -546,21 +553,19 @@ impl StakeAddressMap { #[cfg(test)] mod tests { use super::*; + use crate::hash::Hash; use crate::{NetworkId, StakeAddress, StakeCredential}; const STAKE_KEY_HASH: KeyHash = KeyHash::new([0x99; 28]); const STAKE_KEY_HASH_2: KeyHash = KeyHash::new([0xaa; 28]); const STAKE_KEY_HASH_3: KeyHash = KeyHash::new([0xbb; 28]); - const SPO_HASH: KeyHash = KeyHash::new([0x01; 28]); - const SPO_HASH_2: KeyHash = KeyHash::new([0x02; 28]); + const SPO_HASH: PoolId = PoolId::new(Hash::new([0xbb_u8; 28])); + const SPO_HASH_2: PoolId = PoolId::new(Hash::new([0x02_u8; 28])); const DREP_HASH: KeyHash = KeyHash::new([0xca; 28]); fn create_stake_address(hash: KeyHash) -> StakeAddress { - StakeAddress::new( - StakeCredential::AddrKeyHash(hash), - NetworkId::Mainnet, - ) + StakeAddress::new(StakeCredential::AddrKeyHash(hash), NetworkId::Mainnet) } mod registration_tests { @@ -1532,4 +1537,4 @@ mod tests { assert!(delegators.iter().any(|(_, stake)| *stake == 2000)); } } -} \ No newline at end of file +} diff --git a/common/src/types.rs b/common/src/types.rs index b420bd48..e6ec4a23 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -1035,10 +1035,10 @@ pub struct Deregistration { #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum DRepChoice { /// Address key - Key(DrepKey), + Key(KeyHash), /// Script key - Script(DrepScriptKey), + Script(KeyHash), /// Abstain Abstain, diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index 8ccc4915..9b88610b 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use acropolis_common::hash::AddrKeyhash; -use acropolis_common::PoolKeyHash; +use acropolis_common::PoolId; use anyhow::Result; use fjall::{Config, Keyspace, PartitionCreateOptions}; @@ -15,7 +15,7 @@ const TOTAL_KEY_LEN: usize = EPOCH_LEN + POOL_KEY_LENGTH + STAKE_KEY_LEN; // ~130 commits for typical epoch (~1.3M delegations) const BATCH_SIZE: usize = 10_000; -fn encode_key(epoch: u64, pool_key: &PoolKeyHash, stake_key: &AddrKeyhash) -> Vec { +fn encode_key(epoch: u64, pool_key: &PoolId, stake_key: &AddrKeyhash) -> Vec { let mut key = Vec::with_capacity(TOTAL_KEY_LEN); key.extend_from_slice(&epoch.to_be_bytes()); key.extend_from_slice(pool_key.as_ref()); @@ -23,16 +23,16 @@ fn encode_key(epoch: u64, pool_key: &PoolKeyHash, stake_key: &AddrKeyhash) -> Ve key } -fn encode_epoch_pool_prefix(epoch: u64, pool_key: &PoolKeyHash) -> Vec { +fn encode_epoch_pool_prefix(epoch: u64, pool_key: &PoolId) -> Vec { let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_KEY_LENGTH); prefix.extend_from_slice(&epoch.to_be_bytes()); prefix.extend_from_slice(pool_key.as_ref()); prefix } -fn decode_key(key: &[u8]) -> Result<(u64, PoolKeyHash, AddrKeyhash)> { +fn decode_key(key: &[u8]) -> Result<(u64, PoolId, AddrKeyhash)> { let epoch = u64::from_be_bytes(key[..EPOCH_LEN].try_into()?); - let pool_key: PoolKeyHash = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].try_into()?; + let pool_key: PoolId = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].try_into()?; let stake_key: AddrKeyhash = key[EPOCH_LEN + POOL_KEY_LENGTH..].try_into()?; Ok((epoch, pool_key, stake_key)) } @@ -101,7 +101,7 @@ impl SPDDStore { pub fn store_spdd( &mut self, epoch: u64, - spdd_state: HashMap>, + spdd_state: HashMap>, ) -> fjall::Result<()> { if self.is_epoch_complete(epoch)? { return Ok(()); @@ -183,7 +183,7 @@ impl SPDDStore { Ok(deleted_epochs) } - pub fn query_by_epoch(&self, epoch: u64) -> Result> { + pub fn query_by_epoch(&self, epoch: u64) -> Result> { if !self.is_epoch_complete(epoch)? { return Err(anyhow::anyhow!("Epoch SPDD Data is not complete")); } @@ -202,7 +202,7 @@ impl SPDDStore { pub fn query_by_epoch_and_pool( &self, epoch: u64, - pool_key: &PoolKeyHash, + pool_key: &PoolId, ) -> Result> { if !self.is_epoch_complete(epoch)? { return Err(anyhow::anyhow!("Epoch SPDD Data is not complete")); @@ -226,12 +226,13 @@ mod tests { use acropolis_common::crypto::keyhash_224; // ADDED use acropolis_common::hash::AddrKeyhash; + use acropolis_common::PoolId; const DB_PATH: &str = "spdd_db"; // ADDED: Helper to create test hashes - fn test_pool_hash(byte: u8) -> PoolKeyHash { - keyhash_224(&vec![byte]) + fn test_pool_hash(byte: u8) -> PoolId { + PoolId::new(keyhash_224(&vec![byte])) } fn test_addr_hash(byte: u8) -> AddrKeyhash { @@ -242,7 +243,7 @@ mod tests { fn test_store_spdd_state() { let mut spdd_store = SPDDStore::new(std::path::Path::new(DB_PATH), 1).expect("Failed to create SPDD store"); - let mut spdd_state: HashMap> = HashMap::new(); + let mut spdd_state: HashMap> = HashMap::new(); spdd_state.insert( test_pool_hash(0x01), @@ -269,7 +270,7 @@ mod tests { .expect("Failed to create SPDD store"); for epoch in 1..=3 { - let mut spdd_state: HashMap> = HashMap::new(); + let mut spdd_state: HashMap> = HashMap::new(); spdd_state.insert( test_pool_hash(epoch as u8), diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index a47c9b37..0b2ba339 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -4,19 +4,11 @@ use crate::rewards::{calculate_rewards, RewardsResult}; use crate::snapshot::Snapshot; use crate::verifier::Verifier; use acropolis_common::queries::accounts::OptimalPoolSizing; -use acropolis_common::{ - math::update_value_with_delta, - messages::{ - DRepDelegationDistribution, DRepStateMessage, EpochActivityMessage, PotDeltasMessage, - ProtocolParamsMessage, SPOStateMessage, StakeAddressDeltasMessage, TxCertificatesMessage, - WithdrawalsMessage, - }, - protocol_params::ProtocolParams, - stake_addresses::{StakeAddressMap, StakeAddressState}, - BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, - InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolLiveStakeInfo, - PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, TxCertificate, -}; +use acropolis_common::{math::update_value_with_delta, messages::{ + DRepDelegationDistribution, DRepStateMessage, EpochActivityMessage, PotDeltasMessage, + ProtocolParamsMessage, SPOStateMessage, StakeAddressDeltasMessage, TxCertificatesMessage, + WithdrawalsMessage, +}, protocol_params::ProtocolParams, stake_addresses::{StakeAddressMap, StakeAddressState}, BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolId, PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, TxCertificate}; use anyhow::Result; use imbl::OrdMap; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -164,17 +156,17 @@ impl State { } /// Get Pool Live Stake Info - pub fn get_pool_live_stake_info(&self, pool_operator: &KeyHash) -> PoolLiveStakeInfo { + pub fn get_pool_live_stake_info(&self, pool_operator: &PoolId) -> PoolLiveStakeInfo { self.stake_addresses.lock().unwrap().get_pool_live_stake_info(pool_operator) } /// Get Pools Live stake - pub fn get_pools_live_stakes(&self, pool_operators: &Vec) -> Vec { + pub fn get_pools_live_stakes(&self, pool_operators: &Vec) -> Vec { self.stake_addresses.lock().unwrap().get_pools_live_stakes(pool_operators) } /// Get Pool Delegators with live_stakes - pub fn get_pool_delegators(&self, pool_operator: &KeyHash) -> Vec<(KeyHash, u64)> { + pub fn get_pool_delegators(&self, pool_operator: &PoolId) -> Vec<(KeyHash, u64)> { self.stake_addresses.lock().unwrap().get_pool_delegators(pool_operator) } diff --git a/modules/rest_blockfrost/src/handlers/accounts.rs b/modules/rest_blockfrost/src/handlers/accounts.rs index 09ff6e08..16e141dd 100644 --- a/modules/rest_blockfrost/src/handlers/accounts.rs +++ b/modules/rest_blockfrost/src/handlers/accounts.rs @@ -83,7 +83,7 @@ pub async fn handle_single_account_blockfrost( .await?; let delegated_spo = match &account.delegated_spo { - Some(spo) => match spo.to_bech32_with_hrp("pool") { + Some(spo) => match spo.to_bech32() { Ok(val) => Some(val), Err(e) => { return Ok(RESTResponse::with_text( diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index 75cf555c..7fb79c57 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -4,14 +4,19 @@ use crate::{ EpochActivityRest, ProtocolParamsRest, SPDDByEpochAndPoolItemRest, SPDDByEpochItemRest, }, }; -use acropolis_common::{messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse}, - epochs::{EpochsStateQuery, EpochsStateQueryResponse}, - parameters::{ParametersStateQuery, ParametersStateQueryResponse}, - pools::{PoolsStateQuery, PoolsStateQueryResponse}, - spdd::{SPDDStateQuery, SPDDStateQueryResponse}, - utils::query_state, -}, serialization::Bech32WithHrp, KeyHash, NetworkId, StakeAddress, StakeCredential}; +use acropolis_common::{ + messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, + queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse}, + epochs::{EpochsStateQuery, EpochsStateQueryResponse}, + parameters::{ParametersStateQuery, ParametersStateQueryResponse}, + pools::{PoolsStateQuery, PoolsStateQueryResponse}, + spdd::{SPDDStateQuery, SPDDStateQueryResponse}, + utils::query_state, + }, + serialization::Bech32WithHrp, + NetworkId, PoolId, StakeAddress, StakeCredential, +}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; use std::sync::Arc; @@ -703,7 +708,7 @@ pub async fn handle_epoch_pool_blocks_blockfrost( // query Pool's Blocks by epoch from spo-state let msg = Arc::new(Message::StateQuery(StateQuery::Pools( PoolsStateQuery::GetBlocksByPoolAndEpoch { - pool_id: KeyHash::try_from(spo.clone()).unwrap(), + pool_id: PoolId::try_from(spo.clone()).unwrap(), epoch: epoch_number, }, ))); diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index 17eb6b15..a0d028d3 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -1,23 +1,17 @@ //! REST handlers for Acropolis Blockfrost /pools endpoints -use acropolis_common::{ - messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, - queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse}, - epochs::{EpochsStateQuery, EpochsStateQueryResponse}, - pools::{PoolsStateQuery, PoolsStateQueryResponse}, - utils::query_state, - }, - rest_helper::ToCheckedF64, - serialization::Bech32WithHrp, - PoolRetirement, PoolUpdateAction, StakeCredential, TxHash, -}; +use acropolis_common::{messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse}, + epochs::{EpochsStateQuery, EpochsStateQueryResponse}, + pools::{PoolsStateQuery, PoolsStateQueryResponse}, + utils::query_state, +}, rest_helper::ToCheckedF64, serialization::Bech32WithHrp, PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxHash}; use anyhow::Result; use caryatid_sdk::Context; use rust_decimal::Decimal; use std::{sync::Arc, time::Duration}; use tokio::join; use tracing::warn; - +use acropolis_common::serialization::Bech32Conversion; use crate::{ handlers_config::HandlersConfig, types::{PoolDelegatorRest, PoolInfoRest, PoolRelayRest, PoolUpdateEventRest, PoolVoteRest}, @@ -63,7 +57,7 @@ pub async fn handle_pools_list_blockfrost( let pool_ids = pool_operators .iter() - .map(|operator| operator.to_bech32_with_hrp("pool")) + .map(|operator| operator.to_bech32()) .collect::, _>>(); match pool_ids { @@ -102,7 +96,7 @@ pub async fn handle_pools_extended_retired_retiring_single_blockfrost( "retiring" => { return handle_pools_retiring_blockfrost(context.clone(), handlers_config.clone()).await } - _ => match Vec::::from_bech32_with_hrp(param, "pool") { + _ => match PoolId::from_bech32(param) { Ok(pool_id) => { return handle_pools_spo_blockfrost( context.clone(), @@ -205,7 +199,7 @@ async fn handle_pools_extended_blockfrost( let latest_epoch = latest_epoch_info.epoch; let optimal_pool_sizing = optimal_pool_sizing?; - // if pools are empty, return empty list + // if pools are empty, return an empty list if pools_list_with_info.is_empty() { return Ok(RESTResponse::with_json(200, "[]")); } @@ -222,7 +216,7 @@ async fn handle_pools_extended_blockfrost( .map(|(pool_operator, _)| pool_operator.clone()) .collect::>(); - // Get active stake for each pool from spo-state + // Get an active stake for each pool from spo-state let pools_active_stakes_msg = Arc::new(Message::StateQuery(StateQuery::Pools( PoolsStateQuery::GetPoolsActiveStakes { pools_operators: pools_operators.clone(), @@ -311,8 +305,8 @@ async fn handle_pools_extended_blockfrost( .enumerate() .map(|(i, (pool_operator, pool_registration))| { Ok(PoolExtendedRest { - pool_id: pool_operator.to_bech32_with_hrp("pool")?, - hex: pool_operator.clone(), + pool_id: pool_operator.to_bech32()?, + hex: pool_operator.to_vec(), active_stake: pools_active_stakes .as_ref() .map(|active_stakes| active_stakes[i]), @@ -372,7 +366,7 @@ async fn handle_pools_retired_blockfrost( let retired_pools_rest = retired_pools .iter() .filter_map(|PoolRetirement { operator, epoch }| { - let pool_id = operator.to_bech32_with_hrp("pool").ok()?; + let pool_id = operator.to_bech32().ok()?; Some(PoolRetirementRest { pool_id, epoch: *epoch, @@ -418,7 +412,7 @@ async fn handle_pools_retiring_blockfrost( let retiring_pools_rest = retiring_pools .iter() .filter_map(|PoolRetirement { operator, epoch }| { - let pool_id = operator.to_bech32_with_hrp("pool").ok()?; + let pool_id = operator.to_bech32().ok()?; Some(PoolRetirementRest { pool_id, epoch: *epoch, @@ -437,7 +431,7 @@ async fn handle_pools_retiring_blockfrost( async fn handle_pools_spo_blockfrost( context: Arc>, - pool_operator: Vec, + pool_operator: PoolId, handlers_config: Arc, ) -> Result { // Get PoolRegistration from spo state @@ -691,7 +685,7 @@ async fn handle_pools_spo_blockfrost( let active_stakes_info = active_stakes_info?; let live_pledge = live_pledge?; - let pool_id = pool_info.operator.to_bech32_with_hrp("pool").unwrap(); + let pool_id = pool_info.operator.to_bech32()?; let reward_account = pool_info.reward_account.get_credential().to_stake_bech32(); let Ok(reward_account) = reward_account else { return Ok(RESTResponse::with_text(404, "Invalid Reward Account")); @@ -749,7 +743,7 @@ pub async fn handle_pool_history_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -823,7 +817,7 @@ pub async fn handle_pool_metadata_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -904,7 +898,7 @@ pub async fn handle_pool_relays_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -958,7 +952,7 @@ pub async fn handle_pool_delegators_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -1055,7 +1049,7 @@ pub async fn handle_pool_blocks_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -1107,7 +1101,7 @@ pub async fn handle_pool_updates_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -1167,7 +1161,7 @@ pub async fn handle_pool_votes_blockfrost( return Ok(RESTResponse::with_text(400, "Missing pool ID parameter")); }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index 480b644a..c024f3fe 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -1,14 +1,5 @@ use crate::cost_models::{PLUTUS_V1, PLUTUS_V2, PLUTUS_V3}; -use acropolis_common::{ - messages::EpochActivityMessage, - protocol_params::{Nonce, NonceVariant, ProtocolParams}, - queries::blocks::BlockInfo, - queries::governance::DRepActionUpdate, - rest_helper::ToCheckedF64, - serialization::{DisplayFromBech32, PoolPrefix}, - AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolUpdateAction, Relay, TxHash, Vote, -}; +use acropolis_common::{messages::EpochActivityMessage, protocol_params::{Nonce, NonceVariant, ProtocolParams}, queries::blocks::BlockInfo, queries::governance::DRepActionUpdate, rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, PoolEpochState, PoolUpdateAction, Relay, TxHash, VRFKey, Vote}; use anyhow::Result; use num_traits::ToPrimitive; use rust_decimal::Decimal; @@ -432,7 +423,7 @@ pub struct PoolInfoRest { #[serde_as(as = "Hex")] pub hex: KeyHash, #[serde_as(as = "Hex")] - pub vrf_key: KeyHash, + pub vrf_key: VRFKey, pub blocks_minted: u64, pub blocks_epoch: u64, #[serde_as(as = "DisplayFromStr")] diff --git a/modules/spo_state/src/epochs_history.rs b/modules/spo_state/src/epochs_history.rs index b2135d3c..4ba7316c 100644 --- a/modules/spo_state/src/epochs_history.rs +++ b/modules/spo_state/src/epochs_history.rs @@ -216,19 +216,22 @@ mod tests { #[test] fn get_pool_history_returns_none_when_spo_is_not_found() { + let key_hash = KeyHash::new([1; 28]); let epochs_history = EpochsHistoryState::new(save_history_store_config()); - let pool_history = epochs_history.get_pool_history(&vec![1]); + let pool_history = epochs_history.get_pool_history(&key_hash); assert!(pool_history.is_none()); } #[test] fn get_pool_history_returns_data() { let epochs_history = EpochsHistoryState::new(save_history_store_config()); + let key_hash = KeyHash::new([1; 28]); + let spo_block_key_hash = KeyHash::new([2; 28]); let block = new_block(2); let mut spdd_msg = new_spdd_message(1); spdd_msg.spos = vec![( - vec![1], + key_hash, DelegatedStake { active: 1, active_delegators_count: 1, @@ -238,14 +241,14 @@ mod tests { epochs_history.handle_spdd(&block, &spdd_msg); let mut epoch_activity_msg = new_epoch_activity_message(1); - epoch_activity_msg.spo_blocks = vec![(vec![11], 1)]; + epoch_activity_msg.spo_blocks = vec![(spo_block_key_hash, 1)]; epoch_activity_msg.total_blocks = 1; epoch_activity_msg.total_fees = 10; - epochs_history.handle_epoch_activity(&block, &epoch_activity_msg, &vec![(vec![1], 1)]); + epochs_history.handle_epoch_activity(&block, &epoch_activity_msg, &vec![(key_hash, 1)]); let mut spo_rewards_msg = new_spo_rewards_message(1); spo_rewards_msg.spos = vec![( - vec![1], + key_hash, SPORewards { total_rewards: 100, operator_rewards: 10, @@ -253,7 +256,7 @@ mod tests { )]; epochs_history.handle_spo_rewards(&block, &spo_rewards_msg); - let pool_history = epochs_history.get_pool_history(&vec![1]).unwrap(); + let pool_history = epochs_history.get_pool_history(&key_hash).unwrap(); assert_eq!(2, pool_history.len()); let first_epoch = pool_history.get(0).unwrap(); let third_epoch = pool_history.get(1).unwrap(); diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 24a90c7d..33176998 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -20,7 +20,7 @@ pub struct State { epoch: u64, - spos: HashMap, + spos: HashMap, pending_updates: HashMap, @@ -88,7 +88,7 @@ impl State { impl From for State { fn from(value: SPOState) -> Self { - let spos: HashMap = value.pools.into(); + let spos: HashMap = value.pools.into(); let pending_deregistrations = value.retiring.into_iter().fold(HashMap::new(), |mut acc, (key_hash, epoch)| { acc.entry(epoch).or_insert_with(Vec::new).push(key_hash); @@ -139,7 +139,7 @@ impl State { } /// Get total blocks minted by pools - pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { + pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { pools_operators .iter() .map(|pool_operator| *self.total_blocks_minted.get(pool_operator).unwrap_or(&0)) @@ -147,12 +147,12 @@ impl State { } /// Get total blocks minted by pool - pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &PoolId) -> u64 { + pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &KeyHash) -> u64 { *self.total_blocks_minted.get(pool_operator).unwrap_or(&0) } /// Get all Stake Pool operators' operator hashes - pub fn list_pool_operators(&self) -> Vec { + pub fn list_pool_operators(&self) -> Vec { self.spos.keys().cloned().collect() } @@ -664,29 +664,21 @@ impl State { } } +// -- Tests -- #[cfg(test)] mod tests { use super::*; use crate::test_utils::*; - use acropolis_common::{state_history::{StateHistory, StateHistoryStore}, PoolId, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey}; + use acropolis_common::{state_history::{StateHistory, StateHistoryStore}, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey}; use tokio::sync::Mutex; - fn test_pool_id(byte: u8) -> PoolId { - PoolId::from(keyhash_224(&vec![byte])) - } - - fn test_keyhash_from_bytes(bytes: &[u8]) -> KeyHash { - keyhash_224(bytes) - } - - fn default_pool_registration( operator: KeyHash, vrf_key_hash: Option, ) -> PoolRegistration { PoolRegistration { operator: operator.clone(), - vrf_key_hash: vrf_key_hash.unwrap_or_else(|| VRFKey::default()), + vrf_key_hash: vrf_key_hash.unwrap_or_else(|| vec![0]), pledge: 0, cost: 0, margin: Ratio { @@ -703,8 +695,7 @@ mod tests { #[test] fn get_returns_none_on_empty_state() { let state = State::default(); - let pool_id = test_pool_id(0); // Changed - assert!(state.get(&pool_id).is_none()); // Changed + assert!(state.get(&vec![0]).is_none()); } #[test] @@ -726,10 +717,9 @@ mod tests { async fn spo_gets_registered() { let mut state = State::default(); let mut msg = new_certs_msg(); - let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(pool_id.clone(), None) + reg: default_pool_registration(vec![0], None), tx_hash: TxHash::default(), cert_index: 1, }, @@ -737,7 +727,7 @@ mod tests { let block = new_block(1); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&pool_id); // Changed + let spo = state.spos.get(&vec![0]); assert!(!spo.is_none()); } @@ -745,11 +735,10 @@ mod tests { async fn pending_deregistration_gets_queued() { let mut state = State::default(); let mut msg = new_certs_msg(); - let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id.clone() + operator: vec![0], epoch: 1, }, tx_hash: TxHash::default(), @@ -763,7 +752,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&pool_id)); // Changed + assert!(drs.contains(&vec![0])); } } @@ -772,13 +761,10 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); - let pool_id_0 = test_pool_id(0); // Changed - let pool_id_1 = test_pool_id(1); // Changed - msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_0.clone() + operator: vec![0], epoch: 2, }, tx_hash: TxHash::default(), @@ -792,7 +778,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_1.clone() + operator: vec![1], epoch: 2, }, tx_hash: TxHash::default(), @@ -806,8 +792,8 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(2, drs.len()); - assert!(drs.contains(&pool_id_0)); // Changed - assert!(drs.contains(&pool_id_1)); // Changed + assert!(drs.contains(&vec![0u8])); + assert!(drs.contains(&vec![1u8])); } } @@ -820,13 +806,10 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); - let pool_id_0 = test_pool_id(0); // Changed - let pool_id_1 = test_pool_id(1); // Changed - msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_0.clone() + operator: vec![0], epoch: 2, }, tx_hash: TxHash::default(), @@ -842,43 +825,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_1.clone() - epoch: 2, - }, - tx_hash: TxHash::default(), - cert_index: 0, - }, - )); - assert!(state.handle_tx_certs(&block, &msg).is_ok()); - history.lock().await.commit(block.number, state); - - block.number = 1; - let mut state = history.lock().await.get_rolled_back_state(block.number); - msg = new_certs_msg(); - assert!(state.handle_tx_certs(&block, &msg).is_ok()); - assert_eq!(1, state.pending_deregistrations.len()); - let drs = state.pending_deregistrations.get(&2); - assert!(!drs.is_none()); - if let Some(drs) = drs { - assert_eq!(1, drs.len()); - assert!(drs.contains(&pool_id_0)); // Changed - } - } - - #[tokio::test] - async fn spo_gets_deregistered_on_deregistration() { - let history = Arc::new(Mutex::new(StateHistory::::new( - "spo_state", - StateHistoryStore::default_block_store(), - ))); - let mut state = history.lock().await.get_current_state(); - let mut block = new_block(0); - let mut msg = new_certs_msg(); - let pool_id = test_pool_id(0); // Changed - msg.certificates.push(TxCertificate::PoolRetirementWithPos( - PoolRetirementWithPos { - ret: PoolRetirement { - operator: pool_id.clone() + operator: vec![1], epoch: 2, }, tx_hash: TxHash::default(), @@ -897,7 +844,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&pool_id)); // Changed + assert!(drs.contains(&vec![0])); } } @@ -906,10 +853,9 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); - let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(pool_id.clone(), None) + reg: default_pool_registration(vec![0], None), tx_hash: TxHash::default(), cert_index: 0, }, @@ -917,7 +863,7 @@ mod tests { assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&pool_id); // Changed + let spo = state.spos.get(&vec![0u8]); assert!(!spo.is_none()); block.number = 1; @@ -925,7 +871,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id.clone() + operator: vec![0], epoch: 1, }, tx_hash: TxHash::default(), @@ -950,17 +896,16 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); - let pool_id = test_pool_id(0); // Changed msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(pool_id.clone(), None) + reg: default_pool_registration(vec![0], None), tx_hash: TxHash::default(), cert_index: 0, }, )); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&pool_id); // Changed + let spo = state.spos.get(&vec![0u8]); assert!(!spo.is_none()); history.lock().await.commit(block.number, state); @@ -970,7 +915,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id.clone() + operator: vec![0], epoch: 1, }, tx_hash: TxHash::default(), @@ -994,7 +939,7 @@ mod tests { let mut state = history.lock().await.get_rolled_back_state(block.number); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&pool_id); // Changed + let spo = state.spos.get(&vec![0]); assert!(!spo.is_none()); } @@ -1009,13 +954,10 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); - let pool_id_0 = test_pool_id(0); // Changed - let pool_id_1 = test_pool_id(1); // Changed - msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_0.clone() + operator: vec![0], epoch: 2, }, tx_hash: TxHash::default(), @@ -1029,7 +971,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_id_1.clone() + operator: vec![1], epoch: 3, }, tx_hash: TxHash::default(), @@ -1040,21 +982,17 @@ mod tests { let mut retiring_pools = state.get_retiring_pools(); retiring_pools.sort_by_key(|p| p.epoch); assert_eq!(2, retiring_pools.len()); - assert_eq!(pool_id_0, retiring_pools[0].operator); // Changed + assert_eq!(vec![0], retiring_pools[0].operator); assert_eq!(2, retiring_pools[0].epoch); - assert_eq!(pool_id_1, retiring_pools[1].operator); // Changed + assert_eq!(vec![1], retiring_pools[1].operator); assert_eq!(3, retiring_pools[1].epoch); } #[test] fn get_total_blocks_minted_returns_zeros_when_state_is_new() { let state = State::default(); - let pool_id = test_pool_id(0); // Changed - assert_eq!( - 0, - state.get_total_blocks_minted_by_pools(&vec![pool_id.clone()])[0] - ); // Changed - assert_eq!(0, state.get_total_blocks_minted_by_pool(&pool_id)); // Changed + assert_eq!(0, state.get_total_blocks_minted_by_pools(&vec![vec![0]])[0]); + assert_eq!(0, state.get_total_blocks_minted_by_pool(&vec![0])); } #[test] @@ -1084,8 +1022,7 @@ mod tests { #[test] fn get_blocks_returns_none_when_blocks_not_enabled() { let state = State::default(); - let pool_id = test_pool_id(0); // Changed - assert!(state.get_blocks_by_pool(&pool_id).is_none()); // Changed + assert!(state.get_blocks_by_pool(&vec![0]).is_none()); } #[test] From fe2b0d62dc6eeb85f43496cd5c2d10b47905bb5e Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 10:38:43 -0700 Subject: [PATCH 04/20] Fix epochs state / update rest handlers --- codec/src/map_parameters.rs | 11 +- common/src/address.rs | 35 ++-- common/src/ledger_state.rs | 4 +- common/src/messages.rs | 6 +- common/src/queries/accounts.rs | 4 +- common/src/queries/epochs.rs | 4 +- common/src/queries/pools.rs | 5 +- common/src/snapshot/pool_params.rs | 5 +- common/src/types.rs | 21 ++- modules/accounts_state/src/rewards.rs | 10 +- modules/accounts_state/src/snapshot.rs | 21 +-- .../src/spo_distribution_publisher.rs | 6 +- .../src/spo_rewards_publisher.rs | 4 +- modules/accounts_state/src/state.rs | 98 +++++------ modules/accounts_state/src/verifier.rs | 12 +- modules/epochs_state/src/state.rs | 17 +- modules/governance_state/src/state.rs | 4 +- .../src/immutable_historical_account_store.rs | 24 ++- .../historical_accounts_state/src/state.rs | 9 +- .../rest_blockfrost/src/handlers/accounts.rs | 2 +- modules/rest_blockfrost/src/handlers/pools.rs | 33 ++-- modules/rest_blockfrost/src/types.rs | 13 +- modules/spdd_state/src/rest.rs | 9 +- modules/spdd_state/src/state.rs | 13 +- modules/spo_state/src/epochs_history.rs | 8 +- .../spo_state/src/retired_pools_history.rs | 15 +- modules/spo_state/src/spo_state.rs | 4 +- modules/spo_state/src/state.rs | 163 +++++++++++------- modules/stake_delta_filter/src/utils.rs | 7 +- 29 files changed, 325 insertions(+), 242 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 75e0cffc..ff7d2ad2 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -18,7 +18,6 @@ use acropolis_common::{ rational_number::RationalNumber, *, }; -use pallas_primitives::Bytes; use std::collections::{HashMap, HashSet}; /// Map Pallas Network to our NetworkId @@ -32,15 +31,13 @@ pub fn map_network(network: addresses::Network) -> Result { /// Convert from Pallas Hash to Acropolis Hash pub fn pallas_hash_to_acropolis( - pallas_hash: &pallas_primitives::Hash + pallas_hash: &pallas_primitives::Hash, ) -> Hash { Hash::new(**pallas_hash) } /// Convert from Acropolis Hash to Pallas Hash -pub fn acropolis_hash_to_pallas( - our_hash: &Hash -) -> pallas_primitives::Hash { +pub fn acropolis_hash_to_pallas(our_hash: &Hash) -> pallas_primitives::Hash { pallas_primitives::Hash::new(**our_hash) } @@ -127,7 +124,9 @@ pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> pub fn map_drep(drep: &conway::DRep) -> DRepChoice { match drep { conway::DRep::Key(key_hash) => DRepChoice::Key(pallas_hash_to_acropolis(key_hash)), - conway::DRep::Script(script_hash) => DRepChoice::Script(pallas_hash_to_acropolis(script_hash)), + conway::DRep::Script(script_hash) => { + DRepChoice::Script(pallas_hash_to_acropolis(script_hash)) + } conway::DRep::Abstain => DRepChoice::Abstain, conway::DRep::NoConfidence => DRepChoice::NoConfidence, } diff --git a/common/src/address.rs b/common/src/address.rs index a5eb161e..a2cf6e73 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -213,20 +213,22 @@ impl ShelleyAddress { let payment_part = match (header >> 4) & 0x01 { 0 => ShelleyAddressPaymentPart::PaymentKeyHash( - data[1..29].try_into().map_err(|_| anyhow!("Invalid payment key hash size"))? + data[1..29].try_into().map_err(|_| anyhow!("Invalid payment key hash size"))?, ), 1 => ShelleyAddressPaymentPart::ScriptHash( - data[1..29].try_into().map_err(|_| anyhow!("Invalid script hash size"))? + data[1..29].try_into().map_err(|_| anyhow!("Invalid script hash size"))?, ), _ => panic!(), }; let delegation_part = match (header >> 5) & 0x03 { 0 => ShelleyAddressDelegationPart::StakeKeyHash( - data[29..57].try_into().map_err(|_| anyhow!("Invalid stake key hash size"))? + data[29..57].try_into().map_err(|_| anyhow!("Invalid stake key hash size"))?, ), 1 => ShelleyAddressDelegationPart::ScriptHash( - data[29..57].try_into().map_err(|_| anyhow!("Invalid delegation script hash size"))? + data[29..57] + .try_into() + .map_err(|_| anyhow!("Invalid delegation script hash size"))?, ), 2 => { let mut decoder = VarIntDecoder::new(&data[29..]); @@ -416,8 +418,12 @@ impl StakeAddress { }; let credential = match (header >> 4) & 0x0Fu8 { - 0b1110 => StakeCredential::AddrKeyHash(data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?), - 0b1111 => StakeCredential::ScriptHash(data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?), + 0b1110 => StakeCredential::AddrKeyHash( + data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?, + ), + 0b1111 => StakeCredential::ScriptHash( + data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?, + ), _ => return Err(anyhow!("Unknown header {header} in stake address")), }; @@ -447,7 +453,6 @@ impl StakeAddress { data.try_into().map_err(|_| anyhow!("Invalid hash size for stake address")) } - /// Read from binary format (29 bytes) pub fn from_binary(data: &[u8]) -> Result { if data.len() != 29 { @@ -460,8 +465,12 @@ impl StakeAddress { }; let credential = match (data[0] >> 4) & 0x0F { - 0b1110 => StakeCredential::AddrKeyHash(data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?), - 0b1111 => StakeCredential::ScriptHash(data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?), + 0b1110 => StakeCredential::AddrKeyHash( + data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?, + ), + 0b1111 => StakeCredential::ScriptHash( + data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?, + ), _ => bail!("Unknown header byte {:x} in stake address", data[0]), }; @@ -502,7 +511,9 @@ impl minicbor::Encode for StakeAddress { e: &mut minicbor::Encoder, _ctx: &mut C, ) -> Result<(), minicbor::encode::Error> { - let data = self.to_binary().map_err(|_| minicbor::encode::Error::message("Failed to convert to binary"))?; + let data = self + .to_binary() + .map_err(|_| minicbor::encode::Error::message("Failed to convert to binary"))?; e.bytes(&data.as_slice())?; Ok(()) } @@ -822,7 +833,7 @@ mod tests { fn shelley_type_14() { let address = Address::Stake(StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(KeyHash::from(test_stake_key_hash())) + credential: StakeCredential::AddrKeyHash(KeyHash::from(test_stake_key_hash())), }); let text = address.to_string().unwrap(); @@ -1029,4 +1040,4 @@ mod tests { let result = StakeAddress::decode(&mut decoder, &mut ()); assert!(result.is_err()); } -} \ No newline at end of file +} diff --git a/common/src/ledger_state.rs b/common/src/ledger_state.rs index 3ccb0d5a..648c6595 100644 --- a/common/src/ledger_state.rs +++ b/common/src/ledger_state.rs @@ -1,4 +1,6 @@ -use crate::{MultiHostName, PoolId, PoolRegistration, Ratio, Relay, SingleHostAddr, SingleHostName}; +use crate::{ + MultiHostName, PoolId, PoolRegistration, Ratio, Relay, SingleHostAddr, SingleHostName, +}; use anyhow::{bail, Context, Result}; use minicbor::data::Tag; use std::{collections::BTreeMap, fs, path::Path}; diff --git a/common/src/messages.rs b/common/src/messages.rs index c095bbfe..c426b893 100644 --- a/common/src/messages.rs +++ b/common/src/messages.rs @@ -179,7 +179,7 @@ pub struct EpochActivityMessage { pub total_fees: u64, /// Map of SPO IDs to blocks produced - pub spo_blocks: Vec<(KeyHash, usize)>, + pub spo_blocks: Vec<(PoolId, usize)>, /// Nonce pub nonce: Option, @@ -233,7 +233,7 @@ pub struct SPOStakeDistributionMessage { pub epoch: u64, /// SPO stake distribution by operator ID - pub spos: Vec<(KeyHash, DelegatedStake)>, + pub spos: Vec<(PoolId, DelegatedStake)>, } #[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] @@ -242,7 +242,7 @@ pub struct SPORewardsMessage { pub epoch: u64, /// SPO rewards by operator ID (total rewards before distribution, pool operator's rewards) - pub spos: Vec<(KeyHash, SPORewards)>, + pub spos: Vec<(PoolId, SPORewards)>, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/common/src/queries/accounts.rs b/common/src/queries/accounts.rs index de2dd726..d8a11a98 100644 --- a/common/src/queries/accounts.rs +++ b/common/src/queries/accounts.rs @@ -31,7 +31,7 @@ pub enum AccountsStateQuery { // Epochs-related queries GetActiveStakes {}, GetSPDDByEpoch { epoch: u64 }, - GetSPDDByEpochAndPool { epoch: u64, pool_id: KeyHash }, + GetSPDDByEpochAndPool { epoch: u64, pool_id: PoolId }, // Pools related queries GetOptimalPoolSizing, @@ -65,7 +65,7 @@ pub enum AccountsStateQueryResponse { // Epochs-related responses ActiveStakes(u64), /// Vec<(PoolId, StakeKey, ActiveStakeAmount)> - SPDDByEpoch(Vec<(KeyHash, KeyHash, u64)>), + SPDDByEpoch(Vec<(PoolId, KeyHash, u64)>), /// Vec<(StakeKey, ActiveStakeAmount)> SPDDByEpochAndPool(Vec<(KeyHash, u64)>), diff --git a/common/src/queries/epochs.rs b/common/src/queries/epochs.rs index 5ef179f2..8b3abee5 100644 --- a/common/src/queries/epochs.rs +++ b/common/src/queries/epochs.rs @@ -1,4 +1,4 @@ -use crate::{messages::EpochActivityMessage, protocol_params::ProtocolParams, KeyHash}; +use crate::{messages::EpochActivityMessage, protocol_params::ProtocolParams, PoolId}; pub const DEFAULT_EPOCHS_QUERY_TOPIC: (&str, &str) = ("epochs-state-query-topic", "cardano.query.epochs"); @@ -11,7 +11,7 @@ pub enum EpochsStateQuery { GetPreviousEpochs { epoch_number: u64 }, GetEpochStakeDistribution { epoch_number: u64 }, GetEpochStakeDistributionByPool { epoch_number: u64 }, - GetLatestEpochBlocksMintedByPool { spo_id: KeyHash }, + GetLatestEpochBlocksMintedByPool { spo_id: PoolId }, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] diff --git a/common/src/queries/pools.rs b/common/src/queries/pools.rs index a715b74e..04d9f59f 100644 --- a/common/src/queries/pools.rs +++ b/common/src/queries/pools.rs @@ -1,4 +1,7 @@ -use crate::{queries::governance::VoteRecord, rational_number::RationalNumber, KeyHash, PoolEpochState, PoolId, PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, Relay}; +use crate::{ + queries::governance::VoteRecord, rational_number::RationalNumber, KeyHash, PoolEpochState, + PoolId, PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, Relay, +}; pub const DEFAULT_POOLS_QUERY_TOPIC: (&str, &str) = ("pools-state-query-topic", "cardano.query.pools"); diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index 2febc7e4..c81a0eee 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{PoolId, VRFKey}; use super::streaming_snapshot::{ - cbor, AddrKeyhash, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, - UnitInterval, + cbor, AddrKeyhash, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, }; +use crate::{PoolId, VRFKey}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PoolParams { diff --git a/common/src/types.rs b/common/src/types.rs index e6ec4a23..333964da 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -3,7 +3,12 @@ #![allow(dead_code)] use crate::hash::{AddrKeyhash, Hash, ScriptHash}; -use crate::{address::{Address, ShelleyAddress, StakeAddress}, declare_hash_newtype_with_bech32, declare_hash_type, declare_hash_type_with_bech32, protocol_params, rational_number::RationalNumber}; +use crate::{ + address::{Address, ShelleyAddress, StakeAddress}, + declare_hash_newtype_with_bech32, declare_hash_type, declare_hash_type_with_bech32, + protocol_params, + rational_number::RationalNumber, +}; use anyhow::{anyhow, bail, Error, Result}; use bech32::{Bech32, Hrp}; use bitmask_enum::bitmask; @@ -834,7 +839,7 @@ pub struct PoolRegistration { /// Operator pool key hash - used as ID #[serde_as(as = "Hex")] #[n(0)] - pub operator: KeyHash, + pub operator: PoolId, /// VRF key hash #[serde_as(as = "Hex")] @@ -1064,7 +1069,7 @@ pub struct StakeAndVoteDelegation { pub stake_address: StakeAddress, /// Pool - pub operator: KeyHash, + pub operator: PoolId, // DRep vote pub drep: DRepChoice, @@ -1077,7 +1082,7 @@ pub struct StakeRegistrationAndDelegation { pub stake_address: StakeAddress, /// Pool - pub operator: KeyHash, + pub operator: PoolId, // Deposit paid pub deposit: Lovelace, @@ -1105,7 +1110,7 @@ pub struct StakeRegistrationAndStakeAndVoteDelegation { pub stake_address: StakeAddress, /// Pool - pub operator: KeyHash, + pub operator: PoolId, /// DRep choice pub drep: DRepChoice, @@ -1654,7 +1659,7 @@ pub enum Voter { ConstitutionalCommitteeScript(ScriptHash), DRepKey(AddrKeyhash), DRepScript(ScriptHash), - StakePoolKey(AddrKeyhash), + StakePoolKey(PoolId), } impl Voter { @@ -2010,7 +2015,7 @@ mod tests { let mut test_hash_bytes = [0u8; 28]; test_hash_bytes[0..4].copy_from_slice(&[1, 2, 3, 4]); voting.votes.insert( - Voter::StakePoolKey(Hash::new(test_hash_bytes)), + Voter::StakePoolKey(PoolId::new(Hash::new(test_hash_bytes))), SingleVoterVotes::default(), ); @@ -2024,7 +2029,7 @@ mod tests { }, ); voting.votes.insert( - Voter::StakePoolKey(Hash::new(test_hash_bytes)), + Voter::StakePoolKey(PoolId::new(Hash::new(test_hash_bytes))), SingleVoterVotes::default(), ); println!("Json: {}", serde_json::to_string(&voting)?); diff --git a/modules/accounts_state/src/rewards.rs b/modules/accounts_state/src/rewards.rs index 250f81f9..e8fab848 100644 --- a/modules/accounts_state/src/rewards.rs +++ b/modules/accounts_state/src/rewards.rs @@ -2,8 +2,8 @@ use crate::snapshot::{Snapshot, SnapshotSPO}; use acropolis_common::{ - protocol_params::ShelleyParams, rational_number::RationalNumber, KeyHash, Lovelace, SPORewards, - StakeAddress, + protocol_params::ShelleyParams, rational_number::RationalNumber, Lovelace, PoolId, + SPORewards, StakeAddress, }; use anyhow::{bail, Result}; use bigdecimal::{BigDecimal, One, ToPrimitive, Zero}; @@ -43,10 +43,10 @@ pub struct RewardsResult { pub total_paid: u64, /// Rewards to be paid - pub rewards: BTreeMap>, + pub rewards: BTreeMap>, /// SPO rewards - pub spo_rewards: Vec<(KeyHash, SPORewards)>, + pub spo_rewards: Vec<(PoolId, SPORewards)>, } /// Calculate rewards for a given epoch based on current rewards state and protocol parameters @@ -221,7 +221,7 @@ pub fn calculate_rewards( /// Calculate rewards for an individual SPO fn calculate_spo_rewards( - operator_id: &KeyHash, + operator_id: &PoolId, spo: &SnapshotSPO, blocks_produced: u64, total_blocks: usize, diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index ac191df1..22a37759 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -2,7 +2,8 @@ use crate::state::{Pots, RegistrationChange}; use acropolis_common::{ - stake_addresses::StakeAddressMap, KeyHash, Lovelace, PoolRegistration, Ratio, StakeAddress, + stake_addresses::StakeAddressMap, Lovelace, PoolId, PoolRegistration, Ratio, + StakeAddress, }; use imbl::OrdMap; use std::collections::HashMap; @@ -47,7 +48,7 @@ pub struct Snapshot { pub epoch: u64, /// Map of SPOs by operator ID - pub spos: HashMap, + pub spos: HashMap, /// Persistent pot values pub pots: Pots, @@ -64,8 +65,8 @@ impl Snapshot { pub fn new( epoch: u64, stake_addresses: &StakeAddressMap, - spos: &OrdMap, - spo_block_counts: &HashMap, + spos: &OrdMap, + spo_block_counts: &HashMap, pots: &Pots, blocks: usize, registration_changes: Vec, @@ -160,7 +161,7 @@ impl Snapshot { /// Get the total stake held by a vector of stake addresses for a particular SPO (by ID) pub fn get_stake_delegated_to_spo_by_addresses( &self, - spo: &KeyHash, + spo: &PoolId, addresses: &[StakeAddress], ) -> Lovelace { let Some(snapshot_spo) = self.spos.get(spo) else { @@ -187,7 +188,7 @@ mod tests { use super::*; use acropolis_common::stake_addresses::StakeAddressState; use acropolis_common::NetworkId::Mainnet; - use acropolis_common::{StakeAddress, StakeCredential}; + use acropolis_common::{PoolId, StakeAddress, StakeCredential}; // Helper function to create stake addresses for testing fn create_test_stake_address(id: u8) -> StakeAddress { @@ -200,10 +201,10 @@ mod tests { } // Helper function to create SPO key hashes for testing - fn create_test_spo_hash(id: u8) -> KeyHash { + fn create_test_spo_hash(id: u8) -> PoolId { let mut hash = vec![0u8; 28]; hash[0] = id; - KeyHash::try_from(hash).unwrap() + PoolId::try_from(hash).unwrap() } #[test] @@ -264,10 +265,10 @@ mod tests { }, ); - let mut spos: OrdMap = OrdMap::new(); + let mut spos: OrdMap = OrdMap::new(); spos.insert(spo1.clone(), PoolRegistration::default()); spos.insert(spo2.clone(), PoolRegistration::default()); - let spo_block_counts: HashMap = HashMap::new(); + let spo_block_counts: HashMap = HashMap::new(); let snapshot = Snapshot::new( 42, &stake_addresses, diff --git a/modules/accounts_state/src/spo_distribution_publisher.rs b/modules/accounts_state/src/spo_distribution_publisher.rs index 7c963bc5..47a8efdc 100644 --- a/modules/accounts_state/src/spo_distribution_publisher.rs +++ b/modules/accounts_state/src/spo_distribution_publisher.rs @@ -1,5 +1,5 @@ use acropolis_common::messages::{CardanoMessage, Message, SPOStakeDistributionMessage}; -use acropolis_common::{BlockInfo, DelegatedStake, KeyHash}; +use acropolis_common::{BlockInfo, DelegatedStake, PoolId}; use caryatid_sdk::Context; use std::collections::BTreeMap; use std::sync::Arc; @@ -23,7 +23,7 @@ impl SPODistributionPublisher { pub async fn publish_spdd( &mut self, block: &BlockInfo, - spos: BTreeMap, + spos: BTreeMap, ) -> anyhow::Result<()> { self.context .message_bus @@ -32,7 +32,7 @@ impl SPODistributionPublisher { Arc::new(Message::Cardano(( block.clone(), CardanoMessage::SPOStakeDistribution(SPOStakeDistributionMessage { - epoch: block.epoch - 1, // End of previous epoch + epoch: block.epoch - 1, // End of the previous epoch spos: spos.into_iter().collect(), }), ))), diff --git a/modules/accounts_state/src/spo_rewards_publisher.rs b/modules/accounts_state/src/spo_rewards_publisher.rs index 04161b50..42ace388 100644 --- a/modules/accounts_state/src/spo_rewards_publisher.rs +++ b/modules/accounts_state/src/spo_rewards_publisher.rs @@ -1,5 +1,5 @@ use acropolis_common::messages::{CardanoMessage, Message, SPORewardsMessage}; -use acropolis_common::{BlockInfo, KeyHash, SPORewards}; +use acropolis_common::{BlockInfo, PoolId, SPORewards}; use caryatid_sdk::Context; use std::sync::Arc; @@ -22,7 +22,7 @@ impl SPORewardsPublisher { pub async fn publish_spo_rewards( &mut self, block: &BlockInfo, - spo_rewards: Vec<(KeyHash, SPORewards)>, + spo_rewards: Vec<(PoolId, SPORewards)>, ) -> anyhow::Result<()> { self.context .message_bus diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 0b2ba339..03552d07 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -4,11 +4,20 @@ use crate::rewards::{calculate_rewards, RewardsResult}; use crate::snapshot::Snapshot; use crate::verifier::Verifier; use acropolis_common::queries::accounts::OptimalPoolSizing; -use acropolis_common::{math::update_value_with_delta, messages::{ - DRepDelegationDistribution, DRepStateMessage, EpochActivityMessage, PotDeltasMessage, - ProtocolParamsMessage, SPOStateMessage, StakeAddressDeltasMessage, TxCertificatesMessage, - WithdrawalsMessage, -}, protocol_params::ProtocolParams, stake_addresses::{StakeAddressMap, StakeAddressState}, BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolId, PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, TxCertificate}; +use acropolis_common::{ + math::update_value_with_delta, + messages::{ + DRepDelegationDistribution, DRepStateMessage, EpochActivityMessage, PotDeltasMessage, + ProtocolParamsMessage, SPOStateMessage, StakeAddressDeltasMessage, TxCertificatesMessage, + WithdrawalsMessage, + }, + protocol_params::ProtocolParams, + stake_addresses::{StakeAddressMap, StakeAddressState}, + BlockInfo, DRepChoice, DRepCredential, DelegatedStake, InstantaneousRewardSource, + InstantaneousRewardTarget, KeyHash, Lovelace, MoveInstantaneousReward, PoolId, + PoolLiveStakeInfo, PoolRegistration, Pot, SPORewards, StakeAddress, StakeRewardDelta, + TxCertificate, +}; use anyhow::Result; use imbl::OrdMap; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -80,11 +89,11 @@ pub struct RegistrationChange { /// Overall state - stored per block #[derive(Debug, Default, Clone)] pub struct State { - /// Map of active SPOs by operator ID - spos: OrdMap, + /// Map of active SPOs by pool ID + spos: OrdMap, - /// List of SPOs (by operator ID) retiring in the current epoch - retiring_spos: Vec, + /// List of SPOs (by pool ID) retiring in the current epoch + retiring_spos: Vec, /// Map of staking address values /// Wrapped in an Arc so it doesn't get cloned in full by StateHistory @@ -247,7 +256,7 @@ impl State { &mut self, epoch: u64, total_fees: u64, - spo_block_counts: HashMap, + spo_block_counts: HashMap, verifier: &Verifier, ) -> Result> { // TODO HACK! Investigate why this differs to our calculated reserves after AVVM @@ -589,12 +598,12 @@ impl State { /// (both with and without rewards) for each active SPO /// And Stake Pool Reward State (rewards and delegators_count for each pool) /// Key of returned map is the SPO 'operator' ID - pub fn generate_spdd(&self) -> BTreeMap { + pub fn generate_spdd(&self) -> BTreeMap { let stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.generate_spdd() } - pub fn dump_spdd_state(&self) -> HashMap> { + pub fn dump_spdd_state(&self) -> HashMap> { let stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.dump_spdd_state() } @@ -631,8 +640,8 @@ impl State { &mut self, ea_msg: &EpochActivityMessage, verifier: &Verifier, - ) -> Result<(Vec<(KeyHash, SPORewards)>, Vec)> { - let mut spo_rewards: Vec<(KeyHash, SPORewards)> = Vec::new(); + ) -> Result<(Vec<(PoolId, SPORewards)>, Vec)> { + let mut spo_rewards: Vec<(PoolId, SPORewards)> = Vec::new(); // Collect stake addresses reward deltas let mut reward_deltas = Vec::::new(); @@ -686,7 +695,7 @@ impl State { }; // Map block counts, filtering out SPOs we don't know (OBFT in early Shelley) - let spo_blocks: HashMap = ea_msg + let spo_blocks: HashMap = ea_msg .spo_blocks .iter() .filter(|(hash, _)| self.spos.contains_key(hash)) @@ -708,7 +717,7 @@ impl State { /// epoch pub fn handle_spo_state(&mut self, spo_msg: &SPOStateMessage) -> Result<()> { // Capture current SPOs, mapped by operator ID - let new_spos: OrdMap = + let new_spos: OrdMap = spo_msg.spos.iter().cloned().map(|spo| (spo.operator.clone(), spo)).collect(); // Get pool deposit amount from parameters, or default @@ -846,7 +855,7 @@ impl State { } /// Record a stake delegation - fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &KeyHash) { + fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &PoolId) { let mut stake_addresses = self.stake_addresses.lock().unwrap(); stake_addresses.record_stake_delegation(&stake_address, spo); } @@ -981,29 +990,13 @@ impl State { #[cfg(test)] mod tests { use super::*; + use acropolis_common::crypto::keyhash_256; use acropolis_common::{ - crypto::keyhash_224, // ADDED: Import keyhash function - protocol_params::ConwayParams, - rational_number::RationalNumber, - Anchor, - Committee, - Constitution, - CostModel, - DRepVotingThresholds, - NetworkId, - PoolVotingThresholds, - Pot, - PotDelta, - Ratio, - Registration, - StakeAddress, - StakeAddressDelta, - StakeAndVoteDelegation, - StakeCredential, - StakeRegistrationAndStakeAndVoteDelegation, - StakeRegistrationAndVoteDelegation, - VoteDelegation, - Withdrawal, + crypto::keyhash_224, protocol_params::ConwayParams, rational_number::RationalNumber, + Anchor, Committee, Constitution, CostModel, DRepVotingThresholds, NetworkId, + PoolVotingThresholds, Pot, PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, + StakeAndVoteDelegation, StakeCredential, StakeRegistrationAndStakeAndVoteDelegation, + StakeRegistrationAndVoteDelegation, VRFKey, VoteDelegation, Withdrawal, }; // Helper to create a StakeAddress from a byte slice @@ -1016,16 +1009,18 @@ mod tests { } } - // ADDED: Helper to create KeyHash for testing fn test_keyhash(byte: u8) -> KeyHash { keyhash_224(&vec![byte]) } - // ADDED: Helper to create KeyHash from byte array fn test_keyhash_from_bytes(bytes: &[u8]) -> KeyHash { keyhash_224(bytes) } + fn test_vrf_keyhash(byte: u8) -> VRFKey { + VRFKey::new(keyhash_256(&vec![byte])) + } + const STAKE_KEY_HASH: [u8; 3] = [0x99, 0x0f, 0x00]; const DREP_HASH: [u8; 4] = [0xca, 0xfe, 0xd0, 0x0d]; @@ -1079,8 +1074,11 @@ mod tests { fn spdd_from_delegation_with_utxo_values_and_pledge() { let mut state = State::default(); - let spo1: KeyHash = test_keyhash(0x01); // CHANGED - let spo2: KeyHash = test_keyhash(0x02); // CHANGED + let spo1: PoolId = PoolId::new(test_keyhash(0x01)); + let spo2: PoolId = PoolId::new(test_keyhash(0x02)); + + let vrf_key_hash_1 = test_vrf_keyhash(0x03); + let vrf_key_hash_2 = test_vrf_keyhash(0x04); // Create the SPOs state @@ -1089,7 +1087,7 @@ mod tests { spos: vec![ PoolRegistration { operator: spo1.clone(), - vrf_key_hash: spo1.clone(), + vrf_key_hash: vrf_key_hash_1, pledge: 26, cost: 0, margin: Ratio { @@ -1103,7 +1101,7 @@ mod tests { }, PoolRegistration { operator: spo2.clone(), - vrf_key_hash: spo2.clone(), + vrf_key_hash: vrf_key_hash_2, pledge: 47, cost: 10, margin: Ratio { @@ -1392,6 +1390,8 @@ mod tests { let drep_key_hash = test_keyhash_from_bytes(&DREP_HASH); let drep_script_hash = test_keyhash_from_bytes(&DREP_HASH); + let pool_id_1 = PoolId::new(*spo1_hash); + let certificates = vec![ // register the first two SPOs separately from their delegation TxCertificate::Registration(Registration { @@ -1404,12 +1404,12 @@ mod tests { }), TxCertificate::VoteDelegation(VoteDelegation { stake_address: spo1.clone(), - drep: DRepChoice::Key(drep_key_hash.clone()), // CHANGED + drep: DRepChoice::Key(drep_key_hash.clone()), }), TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: spo2.clone(), - operator: spo1_hash.clone(), - drep: DRepChoice::Script(drep_script_hash.clone()), // CHANGED + operator: pool_id_1.clone(), + drep: DRepChoice::Script(drep_script_hash.clone()), }), TxCertificate::StakeRegistrationAndVoteDelegation(StakeRegistrationAndVoteDelegation { stake_address: spo3.clone(), @@ -1419,7 +1419,7 @@ mod tests { TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: spo4.clone(), - operator: spo1_hash.clone(), + operator: pool_id_1.clone(), drep: DRepChoice::NoConfidence, deposit: 1, }, diff --git a/modules/accounts_state/src/verifier.rs b/modules/accounts_state/src/verifier.rs index 9cb55955..42b67383 100644 --- a/modules/accounts_state/src/verifier.rs +++ b/modules/accounts_state/src/verifier.rs @@ -166,11 +166,13 @@ impl Verifier { continue; }; - expected_rewards.entry(KeyHash::try_from(spo).unwrap()).or_default().push(RewardDetail { - account: stake_address, - rtype, - amount, - }); + expected_rewards.entry(KeyHash::try_from(spo).unwrap()).or_default().push( + RewardDetail { + account: stake_address, + rtype, + amount, + }, + ); } info!( diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 1b370a35..969ad46a 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -1,13 +1,6 @@ //! Acropolis epoch activity counter: state storage -use acropolis_common::{ - crypto::keyhash_224, - genesis_values::GenesisValues, - messages::{BlockTxsMessage, EpochActivityMessage, ProtocolParamsMessage}, - params::EPOCH_LENGTH, - protocol_params::{Nonces, PraosParams}, - BlockHash, BlockInfo, KeyHash, -}; +use acropolis_common::{crypto::keyhash_224, genesis_values::GenesisValues, messages::{BlockTxsMessage, EpochActivityMessage, ProtocolParamsMessage}, params::EPOCH_LENGTH, protocol_params::{Nonces, PraosParams}, BlockHash, BlockInfo, PoolId}; use anyhow::Result; use imbl::HashMap; use pallas::ledger::traverse::MultiEraHeader; @@ -39,8 +32,8 @@ pub struct State { // last block height last_block_height: u64, - // Map of counts by VRF key hashes - blocks_minted: HashMap, + // Map of counts by Pool ID + blocks_minted: HashMap, // blocks seen this epoch epoch_blocks: usize, @@ -188,7 +181,7 @@ impl State { self.last_block_time = block_info.timestamp; self.last_block_height = block_info.number; self.epoch_blocks += 1; - let spo_id = keyhash_224(issuer_vkey); + let spo_id = PoolId::new(keyhash_224(issuer_vkey)); // Count one on this hash *(self.blocks_minted.entry(spo_id.clone()).or_insert(0)) += 1; @@ -255,7 +248,7 @@ impl State { } } - pub fn get_latest_epoch_blocks_minted_by_pool(&self, spo_id: &KeyHash) -> u64 { + pub fn get_latest_epoch_blocks_minted_by_pool(&self, spo_id: &PoolId) -> u64 { self.blocks_minted.get(spo_id).map(|v| *v as u64).unwrap_or(0) } } diff --git a/modules/governance_state/src/state.rs b/modules/governance_state/src/state.rs index 5c6ed00f..87ee1d0f 100644 --- a/modules/governance_state/src/state.rs +++ b/modules/governance_state/src/state.rs @@ -9,7 +9,7 @@ use acropolis_common::{ }, protocol_params::ConwayParams, BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, Era, GovActionId, GovernanceAction, - GovernanceOutcome, GovernanceOutcomeVariant, KeyHash, Lovelace, ProposalProcedure, + GovernanceOutcome, GovernanceOutcomeVariant, Lovelace, PoolId, ProposalProcedure, SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Voter, VotesCount, VotingOutcome, VotingProcedure, }; @@ -32,7 +32,7 @@ pub struct State { current_era: Era, conway: Option, drep_stake: HashMap, - spo_stake: HashMap, + spo_stake: HashMap, alonzo_babbage_voting: AlonzoBabbageVoting, proposals: HashMap, diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index 1e2ce786..0439cbb4 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -155,8 +155,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeCredential, ) -> Result>> { - let mut immutable_rewards = - self.collect_partition::(&self.rewards_history, &account.get_hash().into_inner())?; + let mut immutable_rewards = self.collect_partition::( + &self.rewards_history, + &account.get_hash().into_inner(), + )?; self.merge_pending( account, @@ -191,8 +193,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeCredential, ) -> Result>> { - let mut immutable_delegations = self - .collect_partition::(&self.delegation_history, &account.get_hash().into_inner())?; + let mut immutable_delegations = self.collect_partition::( + &self.delegation_history, + &account.get_hash().into_inner(), + )?; self.merge_pending( account, @@ -246,8 +250,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeCredential, ) -> Result>> { - let mut immutable_mirs = - self.collect_partition::(&self.mir_history, &account.get_hash().into_inner())?; + let mut immutable_mirs = self.collect_partition::( + &self.mir_history, + &account.get_hash().into_inner(), + )?; self.merge_pending(account, |e| e.mir_history.as_ref(), &mut immutable_mirs).await; @@ -258,8 +264,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeCredential, ) -> Result>> { - let mut immutable_addresses = - self.collect_partition::(&self.addresses, &account.get_hash().into_inner())?; + let mut immutable_addresses = self.collect_partition::( + &self.addresses, + &account.get_hash().into_inner(), + )?; self.merge_pending(account, |e| e.addresses.as_ref(), &mut immutable_addresses).await; diff --git a/modules/historical_accounts_state/src/state.rs b/modules/historical_accounts_state/src/state.rs index 07a81bfd..e0bbb547 100644 --- a/modules/historical_accounts_state/src/state.rs +++ b/modules/historical_accounts_state/src/state.rs @@ -3,9 +3,12 @@ use std::{ sync::Arc, }; -use acropolis_common::{messages::{ - AddressDeltasMessage, StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, -}, BlockInfo, PoolId, ShelleyAddress, StakeAddress, StakeCredential, TxIdentifier}; +use acropolis_common::{ + messages::{ + AddressDeltasMessage, StakeRewardDeltasMessage, TxCertificatesMessage, WithdrawalsMessage, + }, + BlockInfo, PoolId, ShelleyAddress, StakeAddress, StakeCredential, TxIdentifier, +}; use crate::{ immutable_historical_account_store::ImmutableHistoricalAccountStore, diff --git a/modules/rest_blockfrost/src/handlers/accounts.rs b/modules/rest_blockfrost/src/handlers/accounts.rs index 16e141dd..80b2fce4 100644 --- a/modules/rest_blockfrost/src/handlers/accounts.rs +++ b/modules/rest_blockfrost/src/handlers/accounts.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use acropolis_common::messages::{Message, RESTResponse, StateQuery, StateQueryResponse}; use acropolis_common::queries::accounts::{AccountsStateQuery, AccountsStateQueryResponse}; use acropolis_common::queries::utils::query_state; -use acropolis_common::serialization::{Bech32Conversion, Bech32WithHrp}; +use acropolis_common::serialization::Bech32Conversion; use acropolis_common::{DRepChoice, StakeAddress}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index a0d028d3..a6923f15 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -1,17 +1,4 @@ //! REST handlers for Acropolis Blockfrost /pools endpoints -use acropolis_common::{messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ - accounts::{AccountsStateQuery, AccountsStateQueryResponse}, - epochs::{EpochsStateQuery, EpochsStateQueryResponse}, - pools::{PoolsStateQuery, PoolsStateQueryResponse}, - utils::query_state, -}, rest_helper::ToCheckedF64, serialization::Bech32WithHrp, PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxHash}; -use anyhow::Result; -use caryatid_sdk::Context; -use rust_decimal::Decimal; -use std::{sync::Arc, time::Duration}; -use tokio::join; -use tracing::warn; -use acropolis_common::serialization::Bech32Conversion; use crate::{ handlers_config::HandlersConfig, types::{PoolDelegatorRest, PoolInfoRest, PoolRelayRest, PoolUpdateEventRest, PoolVoteRest}, @@ -20,6 +7,24 @@ use crate::{ types::{PoolEpochStateRest, PoolExtendedRest, PoolMetadataRest, PoolRetirementRest}, utils::{fetch_pool_metadata_as_bytes, verify_pool_metadata_hash, PoolMetadataJson}, }; +use acropolis_common::serialization::Bech32Conversion; +use acropolis_common::{ + messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, + queries::{ + accounts::{AccountsStateQuery, AccountsStateQueryResponse}, + epochs::{EpochsStateQuery, EpochsStateQueryResponse}, + pools::{PoolsStateQuery, PoolsStateQueryResponse}, + utils::query_state, + }, + rest_helper::ToCheckedF64, + PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxHash, +}; +use anyhow::Result; +use caryatid_sdk::Context; +use rust_decimal::Decimal; +use std::{sync::Arc, time::Duration}; +use tokio::join; +use tracing::warn; /// Handle `/pools` Blockfrost-compatible endpoint pub async fn handle_pools_list_blockfrost( @@ -700,7 +705,7 @@ async fn handle_pools_spo_blockfrost( }; let pool_info_rest: PoolInfoRest = PoolInfoRest { pool_id, - hex: pool_info.operator, + hex: *pool_info.operator, vrf_key: pool_info.vrf_key_hash, blocks_minted: total_blocks_minted, blocks_epoch: epoch_blocks_minted, diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index c024f3fe..deb9e7cb 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -1,5 +1,14 @@ use crate::cost_models::{PLUTUS_V1, PLUTUS_V2, PLUTUS_V3}; -use acropolis_common::{messages::EpochActivityMessage, protocol_params::{Nonce, NonceVariant, ProtocolParams}, queries::blocks::BlockInfo, queries::governance::DRepActionUpdate, rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, PoolEpochState, PoolUpdateAction, Relay, TxHash, VRFKey, Vote}; +use acropolis_common::{ + messages::EpochActivityMessage, + protocol_params::{Nonce, NonceVariant, ProtocolParams}, + queries::blocks::BlockInfo, + queries::governance::DRepActionUpdate, + rest_helper::ToCheckedF64, + serialization::{DisplayFromBech32, PoolPrefix}, + AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, + PoolEpochState, PoolId, PoolUpdateAction, Relay, TxHash, VRFKey, Vote, +}; use anyhow::Result; use num_traits::ToPrimitive; use rust_decimal::Decimal; @@ -54,7 +63,7 @@ pub struct BlockInfoREST(pub BlockInfo); pub struct SPDDByEpochItemRest { pub stake_address: String, #[serde_as(as = "DisplayFromBech32")] - pub pool_id: KeyHash, + pub pool_id: PoolId, #[serde_as(as = "DisplayFromStr")] pub amount: u64, } diff --git a/modules/spdd_state/src/rest.rs b/modules/spdd_state/src/rest.rs index b26d488b..29662628 100644 --- a/modules/spdd_state/src/rest.rs +++ b/modules/spdd_state/src/rest.rs @@ -1,5 +1,5 @@ use crate::state::State; -use acropolis_common::serialization::{Bech32Conversion, Bech32WithHrp}; +use acropolis_common::serialization::{Bech32Conversion}; use acropolis_common::DelegatedStake; use acropolis_common::{extract_strict_query_params, messages::RESTResponse}; use anyhow::Result; @@ -33,12 +33,7 @@ pub async fn handle_spdd( if let Some(spdd) = spdd_opt { let spdd: HashMap = spdd .iter() - .map(|(k, v)| { - ( - k.to_bech32().unwrap_or_else(|_| hex::encode(k)), - *v, - ) - }) + .map(|(k, v)| (k.to_bech32().unwrap_or_else(|_| hex::encode(k)), *v)) .collect(); match serde_json::to_string(&spdd) { diff --git a/modules/spdd_state/src/state.rs b/modules/spdd_state/src/state.rs index c071dc69..80bf570e 100644 --- a/modules/spdd_state/src/state.rs +++ b/modules/spdd_state/src/state.rs @@ -1,12 +1,12 @@ use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, - DelegatedStake, KeyHash, + DelegatedStake, PoolId, }; use imbl::{OrdMap, OrdSet}; use tracing::info; pub struct State { - spdd_history: StateHistory>, + spdd_history: StateHistory>, } impl State { @@ -18,7 +18,7 @@ impl State { pub fn apply_spdd_snapshot(&mut self, epoch: u64, snapshot: I) where - I: IntoIterator, + I: IntoIterator, { let mut next = self.spdd_history.get_rolled_back_state(epoch); @@ -34,8 +34,7 @@ impl State { present.insert(k); } - let to_remove: Vec<_> = - next.keys().filter(|k| !present.contains(*k)).cloned().collect(); + let to_remove: Vec<_> = next.keys().filter(|k| !present.contains(*k)).cloned().collect(); for k in to_remove { next.remove(&k); } @@ -44,12 +43,12 @@ impl State { } #[allow(dead_code)] - pub fn get_latest(&self) -> Option<&OrdMap> { + pub fn get_latest(&self) -> Option<&OrdMap> { self.spdd_history.current() } #[allow(dead_code)] - pub fn get_epoch(&self, epoch: u64) -> Option<&OrdMap> { + pub fn get_epoch(&self, epoch: u64) -> Option<&OrdMap> { self.spdd_history.get_by_index(epoch) } diff --git a/modules/spo_state/src/epochs_history.rs b/modules/spo_state/src/epochs_history.rs index 4ba7316c..1841c9aa 100644 --- a/modules/spo_state/src/epochs_history.rs +++ b/modules/spo_state/src/epochs_history.rs @@ -2,9 +2,9 @@ use acropolis_common::messages::EpochActivityMessage; use acropolis_common::messages::SPORewardsMessage; use acropolis_common::messages::SPOStakeDistributionMessage; use acropolis_common::rational_number::RationalNumber; -use acropolis_common::BlockInfo; use acropolis_common::KeyHash; use acropolis_common::PoolEpochState; +use acropolis_common::{BlockInfo, PoolId}; use dashmap::DashMap; use rayon::prelude::*; use std::collections::BTreeMap; @@ -100,7 +100,7 @@ impl EpochsHistoryState { /// Return None if any of pool operators active stake is None pub fn get_pools_active_stakes( &self, - pool_operators: &Vec, + pool_operators: &Vec, epoch: u64, ) -> Option> { let Some(epochs_history) = self.epochs_history.as_ref() else { @@ -169,7 +169,7 @@ impl EpochsHistoryState { &self, _block: &BlockInfo, epoch_activity_message: &EpochActivityMessage, - spos: &Vec<(KeyHash, usize)>, + spos: &Vec<(PoolId, usize)>, ) { let Some(epochs_history) = self.epochs_history.as_ref() else { return; @@ -225,7 +225,7 @@ mod tests { #[test] fn get_pool_history_returns_data() { let epochs_history = EpochsHistoryState::new(save_history_store_config()); - let key_hash = KeyHash::new([1; 28]); + let key_hash: PoolId = PoolId::new(KeyHash::new([1; 28])); let spo_block_key_hash = KeyHash::new([2; 28]); let block = new_block(2); diff --git a/modules/spo_state/src/retired_pools_history.rs b/modules/spo_state/src/retired_pools_history.rs index d770ce4a..9bcbe972 100644 --- a/modules/spo_state/src/retired_pools_history.rs +++ b/modules/spo_state/src/retired_pools_history.rs @@ -1,6 +1,5 @@ -use acropolis_common::BlockInfo; -use acropolis_common::KeyHash; use acropolis_common::PoolRetirement; +use acropolis_common::{BlockInfo, PoolId}; use dashmap::DashMap; use std::sync::Arc; @@ -9,7 +8,7 @@ use crate::store_config::StoreConfig; #[derive(Debug, Clone)] pub struct RetiredPoolsHistoryState { /// keyed by epoch - retired_pools_history: Option>>>, + retired_pools_history: Option>>>, } impl RetiredPoolsHistoryState { @@ -54,7 +53,7 @@ impl RetiredPoolsHistoryState { /// Handle Retired SPOs /// Update retired_pools_history with deregistrations /// - pub fn handle_deregistrations(&self, block: &BlockInfo, retired_spos: &Vec) { + pub fn handle_deregistrations(&self, block: &BlockInfo, retired_spos: &Vec) { let Some(retired_pools_history) = self.retired_pools_history.as_ref() else { return; }; @@ -91,14 +90,16 @@ mod tests { let state = RetiredPoolsHistoryState::new(save_retired_pools_store_config()); let block = new_block(2); - let retired_spos = vec![vec![1], vec![2]]; + let spo_1 = PoolId::new(KeyHash::new([1; 28])); + let spo_2 = PoolId::new(KeyHash::new([2; 28])); + let retired_spos = vec![spo_1, spo_2]; state.handle_deregistrations(&block, &retired_spos); let retired_pools = state.get_retired_pools(); assert_eq!(2, retired_pools.len()); assert_eq!(2, retired_pools[0].epoch); assert_eq!(2, retired_pools[1].epoch); - assert_eq!(vec![1], retired_pools[0].operator); - assert_eq!(vec![2], retired_pools[1].operator); + assert_eq!(spo_1, retired_pools[0].operator); + assert_eq!(spo_2, retired_pools[1].operator); } } diff --git a/modules/spo_state/src/spo_state.rs b/modules/spo_state/src/spo_state.rs index 4a874566..319fd1b8 100644 --- a/modules/spo_state/src/spo_state.rs +++ b/modules/spo_state/src/spo_state.rs @@ -13,7 +13,7 @@ use acropolis_common::{ }, rational_number::RationalNumber, state_history::{StateHistory, StateHistoryStore}, - BlockInfo, BlockStatus, Era, KeyHash, + BlockInfo, BlockStatus, Era, PoolId, }; use anyhow::Result; use caryatid_sdk::{module, Context, Module, Subscription}; @@ -286,7 +286,7 @@ impl SPOState { span.in_scope(|| { Self::check_sync(¤t_block, &block_info); // update epochs_history - let spos: Vec<(KeyHash, usize)> = epoch_activity_message + let spos: Vec<(PoolId, usize)> = epoch_activity_message .spo_blocks .iter() .map(|(hash, count)| (hash.clone(), *count)) diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 33176998..677491da 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, PoolId, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, 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, PoolId, PoolMetadata, PoolRegistration, PoolRegistrationWithPos, + PoolRetirement, PoolRetirementWithPos, PoolUpdateEvent, Relay, StakeAddress, TxCertificate, + TxHash, Voter, VotingProcedures, +}; use anyhow::Result; use imbl::HashMap; use std::sync::{Arc, Mutex}; @@ -20,19 +30,19 @@ pub struct State { epoch: u64, - spos: HashMap, + spos: HashMap, - pending_updates: HashMap, + pending_updates: HashMap, - pending_deregistrations: HashMap>, + pending_deregistrations: HashMap>, // Total blocks minted till block number // Keyed by pool_id - total_blocks_minted: HashMap, + total_blocks_minted: HashMap, /// historical spo state - /// keyed by pool operator id - historical_spos: Option>, + /// keyed by pool_id + historical_spos: Option>, /// stake_addresses (We save stake_addresses according to store_config) stake_addresses: Option>>, @@ -124,7 +134,7 @@ impl From<&State> for SPOState { key_hashes .iter() .map(|key_hash| (key_hash.clone(), *epoch)) - .collect::>() + .collect::>() }) .flatten() .collect(), @@ -134,12 +144,12 @@ impl From<&State> for SPOState { impl State { #[allow(dead_code)] - pub fn get(&self, pool_id: &KeyHash) -> Option<&PoolRegistration> { + pub fn get(&self, pool_id: &PoolId) -> Option<&PoolRegistration> { self.spos.get(pool_id) } /// Get total blocks minted by pools - pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { + pub fn get_total_blocks_minted_by_pools(&self, pools_operators: &Vec) -> Vec { pools_operators .iter() .map(|pool_operator| *self.total_blocks_minted.get(pool_operator).unwrap_or(&0)) @@ -147,27 +157,27 @@ impl State { } /// Get total blocks minted by pool - pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &KeyHash) -> u64 { + pub fn get_total_blocks_minted_by_pool(&self, pool_operator: &PoolId) -> u64 { *self.total_blocks_minted.get(pool_operator).unwrap_or(&0) } /// Get all Stake Pool operators' operator hashes - pub fn list_pool_operators(&self) -> Vec { + pub fn list_pool_operators(&self) -> Vec { self.spos.keys().cloned().collect() } /// Get all Stake Pool Operators' operator hashes and their registration information - pub fn list_pools_with_info(&self) -> Vec<(KeyHash, PoolRegistration)> { + pub fn list_pools_with_info(&self) -> Vec<(PoolId, PoolRegistration)> { self.spos.iter().map(|(k, v)| (k.clone(), v.clone())).collect() } /// Get pool metadata - pub fn get_pool_metadata(&self, pool_id: &KeyHash) -> Option { + pub fn get_pool_metadata(&self, pool_id: &PoolId) -> Option { self.spos.get(pool_id).map(|p| p.pool_metadata.clone()).flatten() } /// Get Pool Delegators - pub fn get_pool_delegators(&self, pool_operator: &KeyHash) -> Option> { + pub fn get_pool_delegators(&self, pool_operator: &PoolId) -> Option> { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return None; }; @@ -192,7 +202,7 @@ impl State { /// Get Blocks by Pool /// Return Vector of block heights /// Return None when store_blocks not enabled - pub fn get_blocks_by_pool(&self, pool_id: &KeyHash) -> Option> { + pub fn get_blocks_by_pool(&self, pool_id: &PoolId) -> Option> { let Some(historical_spos) = self.historical_spos.as_ref() else { return None; }; @@ -201,7 +211,7 @@ impl State { /// Get Blocks by Pool and Epoch /// Return None when store_blocks not enabled - pub fn get_blocks_by_pool_and_epoch(&self, pool_id: &KeyHash, epoch: u64) -> Option> { + pub fn get_blocks_by_pool_and_epoch(&self, pool_id: &PoolId, epoch: u64) -> Option> { let Some(historical_spos) = self.historical_spos.as_ref() else { return None; }; @@ -209,17 +219,17 @@ impl State { } /// Get Pool Updates - pub fn get_pool_updates(&self, pool_id: &KeyHash) -> Option> { + pub fn get_pool_updates(&self, pool_id: &PoolId) -> Option> { self.historical_spos.as_ref()?.get(pool_id).and_then(|s| s.updates.clone()) } /// Get Pool Votes - pub fn get_pool_votes(&self, pool_id: &KeyHash) -> Option> { + pub fn get_pool_votes(&self, pool_id: &PoolId) -> Option> { self.historical_spos.as_ref()?.get(pool_id).and_then(|s| s.votes.clone()) } /// Get pool relay - pub fn get_pool_relays(&self, pool_id: &KeyHash) -> Option> { + pub fn get_pool_relays(&self, pool_id: &PoolId) -> Option> { self.spos.get(pool_id).map(|p| p.relays.clone()) } @@ -253,7 +263,7 @@ impl State { // Handle block's minting. pub fn handle_mint(&mut self, block_info: &BlockInfo, issuer_vkey: &[u8]) -> bool { - let pool_id = keyhash_224(issuer_vkey); + let pool_id = PoolId::from(keyhash_224(issuer_vkey)); if self.spos.get(&pool_id).is_none() { return false; } @@ -285,7 +295,7 @@ impl State { self.pending_updates.clear(); // Deregister any pending - let mut retired_spos: Vec = Vec::new(); + let mut retired_spos: Vec = Vec::new(); let deregistrations = self.pending_deregistrations.remove(&self.epoch); if let Some(deregistrations) = deregistrations { for dr in deregistrations { @@ -466,7 +476,7 @@ impl State { /// Record a stake delegation /// Update historical_spo_state's delegators - fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &KeyHash) { + fn record_stake_delegation(&mut self, stake_address: &StakeAddress, spo: &PoolId) { let Some(stake_addresses) = self.stake_addresses.as_ref() else { return; }; @@ -669,16 +679,28 @@ impl State { mod tests { use super::*; use crate::test_utils::*; - use acropolis_common::{state_history::{StateHistory, StateHistoryStore}, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey}; + use acropolis_common::hash::Hash; + use acropolis_common::{ + state_history::{StateHistory, StateHistoryStore}, + PoolId, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey, + }; use tokio::sync::Mutex; + fn test_pool_id(byte: u8) -> PoolId { + PoolId::new(Hash::new([byte; 28])) + } + + fn test_pool_id_from_bytes(bytes: &[u8]) -> PoolId { + PoolId::new(keyhash_224(bytes)) + } + fn default_pool_registration( - operator: KeyHash, + operator: PoolId, vrf_key_hash: Option, ) -> PoolRegistration { PoolRegistration { - operator: operator.clone(), - vrf_key_hash: vrf_key_hash.unwrap_or_else(|| vec![0]), + operator, + vrf_key_hash: vrf_key_hash.unwrap_or_else(|| VRFKey::default()), pledge: 0, cost: 0, margin: Ratio { @@ -695,7 +717,7 @@ mod tests { #[test] fn get_returns_none_on_empty_state() { let state = State::default(); - assert!(state.get(&vec![0]).is_none()); + assert!(state.get(&test_pool_id(0)).is_none()); } #[test] @@ -717,9 +739,11 @@ mod tests { async fn spo_gets_registered() { let mut state = State::default(); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); + msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id, None), tx_hash: TxHash::default(), cert_index: 1, }, @@ -727,7 +751,7 @@ mod tests { let block = new_block(1); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0]); + let spo = state.spos.get(&pool_id); assert!(!spo.is_none()); } @@ -735,10 +759,12 @@ mod tests { async fn pending_deregistration_gets_queued() { let mut state = State::default(); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id, epoch: 1, }, tx_hash: TxHash::default(), @@ -752,7 +778,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&vec![0])); + assert!(drs.contains(&pool_id)); } } @@ -761,10 +787,13 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); + let pool_id_1 = test_pool_id(1); + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0, epoch: 2, }, tx_hash: TxHash::default(), @@ -778,7 +807,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1, epoch: 2, }, tx_hash: TxHash::default(), @@ -792,8 +821,8 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(2, drs.len()); - assert!(drs.contains(&vec![0u8])); - assert!(drs.contains(&vec![1u8])); + assert!(drs.contains(&pool_id_0)); + assert!(drs.contains(&pool_id_1)); } } @@ -806,10 +835,13 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); + let pool_id_1 = test_pool_id(1); + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0, epoch: 2, }, tx_hash: TxHash::default(), @@ -825,7 +857,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1, epoch: 2, }, tx_hash: TxHash::default(), @@ -844,7 +876,7 @@ mod tests { assert!(!drs.is_none()); if let Some(drs) = drs { assert_eq!(1, drs.len()); - assert!(drs.contains(&vec![0])); + assert!(drs.contains(&pool_id_0)); } } @@ -853,9 +885,11 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); + msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id, None), tx_hash: TxHash::default(), cert_index: 0, }, @@ -863,7 +897,7 @@ mod tests { assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0u8]); + let spo = state.spos.get(&pool_id); assert!(!spo.is_none()); block.number = 1; @@ -871,7 +905,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id, epoch: 1, }, tx_hash: TxHash::default(), @@ -896,16 +930,18 @@ mod tests { let mut state = history.lock().await.get_current_state(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id = test_pool_id(0); + msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(vec![0], None), + reg: default_pool_registration(pool_id, None), tx_hash: TxHash::default(), cert_index: 0, }, )); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0u8]); + let spo = state.spos.get(&pool_id); assert!(!spo.is_none()); history.lock().await.commit(block.number, state); @@ -915,7 +951,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id, epoch: 1, }, tx_hash: TxHash::default(), @@ -939,7 +975,7 @@ mod tests { let mut state = history.lock().await.get_rolled_back_state(block.number); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(&vec![0]); + let spo = state.spos.get(&pool_id); assert!(!spo.is_none()); } @@ -954,10 +990,13 @@ mod tests { let mut state = State::default(); let mut block = new_block(0); let mut msg = new_certs_msg(); + let pool_id_0 = test_pool_id(0); + let pool_id_1 = test_pool_id(1); + msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![0], + operator: pool_id_0, epoch: 2, }, tx_hash: TxHash::default(), @@ -971,7 +1010,7 @@ mod tests { msg.certificates.push(TxCertificate::PoolRetirementWithPos( PoolRetirementWithPos { ret: PoolRetirement { - operator: vec![1], + operator: pool_id_1, epoch: 3, }, tx_hash: TxHash::default(), @@ -982,17 +1021,18 @@ mod tests { let mut retiring_pools = state.get_retiring_pools(); retiring_pools.sort_by_key(|p| p.epoch); assert_eq!(2, retiring_pools.len()); - assert_eq!(vec![0], retiring_pools[0].operator); + assert_eq!(pool_id_0, retiring_pools[0].operator); assert_eq!(2, retiring_pools[0].epoch); - assert_eq!(vec![1], retiring_pools[1].operator); + assert_eq!(pool_id_1, retiring_pools[1].operator); assert_eq!(3, retiring_pools[1].epoch); } #[test] fn get_total_blocks_minted_returns_zeros_when_state_is_new() { let state = State::default(); - assert_eq!(0, state.get_total_blocks_minted_by_pools(&vec![vec![0]])[0]); - assert_eq!(0, state.get_total_blocks_minted_by_pool(&vec![0])); + let pool_id = test_pool_id(0); + assert_eq!(0, state.get_total_blocks_minted_by_pools(&vec![pool_id])[0]); + assert_eq!(0, state.get_total_blocks_minted_by_pool(&pool_id)); } #[test] @@ -1000,10 +1040,11 @@ mod tests { let mut state = State::new(&save_blocks_store_config()); let mut block = new_block(0); let mut msg = new_certs_msg(); - let spo_id = keyhash_224(&vec![1 as u8]); + let spo_id = test_pool_id_from_bytes(&[1]); + msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(spo_id.clone(), None), + reg: default_pool_registration(spo_id, None), tx_hash: TxHash::default(), cert_index: 0, }, @@ -1022,7 +1063,8 @@ mod tests { #[test] fn get_blocks_returns_none_when_blocks_not_enabled() { let state = State::default(); - assert!(state.get_blocks_by_pool(&vec![0]).is_none()); + let pool_id = test_pool_id(0); + assert!(state.get_blocks_by_pool(&pool_id).is_none()); } #[test] @@ -1037,10 +1079,11 @@ mod tests { let mut state = State::new(&save_blocks_store_config()); let mut block = new_block(0); let mut msg = new_certs_msg(); - let spo_id = keyhash_224(&vec![1 as u8]); + let spo_id = test_pool_id_from_bytes(&[1]); + msg.certificates.push(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { - reg: default_pool_registration(spo_id.clone(), None), + reg: default_pool_registration(spo_id, None), tx_hash: TxHash::default(), cert_index: 0, }, diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 2e960d3f..bae134e9 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -401,7 +401,12 @@ pub fn process_message( #[cfg(test)] mod test { use crate::*; - use acropolis_common::{messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, ByronAddress, Era, KeyHash, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeCredential, UTxOIdentifier, ValueDelta}; + use acropolis_common::{ + messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, + ByronAddress, Era, KeyHash, ShelleyAddress, ShelleyAddressDelegationPart, + ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeCredential, + UTxOIdentifier, ValueDelta, + }; use bech32::{Bech32, Hrp}; fn parse_addr(s: &str) -> Result { From 41681eac045f2d6d2d3e589be7cf17f33246c561 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 15:11:49 -0700 Subject: [PATCH 05/20] Refactor: Introduce type-safe `Hash` conversion utilities, replace manual conversions across modules, and adjust types for stronger consistency. Update tests and documentation accordingly. --- codec/src/map_parameters.rs | 114 +++++++++++------- common/src/address.rs | 2 +- common/src/hash.rs | 16 +-- common/src/stake_addresses.rs | 53 ++++---- common/src/types.rs | 2 +- modules/chain_store/src/chain_store.rs | 6 +- modules/chain_store/src/stores/fjall.rs | 2 +- modules/chain_store/src/stores/mod.rs | 2 +- modules/epochs_state/src/state.rs | 35 ++++-- .../rest_blockfrost/src/handlers/epochs.rs | 2 +- modules/rest_blockfrost/src/types.rs | 4 +- modules/spo_state/src/epochs_history.rs | 12 +- .../spo_state/src/retired_pools_history.rs | 1 + modules/stake_delta_filter/src/utils.rs | 31 +++-- modules/tx_unpacker/src/tx_unpacker.rs | 8 +- modules/tx_unpacker/src/utxo_registry.rs | 2 +- 16 files changed, 171 insertions(+), 121 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index ff7d2ad2..fead4dec 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -29,16 +29,50 @@ pub fn map_network(network: addresses::Network) -> Result { } } -/// Convert from Pallas Hash to Acropolis Hash -pub fn pallas_hash_to_acropolis( - pallas_hash: &pallas_primitives::Hash, +/// Convert a Pallas Hash reference to an Acropolis Hash (owned) +/// Works for any hash size N +pub fn to_hash(pallas_hash: &pallas_primitives::Hash) -> Hash { + Hash::try_from(pallas_hash.as_ref()).unwrap() +} + +/// Convert a Pallas Hash reference to an Acropolis Hash (owned) +/// Works for any hash size N +pub fn genesis_to_hash(pallas_hash: &pallas_primitives::Genesishash) -> Hash { + Hash::try_from(pallas_hash.as_ref()).unwrap() +} + +/// Convert a Pallas Hash reference to an Acropolis Hash (owned) +/// Works for any hash size N +pub fn genesis_delegate_to_hash( + pallas_hash: &pallas_primitives::GenesisDelegateHash, ) -> Hash { - Hash::new(**pallas_hash) + Hash::try_from(pallas_hash.as_ref()).unwrap() } -/// Convert from Acropolis Hash to Pallas Hash -pub fn acropolis_hash_to_pallas(our_hash: &Hash) -> pallas_primitives::Hash { - pallas_primitives::Hash::new(**our_hash) +/// Convert an optional Pallas Hash reference to an optional Acropolis Hash +pub fn to_hash_opt( + pallas_hash: Option<&pallas_primitives::Hash>, +) -> Option> { + pallas_hash.map(|h| to_hash(h)) +} + +/// Convert a Pallas Hash<28> reference to an Acropolis PoolId +pub fn to_pool_id(pallas_hash: &pallas_primitives::Hash<28>) -> PoolId { + PoolId::from(to_hash(pallas_hash)) +} + +/// Convert a Pallas Hash<32> reference to an Acropolis VRFKey +pub fn to_vrf_key(pallas_hash: &pallas_primitives::Hash<32>) -> VRFKey { + VRFKey::try_from(pallas_hash.as_ref()).unwrap() +} + +/// Convert a Pallas Bytes reference to an Acropolis Hash +/// Useful for genesis hash fields that might be stored as Bytes +pub fn bytes_to_hash(bytes: &pallas_primitives::Bytes) -> Hash { + let slice: &[u8] = bytes.as_ref(); + let mut array = [0u8; N]; + array.copy_from_slice(&slice[..N]); + Hash::from(array) } /// Derive our Address from a Pallas address @@ -83,12 +117,8 @@ pub fn map_address(address: &addresses::Address) -> Result
{ addresses::Address::Stake(stake_address) => Ok(Address::Stake(StakeAddress { network: map_network(stake_address.network())?, credential: match stake_address.payload() { - addresses::StakePayload::Stake(hash) => { - StakeCredential::AddrKeyHash(pallas_hash_to_acropolis(hash)) - } - addresses::StakePayload::Script(hash) => { - StakeCredential::ScriptHash(pallas_hash_to_acropolis(hash)) - } + addresses::StakePayload::Stake(hash) => StakeCredential::AddrKeyHash(to_hash(hash)), + addresses::StakePayload::Script(hash) => StakeCredential::ScriptHash(to_hash(hash)), }, })), } @@ -98,10 +128,10 @@ pub fn map_address(address: &addresses::Address) -> Result
{ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(KeyHash::try_from(key_hash.to_vec()).unwrap()) + StakeCredential::AddrKeyHash(to_hash(key_hash)) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(KeyHash::try_from(script_hash.to_vec()).unwrap()) + StakeCredential::ScriptHash(to_hash(script_hash)) } } } @@ -110,10 +140,10 @@ pub fn map_stake_credential(cred: &PallasStakeCredential) -> StakeCredential { pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> StakeAddress { let payload = match cred { PallasStakeCredential::AddrKeyhash(key_hash) => { - StakeCredential::AddrKeyHash(KeyHash::try_from(key_hash.to_vec()).unwrap()) + StakeCredential::AddrKeyHash(to_hash(key_hash)) } PallasStakeCredential::ScriptHash(script_hash) => { - StakeCredential::ScriptHash(KeyHash::try_from(script_hash.to_vec()).unwrap()) + StakeCredential::ScriptHash(to_hash(script_hash)) } }; @@ -123,10 +153,8 @@ pub fn map_stake_address(cred: &PallasStakeCredential, network_id: NetworkId) -> /// Map a Pallas DRep to our DRepChoice pub fn map_drep(drep: &conway::DRep) -> DRepChoice { match drep { - conway::DRep::Key(key_hash) => DRepChoice::Key(pallas_hash_to_acropolis(key_hash)), - conway::DRep::Script(script_hash) => { - DRepChoice::Script(pallas_hash_to_acropolis(script_hash)) - } + conway::DRep::Key(key_hash) => DRepChoice::Key(to_hash(key_hash)), + conway::DRep::Script(script_hash) => DRepChoice::Script(to_hash(script_hash)), conway::DRep::Abstain => DRepChoice::Abstain, conway::DRep::NoConfidence => DRepChoice::NoConfidence, } @@ -188,7 +216,7 @@ pub fn map_nullable_gov_action_id( fn map_constitution(constitution: &conway::Constitution) -> Constitution { Constitution { anchor: map_anchor(&constitution.anchor), - guardrail_script: map_nullable(|x| x, &constitution.guardrail_script), + guardrail_script: map_nullable(|x| to_hash(x), &constitution.guardrail_script), } } @@ -251,7 +279,7 @@ pub fn map_certificate( alonzo::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: PoolId::from(pallas_hash_to_acropolis(pool_key_hash)), + operator: to_pool_id(pool_key_hash), })) } alonzo::Certificate::PoolRegistration { @@ -267,8 +295,8 @@ pub fn map_certificate( } => Ok(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { reg: PoolRegistration { - operator: pallas_hash_to_acropolis(operator), - vrf_key_hash: VRFKey::from(pallas_hash_to_acropolis(vrf_keyhash)), + operator: to_pool_id(operator), + vrf_key_hash: to_vrf_key(vrf_keyhash), pledge: *pledge, cost: *cost, margin: Ratio { @@ -280,7 +308,7 @@ pub fn map_certificate( .iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v), + StakeCredential::AddrKeyHash(to_hash(v)), network_id.clone().into(), ) }) @@ -301,7 +329,7 @@ pub fn map_certificate( alonzo::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok( TxCertificate::PoolRetirementWithPos(PoolRetirementWithPos { ret: PoolRetirement { - operator: pallas_hash_to_acropolis(pool_key_hash), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }, tx_hash, @@ -313,9 +341,9 @@ pub fn map_certificate( genesis_delegate_hash, vrf_key_hash, ) => Ok(TxCertificate::GenesisKeyDelegation(GenesisKeyDelegation { - genesis_hash: pallas_hash_to_acropolis(genesis_hash), - genesis_delegate_hash: pallas_hash_to_acropolis(genesis_delegate_hash), - vrf_key_hash: vrf_key_hash, + genesis_hash: genesis_to_hash(genesis_hash), + genesis_delegate_hash: genesis_delegate_to_hash(genesis_delegate_hash), + vrf_key_hash: to_vrf_key(vrf_key_hash), })), alonzo::Certificate::MoveInstantaneousRewardsCert(mir) => Ok( TxCertificate::MoveInstantaneousReward(MoveInstantaneousReward { @@ -360,7 +388,7 @@ pub fn map_certificate( conway::Certificate::StakeDelegation(cred, pool_key_hash) => { Ok(TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: PoolId::from(pool_key_hash), + operator: to_pool_id(pool_key_hash), })) } conway::Certificate::PoolRegistration { @@ -377,8 +405,8 @@ pub fn map_certificate( } => Ok(TxCertificate::PoolRegistrationWithPos( PoolRegistrationWithPos { reg: PoolRegistration { - operator: operator, - vrf_key_hash: vrf_keyhash, + operator: to_pool_id(operator), + vrf_key_hash: to_vrf_key(vrf_keyhash), pledge: *pledge, cost: *cost, margin: Ratio { @@ -390,7 +418,7 @@ pub fn map_certificate( .into_iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v), + StakeCredential::AddrKeyHash(to_hash(v)), network_id.clone().into(), ) }) @@ -411,7 +439,7 @@ pub fn map_certificate( conway::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok( TxCertificate::PoolRetirementWithPos(PoolRetirementWithPos { ret: PoolRetirement { - operator: pool_key_hash.into(), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }, tx_hash, @@ -443,7 +471,7 @@ pub fn map_certificate( conway::Certificate::StakeVoteDeleg(cred, pool_key_hash, drep) => Ok( TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash, + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), }), ), @@ -451,7 +479,7 @@ pub fn map_certificate( conway::Certificate::StakeRegDeleg(cred, pool_key_hash, coin) => Ok( TxCertificate::StakeRegistrationAndDelegation(StakeRegistrationAndDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash, + operator: to_pool_id(pool_key_hash), deposit: *coin, }), ), @@ -470,7 +498,7 @@ pub fn map_certificate( Ok(TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash, + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), deposit: *coin, }, @@ -860,14 +888,14 @@ pub fn map_governance_proposals_procedures( fn map_voter(voter: &conway::Voter) -> Voter { match voter { conway::Voter::ConstitutionalCommitteeKey(key_hash) => { - Voter::ConstitutionalCommitteeKey(key_hash) + Voter::ConstitutionalCommitteeKey(to_hash(key_hash)) } conway::Voter::ConstitutionalCommitteeScript(script_hash) => { - Voter::ConstitutionalCommitteeScript(script_hash) + Voter::ConstitutionalCommitteeScript(to_hash(script_hash)) } - conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(addr_key_hash), - conway::Voter::DRepScript(script_hash) => Voter::DRepScript(script_hash), - conway::Voter::StakePoolKey(key_hash) => Voter::StakePoolKey(key_hash), + conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(to_hash(addr_key_hash)), + conway::Voter::DRepScript(script_hash) => Voter::DRepScript(to_hash(script_hash)), + conway::Voter::StakePoolKey(key_hash) => Voter::StakePoolKey(to_pool_id(key_hash)), } } diff --git a/common/src/address.rs b/common/src/address.rs index a2cf6e73..df6d166b 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -437,7 +437,7 @@ impl StakeAddress { } /// Convert to binary format (29 bytes) - pub fn to_binary(&self) -> Result { + pub fn to_binary(&self) -> Result> { let network_bits = match self.network { NetworkId::Mainnet => 0b1u8, NetworkId::Testnet => 0b0u8, diff --git a/common/src/hash.rs b/common/src/hash.rs index 7a7b2af8..88c9c0d4 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -16,7 +16,7 @@ use std::{fmt, ops::Deref, str::FromStr}; /// /// # Examples /// -/// ``` +/// ```ignore /// use your_crate::Hash; /// /// // Parse from hex string @@ -67,7 +67,7 @@ impl Hash { /// /// # Examples /// - /// ``` + /// ```ignore /// use your_crate::Hash; /// /// const MY_HASH: Hash<32> = Hash::new([0u8; 32]); @@ -81,7 +81,7 @@ impl Hash { /// /// # Examples /// - /// ``` + /// ```ignore /// use your_crate::Hash; /// /// let hash = Hash::new([1u8; 28]); @@ -97,7 +97,7 @@ impl Hash { /// /// # Examples /// - /// ``` + /// ```ignore /// use your_crate::Hash; /// /// let hash = Hash::new([1u8; 28]); @@ -204,7 +204,7 @@ impl FromStr for Hash { /// /// # Examples /// - /// ``` + /// ```ignore /// use your_crate::Hash; /// /// let hash: Hash<28> = "276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3" @@ -273,7 +273,7 @@ pub type AddrKeyhash = Hash<28>; /// /// # Examples /// -/// ``` +/// ```ignore /// declare_hash_type!(BlockHash, 32); /// declare_hash_type!(TxHash, 32); /// ``` @@ -300,7 +300,7 @@ macro_rules! declare_hash_type { /// /// # Examples /// -/// ``` +/// ```ignore /// declare_hash_type_with_bech32!(VRFKey, 32, "vrf_vk"); /// /// let key: VRFKey = // ... get key @@ -360,7 +360,7 @@ macro_rules! declare_hash_type_with_bech32 { /// /// # Examples /// -/// ``` +/// ```ignore /// // Both are 28 bytes but have different Bech32 encodings /// declare_hash_newtype_with_bech32!(PoolId, 28, "pool"); /// declare_hash_newtype_with_bech32!(DrepId, 28, "drep"); diff --git a/common/src/stake_addresses.rs b/common/src/stake_addresses.rs index 0d49089c..476444cc 100644 --- a/common/src/stake_addresses.rs +++ b/common/src/stake_addresses.rs @@ -1,11 +1,3 @@ -use std::{ - collections::{ - hash_map::{Entry, Iter, Values}, - BTreeMap, HashMap, - }, - sync::atomic::AtomicU64, -}; - use crate::{ math::update_value_with_delta, messages::DRepDelegationDistribution, DRepChoice, DRepCredential, DelegatedStake, KeyHash, Lovelace, PoolId, PoolLiveStakeInfo, StakeAddress, @@ -15,6 +7,13 @@ use anyhow::Result; use dashmap::DashMap; use rayon::prelude::*; use serde_with::{hex::Hex, serde_as}; +use std::{ + collections::{ + hash_map::{Entry, Iter, Values}, + BTreeMap, HashMap, + }, + sync::atomic::AtomicU64, +}; use tracing::{error, warn}; /// State of an individual stake address @@ -172,14 +171,10 @@ impl StakeAddressMap { let delegators: Vec<(KeyHash, u64)> = self .inner .iter() - .filter_map(|(stake_key, sas)| match sas.delegated_spo.as_ref() { + .filter_map(|(stake_address, sas)| match sas.delegated_spo.as_ref() { Some(delegated_spo) => { if delegated_spo.eq(pool_operator) { - // to_binary() now returns Result - stake_key - .to_binary() - .ok() - .map(|key_hash| (key_hash, sas.utxo_value + sas.rewards)) + Some((*stake_address.get_hash(), sas.utxo_value + sas.rewards)) } else { None } @@ -193,15 +188,13 @@ impl StakeAddressMap { /// Get DRep Delegators with live_stakes pub fn get_drep_delegators(&self, drep: &DRepChoice) -> Vec<(KeyHash, u64)> { - // Find stake addresses delegated to drep let delegators: Vec<(KeyHash, u64)> = self .inner .iter() .filter_map(|(stake_address, sas)| match sas.delegated_drep.as_ref() { Some(delegated_drep) => { if delegated_drep.eq(drep) { - // to_binary() now returns Result - stake_address.to_binary().ok().map(|key_hash| (key_hash, sas.utxo_value)) + Some((*stake_address.get_hash(), sas.utxo_value)) } else { None } @@ -224,8 +217,8 @@ impl StakeAddressMap { for stake_address in stake_addresses { let account = self.get(stake_address)?; let utxo_value = account.utxo_value; - let key_hash = stake_address.to_binary().ok()?; - map.insert(key_hash, utxo_value); + let key_hash = stake_address.get_hash(); + map.insert(*key_hash, utxo_value); } Some(map) @@ -242,8 +235,8 @@ impl StakeAddressMap { for stake_address in stake_addresses { let account = self.get(stake_address)?; let balance = account.utxo_value + account.rewards; - let key_hash = stake_address.to_binary().ok()?; - map.insert(key_hash, balance); + let key_hash = stake_address.get_hash(); + map.insert(*key_hash, balance); } Some(map) @@ -260,8 +253,8 @@ impl StakeAddressMap { for stake_address in stake_addresses { let account = self.get(stake_address)?; let maybe_drep = account.delegated_drep.clone(); - let key_hash = stake_address.to_binary().ok()?; - map.insert(key_hash, maybe_drep); + let key_hash = stake_address.get_hash(); + map.insert(*key_hash, maybe_drep); } Some(map) @@ -1243,8 +1236,8 @@ mod tests { let map = stake_addresses.get_accounts_utxo_values_map(&keys).unwrap(); assert_eq!(map.len(), 2); - assert_eq!(map.get(&addr1.to_binary().unwrap()).copied().unwrap(), 1000); - assert_eq!(map.get(&addr2.to_binary().unwrap()).copied().unwrap(), 2000); + assert_eq!(map.get(&addr1.get_hash()).copied().unwrap(), 1000); + assert_eq!(map.get(&addr2.get_hash()).copied().unwrap(), 2000); } #[test] @@ -1357,8 +1350,8 @@ mod tests { let map = stake_addresses.get_accounts_balances_map(&addresses).unwrap(); assert_eq!(map.len(), 2); - assert_eq!(map.get(&addr1.to_binary().unwrap()).copied().unwrap(), 1100); - assert_eq!(map.get(&addr2.to_binary().unwrap()).copied().unwrap(), 2000); + assert_eq!(map.get(&addr1.get_hash()).copied().unwrap(), 1100); + assert_eq!(map.get(&addr2.get_hash()).copied().unwrap(), 2000); } #[test] @@ -1466,14 +1459,14 @@ mod tests { assert_eq!(map.len(), 3); assert_eq!( - map.get(&addr1.to_binary().unwrap()).unwrap(), + map.get(&addr1.get_hash()).unwrap(), &Some(DRepChoice::Abstain) ); assert_eq!( - map.get(&addr2.to_binary().unwrap()).unwrap(), + map.get(&addr2.get_hash()).unwrap(), &Some(DRepChoice::Key(DREP_HASH)) ); - assert_eq!(map.get(&addr3.to_binary().unwrap()).unwrap(), &None); + assert_eq!(map.get(&addr3.get_hash()).unwrap(), &None); } #[test] diff --git a/common/src/types.rs b/common/src/types.rs index 333964da..09fc34ed 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -989,7 +989,7 @@ pub struct GenesisKeyDelegation { pub genesis_delegate_hash: KeyHash, /// VRF key hash - pub vrf_key_hash: KeyHash, + pub vrf_key_hash: VRFKey, } /// Source of a MIR diff --git a/modules/chain_store/src/chain_store.rs b/modules/chain_store/src/chain_store.rs index c2385831..3dfb15db 100644 --- a/modules/chain_store/src/chain_store.rs +++ b/modules/chain_store/src/chain_store.rs @@ -400,7 +400,7 @@ impl ChainStore { block_info.push(BlockInfo { timestamp: block.extra.timestamp, number: header.number(), - hash: *header.hash().into(), + hash: BlockHash::new(*header.hash()), slot: header.slot(), epoch: block.extra.epoch, epoch_slot: block.extra.epoch_slot, @@ -416,8 +416,8 @@ impl ChainStore { block_vrf: header.vrf_vkey().map(|key| VRFKey::try_from(key).ok().unwrap()), op_cert, op_cert_counter, - previous_block: header.previous_hash().map(|h| *h.into()), - next_block: next_hash.map(|h| *h.into()), + previous_block: header.previous_hash().map(|h| BlockHash::new(*h)), + next_block: next_hash.map(|h| BlockHash::new(*h)), confirmations: latest_number - header.number(), }); diff --git a/modules/chain_store/src/stores/fjall.rs b/modules/chain_store/src/stores/fjall.rs index b1583cce..4ac8b2ae 100644 --- a/modules/chain_store/src/stores/fjall.rs +++ b/modules/chain_store/src/stores/fjall.rs @@ -263,7 +263,7 @@ mod tests { status: acropolis_common::BlockStatus::Immutable, slot: block.slot(), number: block.number(), - hash: BlockHash(*block.hash()), + hash: BlockHash::new(*block.hash()), epoch, epoch_slot, new_epoch: false, diff --git a/modules/chain_store/src/stores/mod.rs b/modules/chain_store/src/stores/mod.rs index 866c6199..dcbb28bd 100644 --- a/modules/chain_store/src/stores/mod.rs +++ b/modules/chain_store/src/stores/mod.rs @@ -34,5 +34,5 @@ pub struct ExtraBlockData { pub(crate) fn extract_tx_hashes(block: &[u8]) -> Result> { let block = pallas_traverse::MultiEraBlock::decode(block).context("could not decode block")?; - Ok(block.txs().into_iter().map(|tx| TxHash(*tx.hash())).collect()) + Ok(block.txs().into_iter().map(|tx| TxHash::new(*tx.hash())).collect()) } diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 969ad46a..5e6eb6a6 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -1,6 +1,13 @@ //! Acropolis epoch activity counter: state storage -use acropolis_common::{crypto::keyhash_224, genesis_values::GenesisValues, messages::{BlockTxsMessage, EpochActivityMessage, ProtocolParamsMessage}, params::EPOCH_LENGTH, protocol_params::{Nonces, PraosParams}, BlockHash, BlockInfo, PoolId}; +use acropolis_common::{ + crypto::keyhash_224, + genesis_values::GenesisValues, + messages::{BlockTxsMessage, EpochActivityMessage, ProtocolParamsMessage}, + params::EPOCH_LENGTH, + protocol_params::{Nonces, PraosParams}, + BlockHash, BlockInfo, PoolId, +}; use anyhow::Result; use imbl::HashMap; use pallas::ledger::traverse::MultiEraHeader; @@ -329,7 +336,10 @@ mod tests { assert_eq!(state.epoch_blocks, 2); assert_eq!(state.blocks_minted.len(), 1); - assert_eq!(state.blocks_minted.get(&keyhash_224(issuer)), Some(&2)); + assert_eq!( + state.blocks_minted.get(&keyhash_224(issuer).into()), + Some(&2) + ); } #[test] @@ -348,7 +358,7 @@ mod tests { state .blocks_minted .iter() - .find(|(k, _)| *k == &keyhash_224(b"issuer_1")) + .find(|(k, _)| *k == &keyhash_224(b"issuer_1").into()) .map(|(_, v)| *v), Some(1) ); @@ -356,12 +366,13 @@ mod tests { state .blocks_minted .iter() - .find(|(k, _)| *k == &keyhash_224(b"issuer_2")) + .find(|(k, _)| *k == &keyhash_224(b"issuer_2").into()) .map(|(_, v)| *v), Some(2) ); - let blocks_minted = state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_2")); + let blocks_minted = + state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_2").into()); assert_eq!(blocks_minted, 2); } @@ -417,7 +428,10 @@ mod tests { assert_eq!(ea.total_fees, 123); assert_eq!(ea.spo_blocks.len(), 1); assert_eq!( - ea.spo_blocks.iter().find(|(k, _)| k == &keyhash_224(b"issuer_1")).map(|(_, v)| *v), + ea.spo_blocks + .iter() + .find(|(k, _)| k == &keyhash_224(b"issuer_1").into()) + .map(|(_, v)| *v), Some(1) ); assert_eq!(ea.epoch_start_time, genesis.byron_timestamp); @@ -438,7 +452,8 @@ mod tests { assert_eq!(state.last_block_time, block.timestamp); assert_eq!(state.last_block_height, block.number); - let blocks_minted = state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"vrf_1")); + let blocks_minted = + state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"vrf_1").into()); assert_eq!(blocks_minted, 0); } @@ -473,7 +488,7 @@ mod tests { }, ); assert_eq!( - state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_1")), + state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_1").into()), 2 ); history.lock().await.commit(block.number, state); @@ -490,11 +505,11 @@ mod tests { }, ); assert_eq!( - state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_1")), + state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_1").into()), 0 ); assert_eq!( - state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_2")), + state.get_latest_epoch_blocks_minted_by_pool(&keyhash_224(b"issuer_2").into()), 1 ); history.lock().await.commit(block.number, state); diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index 7fb79c57..0a87cf88 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -513,7 +513,7 @@ pub async fn handle_epoch_total_stakes_blockfrost( .to_string() .map_err(|e| anyhow::anyhow!("Failed to convert stake address to string: {e}"))?; Ok(SPDDByEpochItemRest { - pool_id, + pool_id: pool_id.to_vec(), stake_address, amount, }) diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index deb9e7cb..8ef321b1 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -7,7 +7,7 @@ use acropolis_common::{ rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolId, PoolUpdateAction, Relay, TxHash, VRFKey, Vote, + PoolEpochState, PoolUpdateAction, Relay, TxHash, VRFKey, Vote, }; use anyhow::Result; use num_traits::ToPrimitive; @@ -63,7 +63,7 @@ pub struct BlockInfoREST(pub BlockInfo); pub struct SPDDByEpochItemRest { pub stake_address: String, #[serde_as(as = "DisplayFromBech32")] - pub pool_id: PoolId, + pub pool_id: Vec, #[serde_as(as = "DisplayFromStr")] pub amount: u64, } diff --git a/modules/spo_state/src/epochs_history.rs b/modules/spo_state/src/epochs_history.rs index 1841c9aa..6ac91a42 100644 --- a/modules/spo_state/src/epochs_history.rs +++ b/modules/spo_state/src/epochs_history.rs @@ -225,13 +225,13 @@ mod tests { #[test] fn get_pool_history_returns_data() { let epochs_history = EpochsHistoryState::new(save_history_store_config()); - let key_hash: PoolId = PoolId::new(KeyHash::new([1; 28])); - let spo_block_key_hash = KeyHash::new([2; 28]); + let pool_id = PoolId::new(KeyHash::new([1; 28])); + let spo_block_key_hash = PoolId::new(KeyHash::new([2; 28])); let block = new_block(2); let mut spdd_msg = new_spdd_message(1); spdd_msg.spos = vec![( - key_hash, + pool_id, DelegatedStake { active: 1, active_delegators_count: 1, @@ -244,11 +244,11 @@ mod tests { epoch_activity_msg.spo_blocks = vec![(spo_block_key_hash, 1)]; epoch_activity_msg.total_blocks = 1; epoch_activity_msg.total_fees = 10; - epochs_history.handle_epoch_activity(&block, &epoch_activity_msg, &vec![(key_hash, 1)]); + epochs_history.handle_epoch_activity(&block, &epoch_activity_msg, &vec![(pool_id, 1)]); let mut spo_rewards_msg = new_spo_rewards_message(1); spo_rewards_msg.spos = vec![( - key_hash, + pool_id, SPORewards { total_rewards: 100, operator_rewards: 10, @@ -256,7 +256,7 @@ mod tests { )]; epochs_history.handle_spo_rewards(&block, &spo_rewards_msg); - let pool_history = epochs_history.get_pool_history(&key_hash).unwrap(); + let pool_history = epochs_history.get_pool_history(&pool_id).unwrap(); assert_eq!(2, pool_history.len()); let first_epoch = pool_history.get(0).unwrap(); let third_epoch = pool_history.get(1).unwrap(); diff --git a/modules/spo_state/src/retired_pools_history.rs b/modules/spo_state/src/retired_pools_history.rs index 9bcbe972..6fccf4be 100644 --- a/modules/spo_state/src/retired_pools_history.rs +++ b/modules/spo_state/src/retired_pools_history.rs @@ -66,6 +66,7 @@ impl RetiredPoolsHistoryState { mod tests { use super::*; use crate::test_utils::*; + use acropolis_common::KeyHash; #[test] fn retired_pools_history_is_none_when_store_retired_pools_is_false() { diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index bae134e9..d0d4db2c 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -401,13 +401,14 @@ pub fn process_message( #[cfg(test)] mod test { use crate::*; + use acropolis_common::hash::Hash; use acropolis_common::{ messages::AddressDeltasMessage, Address, AddressDelta, BlockHash, BlockInfo, BlockStatus, - ByronAddress, Era, KeyHash, ShelleyAddress, ShelleyAddressDelegationPart, - ShelleyAddressPaymentPart, ShelleyAddressPointer, StakeAddress, StakeCredential, - UTxOIdentifier, ValueDelta, + ByronAddress, Era, ShelleyAddress, ShelleyAddressDelegationPart, ShelleyAddressPaymentPart, + ShelleyAddressPointer, StakeAddress, StakeCredential, UTxOIdentifier, ValueDelta, }; use bech32::{Bech32, Hrp}; + use pallas::ledger::addresses::{PaymentKeyHash, ScriptHash, StakeKeyHash}; fn parse_addr(s: &str) -> Result { let a = pallas::ledger::addresses::Address::from_bech32(s)?; @@ -428,6 +429,18 @@ mod test { } } + pub fn script_to_hash(pallas_hash: ScriptHash) -> Hash { + Hash::try_from(pallas_hash.as_ref()).unwrap() + } + + pub fn stake_to_hash(pallas_hash: StakeKeyHash) -> Hash { + Hash::try_from(pallas_hash.as_ref()).unwrap() + } + + pub fn payment_to_hash(pallas_hash: PaymentKeyHash) -> Hash { + Hash::try_from(pallas_hash.as_ref()).unwrap() + } + /// Derive our Address from a Pallas address // This is essentially a 1:1 mapping but makes the Message definitions independent // of Pallas @@ -443,20 +456,20 @@ mod test { payment: match shelley_address.payment() { addresses::ShelleyPaymentPart::Key(hash) => { - ShelleyAddressPaymentPart::PaymentKeyHash(hash) + ShelleyAddressPaymentPart::PaymentKeyHash(payment_to_hash(*hash)) } addresses::ShelleyPaymentPart::Script(hash) => { - ShelleyAddressPaymentPart::ScriptHash(hash) + ShelleyAddressPaymentPart::ScriptHash(script_to_hash(*hash)) } }, delegation: match shelley_address.delegation() { addresses::ShelleyDelegationPart::Null => ShelleyAddressDelegationPart::None, addresses::ShelleyDelegationPart::Key(hash) => { - ShelleyAddressDelegationPart::StakeKeyHash(hash) + ShelleyAddressDelegationPart::StakeKeyHash(stake_to_hash(*hash)) } addresses::ShelleyDelegationPart::Script(hash) => { - ShelleyAddressDelegationPart::ScriptHash(hash) + ShelleyAddressDelegationPart::ScriptHash(script_to_hash(*hash)) } addresses::ShelleyDelegationPart::Pointer(pointer) => { ShelleyAddressDelegationPart::Pointer(ShelleyAddressPointer { @@ -472,10 +485,10 @@ mod test { network: map_network(stake_address.network())?, credential: match stake_address.payload() { addresses::StakePayload::Stake(hash) => { - StakeCredential::AddrKeyHash(KeyHash::from(hash)) + StakeCredential::AddrKeyHash(stake_to_hash(*hash)) } addresses::StakePayload::Script(hash) => { - StakeCredential::ScriptHash(KeyHash::from(hash)) + StakeCredential::ScriptHash(script_to_hash(*hash)) } }, })), diff --git a/modules/tx_unpacker/src/tx_unpacker.rs b/modules/tx_unpacker/src/tx_unpacker.rs index b63c09f3..a76749a2 100644 --- a/modules/tx_unpacker/src/tx_unpacker.rs +++ b/modules/tx_unpacker/src/tx_unpacker.rs @@ -183,7 +183,7 @@ impl TxUnpacker { for input in inputs { // MultiEraInput // Lookup and remove UTxOIdentifier from registry let oref = input.output_ref(); - let tx_ref = TxOutRef::new(TxHash(**oref.hash()), oref.index() as u16); + let tx_ref = TxOutRef::new(TxHash::new(**oref.hash()), oref.index() as u16); match utxo_registry.consume(&tx_ref) { Ok(tx_identifier) => { @@ -270,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, TxHash(*tx_hash), tx_index, cert_index, network_id.clone()) { + match map_parameters::map_certificate(&cert, TxHash::new(*tx_hash), tx_index, cert_index, network_id.clone()) { Ok(tx_cert) => { certificates.push(tx_cert); }, @@ -343,7 +343,7 @@ impl TxUnpacker { if publish_governance_procedures_topic.is_some() { if let Some(pp) = props { // Nonempty set -- governance_message.proposal_procedures will not be empty - let mut proc_id = GovActionId { transaction_id: TxHash(*tx.hash()), action_index: 0 }; + let mut proc_id = GovActionId { transaction_id: TxHash::new(*tx.hash()), action_index: 0 }; for (action_index, pallas_governance_proposals) in pp.iter().enumerate() { match proc_id.set_action_index(action_index) .and_then (|proc_id| map_parameters::map_governance_proposals_procedures(&proc_id, &pallas_governance_proposals)) @@ -357,7 +357,7 @@ impl TxUnpacker { if let Some(pallas_vp) = votes { // Nonempty set -- governance_message.voting_procedures will not be empty match map_parameters::map_all_governance_voting_procedures(pallas_vp) { - Ok(vp) => voting_procedures.push((TxHash(*tx.hash()), vp)), + Ok(vp) => voting_procedures.push((TxHash::new(*tx.hash()), vp)), Err(e) => error!("Cannot decode governance voting procedures in slot {}: {e}", block.slot) } } diff --git a/modules/tx_unpacker/src/utxo_registry.rs b/modules/tx_unpacker/src/utxo_registry.rs index d10de175..f2f1453d 100644 --- a/modules/tx_unpacker/src/utxo_registry.rs +++ b/modules/tx_unpacker/src/utxo_registry.rs @@ -174,7 +174,7 @@ mod tests { use anyhow::Result; fn make_hash(byte: u8) -> TxHash { - TxHash([byte; 32]) + TxHash::new([byte; 32]) } impl UTxORegistry { /// Lookup unspent tx output From a7cfb003a413146e48338996c488d6b7b4e85f85 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 15:21:56 -0700 Subject: [PATCH 06/20] Delete unused `byte_array` module and remove associated references for cleanup. Refactor `POOL_KEY_LENGTH` to `POOL_ID_LENGTH` --- common/src/byte_array.rs | 89 ------------------- common/src/lib.rs | 1 - modules/accounts_state/src/rewards.rs | 4 +- modules/accounts_state/src/snapshot.rs | 3 +- .../src/spo_distribution_store.rs | 36 ++++---- modules/spdd_state/src/rest.rs | 2 +- 6 files changed, 21 insertions(+), 114 deletions(-) delete mode 100644 common/src/byte_array.rs diff --git a/common/src/byte_array.rs b/common/src/byte_array.rs deleted file mode 100644 index 36524c61..00000000 --- a/common/src/byte_array.rs +++ /dev/null @@ -1,89 +0,0 @@ -// use crate::serialization::{Bech32Conversion, Bech32WithHrp}; -// use anyhow::Error; -// use hex::{FromHex, FromHexError}; -// use serde_with::{hex::Hex, serde_as}; -// use std::ops::Deref; -// -// macro_rules! declare_byte_array_type { -// ($name:ident, $size:expr) => { -// /// $name -// #[serde_as] -// #[derive( -// Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, -// )] -// pub struct $name(#[serde_as(as = "Hex")] pub [u8; $size]); -// -// impl From<[u8; $size]> for $name { -// fn from(bytes: [u8; $size]) -> Self { -// Self(bytes) -// } -// } -// -// impl FromHex for $name { -// type Error = FromHexError; -// -// fn from_hex>(hex: T) -> Result { -// match Self::try_from(Vec::::from_hex(hex)?) { -// Ok(b) => Ok(b), -// Err(_) => Err(FromHexError::InvalidStringLength), -// } -// } -// } -// -// impl TryFrom> for $name { -// type Error = Vec; -// fn try_from(vec: Vec) -> Result { -// Ok($name(vec.try_into()?)) -// } -// } -// -// impl TryFrom<&[u8]> for $name { -// type Error = std::array::TryFromSliceError; -// fn try_from(arr: &[u8]) -> Result { -// Ok($name(arr.try_into()?)) -// } -// } -// -// impl AsRef<[u8]> for $name { -// fn as_ref(&self) -> &[u8] { -// &self.0 -// } -// } -// -// impl Deref for $name { -// type Target = [u8; $size]; -// fn deref(&self) -> &Self::Target { -// &self.0 -// } -// } -// }; -// } -// -// macro_rules! declare_byte_array_type_with_bech32 { -// ($name:ident, $size:expr, $hrp:expr) => { -// declare_byte_array_type!($name, $size); -// impl Bech32Conversion for $name { -// fn to_bech32(&self) -> Result { -// self.0.to_vec().to_bech32_with_hrp($hrp) -// } -// fn from_bech32(s: &str) -> Result { -// match Vec::::from_bech32_with_hrp(s, $hrp) { -// Ok(v) => match Self::try_from(v) { -// Ok(s) => Ok(s), -// Err(_) => Err(Error::msg(format!( -// "Bad vector input to {}", -// stringify!($name) -// ))), -// }, -// Err(e) => Err(e), -// } -// } -// } -// }; -// } -// -// // declare_byte_array_type!(BlockHash, 32); -// // -// // declare_byte_array_type!(TxHash, 32); -// // -// // declare_byte_array_type_with_bech32!(VRFKey, 32, "vrf_vk"); diff --git a/common/src/lib.rs b/common/src/lib.rs index 239e7a83..0ca5a58a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,7 +1,6 @@ // Acropolis common library - main library exports pub mod address; -pub mod byte_array; pub mod calculations; pub mod cip19; pub mod commands; diff --git a/modules/accounts_state/src/rewards.rs b/modules/accounts_state/src/rewards.rs index e8fab848..5aade3e2 100644 --- a/modules/accounts_state/src/rewards.rs +++ b/modules/accounts_state/src/rewards.rs @@ -2,8 +2,8 @@ use crate::snapshot::{Snapshot, SnapshotSPO}; use acropolis_common::{ - protocol_params::ShelleyParams, rational_number::RationalNumber, Lovelace, PoolId, - SPORewards, StakeAddress, + protocol_params::ShelleyParams, rational_number::RationalNumber, Lovelace, PoolId, SPORewards, + StakeAddress, }; use anyhow::{bail, Result}; use bigdecimal::{BigDecimal, One, ToPrimitive, Zero}; diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index 22a37759..1533aaac 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -2,8 +2,7 @@ use crate::state::{Pots, RegistrationChange}; use acropolis_common::{ - stake_addresses::StakeAddressMap, Lovelace, PoolId, PoolRegistration, Ratio, - StakeAddress, + stake_addresses::StakeAddressMap, Lovelace, PoolId, PoolRegistration, Ratio, StakeAddress, }; use imbl::OrdMap; use std::collections::HashMap; diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index 9b88610b..761e7436 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -5,36 +5,36 @@ use acropolis_common::PoolId; use anyhow::Result; use fjall::{Config, Keyspace, PartitionCreateOptions}; -const POOL_KEY_LENGTH: usize = 28; +const POOL_ID_LENGTH: usize = 28; const STAKE_KEY_LEN: usize = 28; const EPOCH_LEN: usize = 8; -const TOTAL_KEY_LEN: usize = EPOCH_LEN + POOL_KEY_LENGTH + STAKE_KEY_LEN; +const TOTAL_KEY_LEN: usize = EPOCH_LEN + POOL_ID_LENGTH + STAKE_KEY_LEN; // Batch size balances commit overhead vs memory usage // ~720KB per batch (72 bytes × 10,000) // ~130 commits for typical epoch (~1.3M delegations) const BATCH_SIZE: usize = 10_000; -fn encode_key(epoch: u64, pool_key: &PoolId, stake_key: &AddrKeyhash) -> Vec { +fn encode_key(epoch: u64, pool_id: &PoolId, stake_key: &AddrKeyhash) -> Vec { let mut key = Vec::with_capacity(TOTAL_KEY_LEN); key.extend_from_slice(&epoch.to_be_bytes()); - key.extend_from_slice(pool_key.as_ref()); + key.extend_from_slice(pool_id.as_ref()); key.extend_from_slice(stake_key.as_ref()); key } -fn encode_epoch_pool_prefix(epoch: u64, pool_key: &PoolId) -> Vec { - let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_KEY_LENGTH); +fn encode_epoch_pool_prefix(epoch: u64, pool_id: &PoolId) -> Vec { + let mut prefix = Vec::with_capacity(EPOCH_LEN + POOL_ID_LENGTH); prefix.extend_from_slice(&epoch.to_be_bytes()); - prefix.extend_from_slice(pool_key.as_ref()); + prefix.extend_from_slice(pool_id.as_ref()); prefix } fn decode_key(key: &[u8]) -> Result<(u64, PoolId, AddrKeyhash)> { let epoch = u64::from_be_bytes(key[..EPOCH_LEN].try_into()?); - let pool_key: PoolId = key[EPOCH_LEN..EPOCH_LEN + POOL_KEY_LENGTH].try_into()?; - let stake_key: AddrKeyhash = key[EPOCH_LEN + POOL_KEY_LENGTH..].try_into()?; - Ok((epoch, pool_key, stake_key)) + let pool_id: PoolId = key[EPOCH_LEN..EPOCH_LEN + POOL_ID_LENGTH].try_into()?; + let stake_key: AddrKeyhash = key[EPOCH_LEN + POOL_ID_LENGTH..].try_into()?; + Ok((epoch, pool_id, stake_key)) } /// Encode epoch completion marker key @@ -45,7 +45,7 @@ fn encode_epoch_marker(epoch: u64) -> Vec { pub struct SPDDStore { keyspace: Keyspace, /// Partition for all SPDD data - /// Key format: epoch(8 bytes) + pool_key + stake_key + /// Key format: epoch(8 bytes) + pool_id + stake_key /// Value: amount(8 bytes) spdd: fjall::PartitionHandle, /// Partition for epoch completion markers @@ -110,9 +110,9 @@ impl SPDDStore { let mut batch = self.keyspace.batch(); let mut count = 0; - for (pool_key, delegations) in spdd_state { + for (pool_id, delegations) in spdd_state { for (stake_key, amount) in delegations { - let key = encode_key(epoch, &pool_key, &stake_key); + let key = encode_key(epoch, &pool_id, &stake_key); let value = amount.to_be_bytes(); batch.insert(&self.spdd, key, value); @@ -192,9 +192,9 @@ impl SPDDStore { let mut result = Vec::new(); for item in self.spdd.prefix(prefix) { let (key, value) = item?; - let (_, pool_key, stake_key) = decode_key(&key)?; + let (_, pool_id, stake_key) = decode_key(&key)?; let amount = u64::from_be_bytes(value.as_ref().try_into()?); - result.push((pool_key, stake_key, amount)); + result.push((pool_id, stake_key, amount)); } Ok(result) } @@ -202,13 +202,13 @@ impl SPDDStore { pub fn query_by_epoch_and_pool( &self, epoch: u64, - pool_key: &PoolId, + pool_id: &PoolId, ) -> Result> { if !self.is_epoch_complete(epoch)? { return Err(anyhow::anyhow!("Epoch SPDD Data is not complete")); } - let prefix = encode_epoch_pool_prefix(epoch, pool_key); + let prefix = encode_epoch_pool_prefix(epoch, pool_id); let mut result = Vec::new(); for item in self.spdd.prefix(prefix) { let (key, value) = item?; @@ -224,13 +224,11 @@ impl SPDDStore { mod tests { use super::*; use acropolis_common::crypto::keyhash_224; - // ADDED use acropolis_common::hash::AddrKeyhash; use acropolis_common::PoolId; const DB_PATH: &str = "spdd_db"; - // ADDED: Helper to create test hashes fn test_pool_hash(byte: u8) -> PoolId { PoolId::new(keyhash_224(&vec![byte])) } diff --git a/modules/spdd_state/src/rest.rs b/modules/spdd_state/src/rest.rs index 29662628..330a8f8a 100644 --- a/modules/spdd_state/src/rest.rs +++ b/modules/spdd_state/src/rest.rs @@ -1,5 +1,5 @@ use crate::state::State; -use acropolis_common::serialization::{Bech32Conversion}; +use acropolis_common::serialization::Bech32Conversion; use acropolis_common::DelegatedStake; use acropolis_common::{extract_strict_query_params, messages::RESTResponse}; use anyhow::Result; From 727ffee86cc6e9b4bfa5491005f27742b8efa9f9 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 16:10:41 -0700 Subject: [PATCH 07/20] Refactor: Replace `VRFKey` with `VrfKeyHash` across modules for consistency, update associated type aliases, imports, and serialization logic. --- codec/src/map_parameters.rs | 12 +++++----- common/src/address.rs | 22 +++++++------------ common/src/hash.rs | 7 ------ common/src/queries/blocks.rs | 4 ++-- common/src/snapshot/pool_params.rs | 7 +++--- common/src/snapshot/streaming_snapshot.rs | 22 +++++++------------ common/src/types.rs | 11 ++++++---- .../src/spo_distribution_store.rs | 4 ++-- modules/accounts_state/src/state.rs | 6 ++--- modules/chain_store/src/chain_store.rs | 4 ++-- .../parameters_state/src/genesis_params.rs | 2 +- .../rest_blockfrost/src/handlers/epochs.rs | 9 ++++---- modules/rest_blockfrost/src/types.rs | 4 ++-- modules/spo_state/src/state.rs | 6 ++--- .../src/body_fetcher.rs | 4 ++-- 15 files changed, 55 insertions(+), 69 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index fead4dec..f9d5cfc9 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -62,8 +62,8 @@ pub fn to_pool_id(pallas_hash: &pallas_primitives::Hash<28>) -> PoolId { } /// Convert a Pallas Hash<32> reference to an Acropolis VRFKey -pub fn to_vrf_key(pallas_hash: &pallas_primitives::Hash<32>) -> VRFKey { - VRFKey::try_from(pallas_hash.as_ref()).unwrap() +pub fn to_vrf_key(pallas_hash: &pallas_primitives::Hash<32>) -> VrfKeyHash { + VrfKeyHash::try_from(pallas_hash.as_ref()).unwrap() } /// Convert a Pallas Bytes reference to an Acropolis Hash @@ -89,20 +89,20 @@ pub fn map_address(address: &addresses::Address) -> Result
{ payment: match shelley_address.payment() { addresses::ShelleyPaymentPart::Key(hash) => { - ShelleyAddressPaymentPart::PaymentKeyHash(hash.to_vec().try_into().unwrap()) + ShelleyAddressPaymentPart::PaymentKeyHash(to_hash(hash)) } addresses::ShelleyPaymentPart::Script(hash) => { - ShelleyAddressPaymentPart::ScriptHash(hash.to_vec().try_into().unwrap()) + ShelleyAddressPaymentPart::ScriptHash(to_hash(hash)) } }, delegation: match shelley_address.delegation() { addresses::ShelleyDelegationPart::Null => ShelleyAddressDelegationPart::None, addresses::ShelleyDelegationPart::Key(hash) => { - ShelleyAddressDelegationPart::StakeKeyHash(hash.to_vec().try_into().unwrap()) + ShelleyAddressDelegationPart::StakeKeyHash(to_hash(hash)) } addresses::ShelleyDelegationPart::Script(hash) => { - ShelleyAddressDelegationPart::ScriptHash(hash.to_vec().try_into().unwrap()) + ShelleyAddressDelegationPart::ScriptHash(to_hash(hash)) } addresses::ShelleyDelegationPart::Pointer(pointer) => { ShelleyAddressDelegationPart::Pointer(ShelleyAddressPointer { diff --git a/common/src/address.rs b/common/src/address.rs index df6d166b..44abe0b9 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -211,25 +211,19 @@ impl ShelleyAddress { let header = *header; + let to_28_bytes = |slice: &[u8]| -> Result { + slice.try_into().map_err(|_| anyhow!("Invalid hash")) + }; + let payment_part = match (header >> 4) & 0x01 { - 0 => ShelleyAddressPaymentPart::PaymentKeyHash( - data[1..29].try_into().map_err(|_| anyhow!("Invalid payment key hash size"))?, - ), - 1 => ShelleyAddressPaymentPart::ScriptHash( - data[1..29].try_into().map_err(|_| anyhow!("Invalid script hash size"))?, - ), + 0 => ShelleyAddressPaymentPart::PaymentKeyHash(to_28_bytes(&data[1..29])?), + 1 => ShelleyAddressPaymentPart::ScriptHash(to_28_bytes(&data[1..29])?), _ => panic!(), }; let delegation_part = match (header >> 5) & 0x03 { - 0 => ShelleyAddressDelegationPart::StakeKeyHash( - data[29..57].try_into().map_err(|_| anyhow!("Invalid stake key hash size"))?, - ), - 1 => ShelleyAddressDelegationPart::ScriptHash( - data[29..57] - .try_into() - .map_err(|_| anyhow!("Invalid delegation script hash size"))?, - ), + 0 => ShelleyAddressDelegationPart::StakeKeyHash(to_28_bytes(&data[29..57])?), + 1 => ShelleyAddressDelegationPart::ScriptHash(to_28_bytes(&data[29..57])?), 2 => { let mut decoder = VarIntDecoder::new(&data[29..]); let slot = decoder.read()?; diff --git a/common/src/hash.rs b/common/src/hash.rs index 88c9c0d4..0d104993 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -262,13 +262,6 @@ impl<'a, C, const BYTES: usize> minicbor::Decode<'a, C> for Hash { } } -// Type aliases for common hash sizes in Cardano -/// A 28-byte hash used for scripts in Cardano addresses. -pub type ScriptHash = Hash<28>; - -/// A 28-byte hash of an address key in Cardano. -pub type AddrKeyhash = Hash<28>; - /// Declares a type alias for a hash with optional documentation. /// /// # Examples diff --git a/common/src/queries/blocks.rs b/common/src/queries/blocks.rs index 1b5c2a33..efb35e6d 100644 --- a/common/src/queries/blocks.rs +++ b/common/src/queries/blocks.rs @@ -1,7 +1,7 @@ use crate::{ queries::misc::Order, serialization::{Bech32Conversion, Bech32WithHrp}, - Address, BlockHash, GenesisDelegate, HeavyDelegate, KeyHash, TxHash, TxIdentifier, VRFKey, + Address, BlockHash, GenesisDelegate, HeavyDelegate, KeyHash, TxHash, TxIdentifier, VrfKeyHash, }; use cryptoxide::hashing::blake2b::Blake2b; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -114,7 +114,7 @@ pub struct BlockInfo { pub tx_count: u64, pub output: Option, pub fees: Option, - pub block_vrf: Option, + pub block_vrf: Option, pub op_cert: Option, pub op_cert_counter: Option, pub previous_block: Option, diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index c81a0eee..51eb9b04 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -13,14 +13,15 @@ // limitations under the License. use super::streaming_snapshot::{ - cbor, AddrKeyhash, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, + cbor, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, }; -use crate::{PoolId, VRFKey}; +use crate::{PoolId, VrfKeyHash}; +use crate::types::AddrKeyhash; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PoolParams { pub id: PoolId, - pub vrf: VRFKey, + pub vrf: VrfKeyHash, pub pledge: Coin, pub cost: Coin, pub margin: UnitInterval, diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index dd727410..8e91a5a2 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -29,7 +29,7 @@ use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use tracing::info; -pub use crate::hash::{AddrKeyhash, Hash, ScriptHash}; +pub use crate::hash::Hash; pub use crate::stake_addresses::{AccountState, StakeAddressState}; pub use crate::StakeCredential; @@ -74,7 +74,7 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential { Ok(StakeCredential::ScriptHash(key_hash)) } 1 => { - // AddrKeyHash variant (second in enum) - decode bytes directly + // AddrKeyHash variant (second in enum) - decodes bytes directly let bytes = d.bytes()?; let key_hash = KeyHash::try_from(bytes).map_err(|_| { minicbor::decode::Error::message( @@ -307,6 +307,8 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { // Type aliases for pool_params compatibility // ----------------------------------------------------------------------------- +pub use crate::types::AddrKeyhash; +pub use crate::types::ScriptHash; use crate::{KeyHash, PoolId}; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; @@ -1086,12 +1088,8 @@ impl StreamingSnapshotParser { // Convert DRep delegation from StrictMaybe to Option let delegated_drep = match &account.drep { StrictMaybe::Just(drep) => Some(match drep { - DRep::Key(hash) => crate::DRepChoice::Key( - KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), - ), - DRep::Script(hash) => crate::DRepChoice::Script( - KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), - ), + DRep::Key(hash) => crate::DRepChoice::Key(*hash), + DRep::Script(hash) => crate::DRepChoice::Script(*hash), DRep::Abstain => crate::DRepChoice::Abstain, DRep::NoConfidence => crate::DRepChoice::NoConfidence, }), @@ -1456,12 +1454,8 @@ impl StreamingSnapshotParser { // Convert DRep delegation from StrictMaybe to Option let delegated_drep = match &account.drep { StrictMaybe::Just(drep) => Some(match drep { - DRep::Key(hash) => crate::DRepChoice::Key( - KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), - ), - DRep::Script(hash) => crate::DRepChoice::Script( - KeyHash::try_from(hash.as_ref().to_vec()).unwrap(), - ), + DRep::Key(hash) => crate::DRepChoice::Key(*hash), + DRep::Script(hash) => crate::DRepChoice::Script(*hash), DRep::Abstain => crate::DRepChoice::Abstain, DRep::NoConfidence => crate::DRepChoice::NoConfidence, }), diff --git a/common/src/types.rs b/common/src/types.rs index 09fc34ed..cb985e64 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -2,7 +2,7 @@ // We don't use these types in the acropolis_common crate itself #![allow(dead_code)] -use crate::hash::{AddrKeyhash, Hash, ScriptHash}; +use crate::hash::Hash; use crate::{ address::{Address, ShelleyAddress, StakeAddress}, declare_hash_newtype_with_bech32, declare_hash_type, declare_hash_type_with_bech32, @@ -437,12 +437,15 @@ impl Default for UTXODelta { pub type KeyHash = Hash<28>; +pub type ScriptHash = KeyHash; +pub type AddrKeyhash = KeyHash; + /// Script identifier pub type GenesisKeyhash = Vec; declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); -declare_hash_newtype_with_bech32!(VRFKey, 32, "vrf_vk"); +declare_hash_newtype_with_bech32!(VrfKeyHash, 32, "vrf_vk"); declare_hash_newtype_with_bech32!(PoolId, 28, "pool"); declare_hash_newtype_with_bech32!(DrepKey, 28, "drep"); declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); @@ -844,7 +847,7 @@ pub struct PoolRegistration { /// VRF key hash #[serde_as(as = "Hex")] #[n(1)] - pub vrf_key_hash: VRFKey, + pub vrf_key_hash: VrfKeyHash, /// Pledged Ada #[n(2)] @@ -989,7 +992,7 @@ pub struct GenesisKeyDelegation { pub genesis_delegate_hash: KeyHash, /// VRF key hash - pub vrf_key_hash: VRFKey, + pub vrf_key_hash: VrfKeyHash, } /// Source of a MIR diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index 761e7436..ea24eddc 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acropolis_common::hash::AddrKeyhash; +use acropolis_common::types::AddrKeyhash; use acropolis_common::PoolId; use anyhow::Result; use fjall::{Config, Keyspace, PartitionCreateOptions}; @@ -224,7 +224,7 @@ impl SPDDStore { mod tests { use super::*; use acropolis_common::crypto::keyhash_224; - use acropolis_common::hash::AddrKeyhash; + use acropolis_common::types::AddrKeyhash; use acropolis_common::PoolId; const DB_PATH: &str = "spdd_db"; diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 03552d07..63f4f9d6 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -996,7 +996,7 @@ mod tests { Anchor, Committee, Constitution, CostModel, DRepVotingThresholds, NetworkId, PoolVotingThresholds, Pot, PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAndVoteDelegation, StakeCredential, StakeRegistrationAndStakeAndVoteDelegation, - StakeRegistrationAndVoteDelegation, VRFKey, VoteDelegation, Withdrawal, + StakeRegistrationAndVoteDelegation, VrfKeyHash, VoteDelegation, Withdrawal, }; // Helper to create a StakeAddress from a byte slice @@ -1017,8 +1017,8 @@ mod tests { keyhash_224(bytes) } - fn test_vrf_keyhash(byte: u8) -> VRFKey { - VRFKey::new(keyhash_256(&vec![byte])) + fn test_vrf_keyhash(byte: u8) -> VrfKeyHash { + VrfKeyHash::new(keyhash_256(&vec![byte])) } const STAKE_KEY_HASH: [u8; 3] = [0x99, 0x0f, 0x00]; diff --git a/modules/chain_store/src/chain_store.rs b/modules/chain_store/src/chain_store.rs index 3dfb15db..b7423e66 100644 --- a/modules/chain_store/src/chain_store.rs +++ b/modules/chain_store/src/chain_store.rs @@ -12,7 +12,7 @@ use acropolis_common::{ }, queries::misc::Order, state_history::{StateHistory, StateHistoryStore}, - BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, TxHash, VRFKey, + BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, TxHash, VrfKeyHash, }; use anyhow::{bail, Result}; use caryatid_sdk::{module, Context, Module}; @@ -413,7 +413,7 @@ impl ChainStore { tx_count: decoded.tx_count() as u64, output, fees, - block_vrf: header.vrf_vkey().map(|key| VRFKey::try_from(key).ok().unwrap()), + block_vrf: header.vrf_vkey().map(|key| VrfKeyHash::try_from(key).ok().unwrap()), op_cert, op_cert_counter, previous_block: header.previous_hash().map(|h| BlockHash::new(*h)), diff --git a/modules/parameters_state/src/genesis_params.rs b/modules/parameters_state/src/genesis_params.rs index 98bade3a..9020e8a0 100644 --- a/modules/parameters_state/src/genesis_params.rs +++ b/modules/parameters_state/src/genesis_params.rs @@ -1,5 +1,5 @@ use crate::alonzo_genesis; -use acropolis_common::hash::ScriptHash; +use acropolis_common::types::ScriptHash; use acropolis_common::{ protocol_params::{AlonzoParams, BabbageParams, ByronParams, ConwayParams, ShelleyParams}, rational_number::{rational_number_from_f32, RationalNumber}, diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index 0a87cf88..cbc302c3 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -4,6 +4,7 @@ use crate::{ EpochActivityRest, ProtocolParamsRest, SPDDByEpochAndPoolItemRest, SPDDByEpochItemRest, }, }; +use acropolis_common::serialization::Bech32Conversion; use acropolis_common::{ messages::{Message, RESTResponse, StateQuery, StateQueryResponse}, queries::{ @@ -553,7 +554,7 @@ pub async fn handle_epoch_pool_stakes_blockfrost( } }; - let Ok(pool_id) = Vec::::from_bech32_with_hrp(pool_id, "pool") else { + let Ok(pool_id) = PoolId::from_bech32(pool_id) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id}"), @@ -618,7 +619,7 @@ pub async fn handle_epoch_pool_stakes_blockfrost( let msg = Arc::new(Message::StateQuery(StateQuery::Accounts( AccountsStateQuery::GetSPDDByEpochAndPool { epoch: epoch_number, - pool_id: pool_id.try_into().unwrap(), + pool_id, }, ))); let spdd = query_state( @@ -698,7 +699,7 @@ pub async fn handle_epoch_pool_blocks_blockfrost( } }; - let Ok(spo) = Vec::::from_bech32_with_hrp(pool_id_param, "pool") else { + let Ok(spo) = PoolId::from_bech32(pool_id_param) else { return Ok(RESTResponse::with_text( 400, &format!("Invalid Bech32 stake pool ID: {pool_id_param}"), @@ -708,7 +709,7 @@ pub async fn handle_epoch_pool_blocks_blockfrost( // query Pool's Blocks by epoch from spo-state let msg = Arc::new(Message::StateQuery(StateQuery::Pools( PoolsStateQuery::GetBlocksByPoolAndEpoch { - pool_id: PoolId::try_from(spo.clone()).unwrap(), + pool_id: spo, epoch: epoch_number, }, ))); diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index 8ef321b1..22316a23 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -7,7 +7,7 @@ use acropolis_common::{ rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolUpdateAction, Relay, TxHash, VRFKey, Vote, + PoolEpochState, PoolUpdateAction, Relay, TxHash, VrfKeyHash, Vote, }; use anyhow::Result; use num_traits::ToPrimitive; @@ -432,7 +432,7 @@ pub struct PoolInfoRest { #[serde_as(as = "Hex")] pub hex: KeyHash, #[serde_as(as = "Hex")] - pub vrf_key: VRFKey, + pub vrf_key: VrfKeyHash, pub blocks_minted: u64, pub blocks_epoch: u64, #[serde_as(as = "DisplayFromStr")] diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 677491da..10fc3fc2 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -682,7 +682,7 @@ mod tests { use acropolis_common::hash::Hash; use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, - PoolId, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VRFKey, + PoolId, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxHash, VrfKeyHash, }; use tokio::sync::Mutex; @@ -696,11 +696,11 @@ mod tests { fn default_pool_registration( operator: PoolId, - vrf_key_hash: Option, + vrf_key_hash: Option, ) -> PoolRegistration { PoolRegistration { operator, - vrf_key_hash: vrf_key_hash.unwrap_or_else(|| VRFKey::default()), + vrf_key_hash: vrf_key_hash.unwrap_or_else(|| VrfKeyHash::default()), pledge: 0, cost: 0, margin: Ratio { diff --git a/modules/upstream_chain_fetcher/src/body_fetcher.rs b/modules/upstream_chain_fetcher/src/body_fetcher.rs index 3ce93105..bd2f7b08 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::RawBlockMessage, BlockInfo, BlockStatus, Era}; +use acropolis_common::{messages::RawBlockMessage, BlockHash, BlockInfo, BlockStatus, Era}; use anyhow::{bail, Result}; use crossbeam::channel::{Receiver, TryRecvError}; use pallas::{ @@ -117,7 +117,7 @@ impl BodyFetcher { }, // TODO vary with 'k' slot, number, - hash: hash.into(), + hash: BlockHash::new(hash), epoch, epoch_slot, new_epoch, From fb77f49c76ad1f2eba9077bc85d1ed615d160d29 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 17:31:16 -0700 Subject: [PATCH 08/20] Refactor: Replace manual key hash conversions with type-safe utilities, update imports, and adjust serialization logic across modules for consistency. --- codec/src/map_parameters.rs | 18 +++++++-------- common/src/address.rs | 22 +++++++++---------- common/src/snapshot/pool_params.rs | 2 +- modules/accounts_state/src/snapshot.rs | 6 ++--- modules/accounts_state/src/state.rs | 15 +++++-------- .../src/immutable_historical_account_store.rs | 14 +++++++----- .../rest_blockfrost/src/handlers/epochs.rs | 1 - modules/rest_blockfrost/src/handlers/pools.rs | 4 +--- modules/rest_blockfrost/src/types.rs | 2 +- modules/spo_state/src/state.rs | 21 +++++++++--------- 10 files changed, 50 insertions(+), 55 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 23fdb50b..d7c0e594 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -327,7 +327,7 @@ pub fn map_certificate( }), alonzo::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok(TxCertificateWithPos { cert: TxCertificate::PoolRetirement(PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }), tx_identifier, @@ -395,7 +395,7 @@ pub fn map_certificate( Ok(TxCertificateWithPos { cert: TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), }), tx_identifier, cert_index: cert_index.try_into().unwrap(), @@ -415,8 +415,8 @@ pub fn map_certificate( pool_metadata, } => Ok(TxCertificateWithPos { cert: TxCertificate::PoolRegistration(PoolRegistration { - operator: operator.to_vec(), - vrf_key_hash: vrf_keyhash.to_vec(), + operator: to_pool_id(operator), + vrf_key_hash: to_vrf_key(vrf_keyhash), pledge: *pledge, cost: *cost, margin: Ratio { @@ -435,7 +435,7 @@ pub fn map_certificate( .into_iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v.to_vec()), + StakeCredential::AddrKeyHash(to_hash(v)), network_id.clone(), ) }) @@ -455,7 +455,7 @@ pub fn map_certificate( conway::Certificate::PoolRetirement(pool_key_hash, epoch) => { Ok(TxCertificateWithPos { cert: TxCertificate::PoolRetirement(PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }), tx_identifier, @@ -494,7 +494,7 @@ pub fn map_certificate( Ok(TxCertificateWithPos { cert: TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), }), tx_identifier, @@ -507,7 +507,7 @@ pub fn map_certificate( cert: TxCertificate::StakeRegistrationAndDelegation( StakeRegistrationAndDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), deposit: *coin, }, ), @@ -533,7 +533,7 @@ pub fn map_certificate( cert: TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), deposit: *coin, }, diff --git a/common/src/address.rs b/common/src/address.rs index a5921a81..36afa1aa 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -398,7 +398,7 @@ impl StakeAddress { NetworkId::Testnet => bech32::Hrp::parse("stake_test")?, }; - let data = self.to_binary()?; + let data = self.to_binary(); Ok(bech32::encode::(hrp, &data.as_slice())?) } @@ -431,20 +431,20 @@ impl StakeAddress { } /// Convert to binary format (29 bytes) - pub fn to_binary(&self) -> Result> { + pub fn to_binary(&self) -> Vec { let network_bits = match self.network { NetworkId::Mainnet => 0b1u8, NetworkId::Testnet => 0b0u8, }; - let (stake_bits, stake_hash): (u8, &KeyHash) = match &self.credential { - StakeCredential::AddrKeyHash(data) => (0b1110, data), - StakeCredential::ScriptHash(data) => (0b1111, data), + let (stake_bits, stake_hash): (u8, &Vec) = match &self.credential { + StakeCredential::AddrKeyHash(data) => (0b1110, &data.to_vec()), + StakeCredential::ScriptHash(data) => (0b1111, &data.to_vec()), }; let mut data = vec![network_bits | (stake_bits << 4)]; - data.extend(stake_hash.as_ref()); - data.try_into().map_err(|_| anyhow!("Invalid hash size for stake address")) + data.extend(stake_hash); + data } /// Read from binary format (29 bytes) @@ -505,9 +505,7 @@ impl minicbor::Encode for StakeAddress { e: &mut minicbor::Encoder, _ctx: &mut C, ) -> Result<(), minicbor::encode::Error> { - let data = self - .to_binary() - .map_err(|_| minicbor::encode::Error::message("Failed to convert to binary"))?; + let data = self.to_binary(); e.bytes(&data.as_slice())?; Ok(()) } @@ -944,7 +942,7 @@ mod tests { #[test] fn stake_addresses_encode_mainnet_stake() { let address = mainnet_stake_address(); - let binary = address.to_binary().unwrap(); + let binary = address.to_binary(); // CBOR encoding wraps the raw 29-byte stake address in a byte string: // - 0x58: CBOR major type 2 (byte string) with 1-byte length follows @@ -965,7 +963,7 @@ mod tests { fn stake_addresses_decode_mainnet_stake() { let binary = { let mut v = vec![0x58, 0x1d]; - v.extend_from_slice(&mainnet_stake_address().to_binary().unwrap().as_slice()); + v.extend_from_slice(&mainnet_stake_address().to_binary().as_slice()); v }; diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index 51eb9b04..ac85acca 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -15,8 +15,8 @@ use super::streaming_snapshot::{ cbor, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, }; -use crate::{PoolId, VrfKeyHash}; use crate::types::AddrKeyhash; +use crate::{PoolId, VrfKeyHash}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PoolParams { diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index a1112b6e..455bcd02 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -195,15 +195,15 @@ mod tests { use super::*; use acropolis_common::stake_addresses::StakeAddressState; use acropolis_common::NetworkId::Mainnet; - use acropolis_common::{PoolId, StakeAddress, StakeCredential}; + use acropolis_common::{KeyHash, PoolId, StakeAddress, StakeCredential}; // Helper function to create stake addresses for testing fn create_test_stake_address(id: u8) -> StakeAddress { - let mut hash = vec![0u8; 28]; + let mut hash = [0u8; 28]; hash[0] = id; StakeAddress { network: Mainnet, - credential: StakeCredential::AddrKeyHash(hash), + credential: StakeCredential::AddrKeyHash(KeyHash::new(hash)), } } diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 8b4f61d8..fc054a26 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -993,14 +993,14 @@ impl State { #[cfg(test)] mod tests { use super::*; - use acropolis_common::crypto::keyhash_256; + use acropolis_common::crypto::{keyhash_224, keyhash_256}; use acropolis_common::{ protocol_params::ConwayParams, rational_number::RationalNumber, Anchor, Committee, Constitution, CostModel, DRepVotingThresholds, NetworkId, PoolVotingThresholds, Pot, PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAndVoteDelegation, StakeCredential, StakeRegistrationAndStakeAndVoteDelegation, StakeRegistrationAndVoteDelegation, TxCertificateWithPos, TxIdentifier, VoteDelegation, - Withdrawal, + VrfKeyHash, Withdrawal, }; // Helper to create a StakeAddress from a byte slice @@ -1392,10 +1392,7 @@ mod tests { // Get the KeyHash once let spo1_hash = spo1.get_hash(); - let drep_key_hash = test_keyhash_from_bytes(&DREP_HASH); - let drep_script_hash = test_keyhash_from_bytes(&DREP_HASH); - let pool_id_1 = PoolId::new(*spo1_hash); let certificates = vec![ @@ -1419,7 +1416,7 @@ mod tests { TxCertificateWithPos { cert: TxCertificate::VoteDelegation(VoteDelegation { stake_address: spo1.clone(), - drep: DRepChoice::Key(DREP_HASH.to_vec()), + drep: DRepChoice::Key(drep_key_hash), }), tx_identifier, cert_index: 0, @@ -1427,8 +1424,8 @@ mod tests { TxCertificateWithPos { cert: TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: spo2.clone(), - operator: spo1.get_hash().to_vec(), - drep: DRepChoice::Script(DREP_HASH.to_vec()), + operator: pool_id_1, + drep: DRepChoice::Script(drep_key_hash), }), tx_identifier, cert_index: 0, @@ -1448,7 +1445,7 @@ mod tests { cert: TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: spo4.clone(), - operator: spo1.get_hash().to_vec(), + operator: pool_id_1, drep: DRepChoice::NoConfidence, deposit: 1, }, diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index 0b9f82d0..8fe8dbc9 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -212,8 +212,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_delegations = self - .collect_partition::(&self.delegation_history, &account.get_hash())?; + let mut immutable_delegations = self.collect_partition::( + &self.delegation_history, + &account.get_hash().into_inner(), + )?; self.merge_pending( account, @@ -229,8 +231,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_mirs = - self.collect_partition::(&self.mir_history, &account.get_hash())?; + let mut immutable_mirs = self.collect_partition::( + &self.mir_history, + &account.get_hash().into_inner(), + )?; self.merge_pending(account, |e| e.mir_history.as_ref(), &mut immutable_mirs).await; @@ -326,7 +330,7 @@ impl ImmutableHistoricalAccountStore { fn make_epoch_key(account: &StakeAddress, epoch: u32) -> [u8; 32] { let mut key = [0u8; 32]; - key[..28].copy_from_slice(&account.get_credential().get_hash()); + key[..28].copy_from_slice(&account.get_credential().get_hash().into_inner()); key[28..32].copy_from_slice(&epoch.to_be_bytes()); key } diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index cbc302c3..e5d1c011 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -15,7 +15,6 @@ use acropolis_common::{ spdd::{SPDDStateQuery, SPDDStateQueryResponse}, utils::query_state, }, - serialization::Bech32WithHrp, NetworkId, PoolId, StakeAddress, StakeCredential, }; use anyhow::{anyhow, Result}; diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index f13dcda0..8c529f14 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -17,9 +17,7 @@ use acropolis_common::{ utils::query_state, }, rest_helper::ToCheckedF64, - serialization::Bech32WithHrp, - PoolRetirement, PoolUpdateAction, StakeCredential, TxIdentifier, - PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxHash, + PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxIdentifier, }; use anyhow::Result; use caryatid_sdk::Context; diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index e0f11883..8c31276f 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -7,7 +7,7 @@ use acropolis_common::{ rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolUpdateAction, Relay, TxHash, VrfKeyHash, Vote, + PoolEpochState, PoolUpdateAction, Relay, TxHash, Vote, VrfKeyHash, }; use anyhow::Result; use num_traits::ToPrimitive; diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index c6a43e50..2fda28e5 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -10,8 +10,8 @@ use acropolis_common::{ params::TECHNICAL_PARAMETER_POOL_RETIRE_MAX_EPOCH, queries::governance::VoteRecord, stake_addresses::StakeAddressMap, - BlockInfo, KeyHash, PoolMetadata, PoolRetirement, PoolUpdateEvent, Relay, - StakeAddress, TxCertificate, TxIdentifier, Voter, VotingProcedures, + BlockInfo, KeyHash, PoolId, PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, + Relay, StakeAddress, TxCertificate, TxHash, TxIdentifier, Voter, VotingProcedures, }; use anyhow::Result; use imbl::HashMap; @@ -671,7 +671,8 @@ mod tests { use acropolis_common::hash::Hash; use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, - PoolRetirement, Ratio, StakeAddress, TxCertificate, TxCertificateWithPos, TxIdentifier, VrfKeyHash + PoolRetirement, Ratio, StakeAddress, TxCertificate, TxCertificateWithPos, TxIdentifier, + VrfKeyHash, }; use tokio::sync::Mutex; @@ -868,7 +869,7 @@ mod tests { assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(pool_id); + let spo = state.spos.get(&pool_id); assert!(spo.is_some()); block.number = 1; @@ -908,7 +909,7 @@ mod tests { }); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(pool_id); + let spo = state.spos.get(&pool_id); assert!(spo.is_some()); history.lock().await.commit(block.number, state); @@ -1038,7 +1039,7 @@ mod tests { let mut state = State::new(&save_blocks_store_config()); let mut block = new_block(0); let mut msg = new_certs_msg(); - let spo_id = keyhash_224(&[1_u8]); + let spo_id = test_pool_id_from_bytes(&[1]); msg.certificates.push(TxCertificateWithPos { cert: TxCertificate::PoolRegistration(default_pool_registration(spo_id.clone(), None)), tx_identifier: TxIdentifier::default(), @@ -1047,11 +1048,9 @@ mod tests { let spo_id = test_pool_id_from_bytes(&[1]); msg.certificates.push(TxCertificateWithPos { - PoolRegistrationWithPos { - reg: default_pool_registration(spo_id, None), - tx_hash: TxHash::default(), - cert_index: 0, - }, + cert: TxCertificate::PoolRegistration(default_pool_registration(spo_id.clone(), None)), + tx_identifier: TxIdentifier::default(), + cert_index: 0, }); assert!(state.handle_tx_certs(&block, &msg).is_ok()); block = new_block(2); From 5a499529ace5ebe831ffc12400863c499064168d Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Tue, 28 Oct 2025 17:31:16 -0700 Subject: [PATCH 09/20] Refactor: Replace manual key hash conversions with type-safe utilities, update imports, and adjust serialization logic across modules for consistency. --- codec/src/map_parameters.rs | 18 +++++++-------- common/src/address.rs | 22 +++++++++---------- common/src/snapshot/pool_params.rs | 2 +- modules/accounts_state/src/snapshot.rs | 6 ++--- modules/accounts_state/src/state.rs | 15 +++++-------- .../src/immutable_historical_account_store.rs | 14 +++++++----- .../rest_blockfrost/src/handlers/epochs.rs | 1 - modules/rest_blockfrost/src/handlers/pools.rs | 4 +--- modules/rest_blockfrost/src/types.rs | 2 +- modules/spo_state/src/state.rs | 21 +++++++++--------- 10 files changed, 50 insertions(+), 55 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 23fdb50b..d7c0e594 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -327,7 +327,7 @@ pub fn map_certificate( }), alonzo::Certificate::PoolRetirement(pool_key_hash, epoch) => Ok(TxCertificateWithPos { cert: TxCertificate::PoolRetirement(PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }), tx_identifier, @@ -395,7 +395,7 @@ pub fn map_certificate( Ok(TxCertificateWithPos { cert: TxCertificate::StakeDelegation(StakeDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), }), tx_identifier, cert_index: cert_index.try_into().unwrap(), @@ -415,8 +415,8 @@ pub fn map_certificate( pool_metadata, } => Ok(TxCertificateWithPos { cert: TxCertificate::PoolRegistration(PoolRegistration { - operator: operator.to_vec(), - vrf_key_hash: vrf_keyhash.to_vec(), + operator: to_pool_id(operator), + vrf_key_hash: to_vrf_key(vrf_keyhash), pledge: *pledge, cost: *cost, margin: Ratio { @@ -435,7 +435,7 @@ pub fn map_certificate( .into_iter() .map(|v| { StakeAddress::new( - StakeCredential::AddrKeyHash(v.to_vec()), + StakeCredential::AddrKeyHash(to_hash(v)), network_id.clone(), ) }) @@ -455,7 +455,7 @@ pub fn map_certificate( conway::Certificate::PoolRetirement(pool_key_hash, epoch) => { Ok(TxCertificateWithPos { cert: TxCertificate::PoolRetirement(PoolRetirement { - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), epoch: *epoch, }), tx_identifier, @@ -494,7 +494,7 @@ pub fn map_certificate( Ok(TxCertificateWithPos { cert: TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), }), tx_identifier, @@ -507,7 +507,7 @@ pub fn map_certificate( cert: TxCertificate::StakeRegistrationAndDelegation( StakeRegistrationAndDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), deposit: *coin, }, ), @@ -533,7 +533,7 @@ pub fn map_certificate( cert: TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: map_stake_address(cred, network_id), - operator: pool_key_hash.to_vec(), + operator: to_pool_id(pool_key_hash), drep: map_drep(drep), deposit: *coin, }, diff --git a/common/src/address.rs b/common/src/address.rs index a5921a81..36afa1aa 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -398,7 +398,7 @@ impl StakeAddress { NetworkId::Testnet => bech32::Hrp::parse("stake_test")?, }; - let data = self.to_binary()?; + let data = self.to_binary(); Ok(bech32::encode::(hrp, &data.as_slice())?) } @@ -431,20 +431,20 @@ impl StakeAddress { } /// Convert to binary format (29 bytes) - pub fn to_binary(&self) -> Result> { + pub fn to_binary(&self) -> Vec { let network_bits = match self.network { NetworkId::Mainnet => 0b1u8, NetworkId::Testnet => 0b0u8, }; - let (stake_bits, stake_hash): (u8, &KeyHash) = match &self.credential { - StakeCredential::AddrKeyHash(data) => (0b1110, data), - StakeCredential::ScriptHash(data) => (0b1111, data), + let (stake_bits, stake_hash): (u8, &Vec) = match &self.credential { + StakeCredential::AddrKeyHash(data) => (0b1110, &data.to_vec()), + StakeCredential::ScriptHash(data) => (0b1111, &data.to_vec()), }; let mut data = vec![network_bits | (stake_bits << 4)]; - data.extend(stake_hash.as_ref()); - data.try_into().map_err(|_| anyhow!("Invalid hash size for stake address")) + data.extend(stake_hash); + data } /// Read from binary format (29 bytes) @@ -505,9 +505,7 @@ impl minicbor::Encode for StakeAddress { e: &mut minicbor::Encoder, _ctx: &mut C, ) -> Result<(), minicbor::encode::Error> { - let data = self - .to_binary() - .map_err(|_| minicbor::encode::Error::message("Failed to convert to binary"))?; + let data = self.to_binary(); e.bytes(&data.as_slice())?; Ok(()) } @@ -944,7 +942,7 @@ mod tests { #[test] fn stake_addresses_encode_mainnet_stake() { let address = mainnet_stake_address(); - let binary = address.to_binary().unwrap(); + let binary = address.to_binary(); // CBOR encoding wraps the raw 29-byte stake address in a byte string: // - 0x58: CBOR major type 2 (byte string) with 1-byte length follows @@ -965,7 +963,7 @@ mod tests { fn stake_addresses_decode_mainnet_stake() { let binary = { let mut v = vec![0x58, 0x1d]; - v.extend_from_slice(&mainnet_stake_address().to_binary().unwrap().as_slice()); + v.extend_from_slice(&mainnet_stake_address().to_binary().as_slice()); v }; diff --git a/common/src/snapshot/pool_params.rs b/common/src/snapshot/pool_params.rs index 51eb9b04..ac85acca 100644 --- a/common/src/snapshot/pool_params.rs +++ b/common/src/snapshot/pool_params.rs @@ -15,8 +15,8 @@ use super::streaming_snapshot::{ cbor, Coin, Nullable, PoolMetadata, Relay, RewardAccount, Set, UnitInterval, }; -use crate::{PoolId, VrfKeyHash}; use crate::types::AddrKeyhash; +use crate::{PoolId, VrfKeyHash}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PoolParams { diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index a1112b6e..455bcd02 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -195,15 +195,15 @@ mod tests { use super::*; use acropolis_common::stake_addresses::StakeAddressState; use acropolis_common::NetworkId::Mainnet; - use acropolis_common::{PoolId, StakeAddress, StakeCredential}; + use acropolis_common::{KeyHash, PoolId, StakeAddress, StakeCredential}; // Helper function to create stake addresses for testing fn create_test_stake_address(id: u8) -> StakeAddress { - let mut hash = vec![0u8; 28]; + let mut hash = [0u8; 28]; hash[0] = id; StakeAddress { network: Mainnet, - credential: StakeCredential::AddrKeyHash(hash), + credential: StakeCredential::AddrKeyHash(KeyHash::new(hash)), } } diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index 8b4f61d8..fc054a26 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -993,14 +993,14 @@ impl State { #[cfg(test)] mod tests { use super::*; - use acropolis_common::crypto::keyhash_256; + use acropolis_common::crypto::{keyhash_224, keyhash_256}; use acropolis_common::{ protocol_params::ConwayParams, rational_number::RationalNumber, Anchor, Committee, Constitution, CostModel, DRepVotingThresholds, NetworkId, PoolVotingThresholds, Pot, PotDelta, Ratio, Registration, StakeAddress, StakeAddressDelta, StakeAndVoteDelegation, StakeCredential, StakeRegistrationAndStakeAndVoteDelegation, StakeRegistrationAndVoteDelegation, TxCertificateWithPos, TxIdentifier, VoteDelegation, - Withdrawal, + VrfKeyHash, Withdrawal, }; // Helper to create a StakeAddress from a byte slice @@ -1392,10 +1392,7 @@ mod tests { // Get the KeyHash once let spo1_hash = spo1.get_hash(); - let drep_key_hash = test_keyhash_from_bytes(&DREP_HASH); - let drep_script_hash = test_keyhash_from_bytes(&DREP_HASH); - let pool_id_1 = PoolId::new(*spo1_hash); let certificates = vec![ @@ -1419,7 +1416,7 @@ mod tests { TxCertificateWithPos { cert: TxCertificate::VoteDelegation(VoteDelegation { stake_address: spo1.clone(), - drep: DRepChoice::Key(DREP_HASH.to_vec()), + drep: DRepChoice::Key(drep_key_hash), }), tx_identifier, cert_index: 0, @@ -1427,8 +1424,8 @@ mod tests { TxCertificateWithPos { cert: TxCertificate::StakeAndVoteDelegation(StakeAndVoteDelegation { stake_address: spo2.clone(), - operator: spo1.get_hash().to_vec(), - drep: DRepChoice::Script(DREP_HASH.to_vec()), + operator: pool_id_1, + drep: DRepChoice::Script(drep_key_hash), }), tx_identifier, cert_index: 0, @@ -1448,7 +1445,7 @@ mod tests { cert: TxCertificate::StakeRegistrationAndStakeAndVoteDelegation( StakeRegistrationAndStakeAndVoteDelegation { stake_address: spo4.clone(), - operator: spo1.get_hash().to_vec(), + operator: pool_id_1, drep: DRepChoice::NoConfidence, deposit: 1, }, diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index 0b9f82d0..8fe8dbc9 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -212,8 +212,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_delegations = self - .collect_partition::(&self.delegation_history, &account.get_hash())?; + let mut immutable_delegations = self.collect_partition::( + &self.delegation_history, + &account.get_hash().into_inner(), + )?; self.merge_pending( account, @@ -229,8 +231,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_mirs = - self.collect_partition::(&self.mir_history, &account.get_hash())?; + let mut immutable_mirs = self.collect_partition::( + &self.mir_history, + &account.get_hash().into_inner(), + )?; self.merge_pending(account, |e| e.mir_history.as_ref(), &mut immutable_mirs).await; @@ -326,7 +330,7 @@ impl ImmutableHistoricalAccountStore { fn make_epoch_key(account: &StakeAddress, epoch: u32) -> [u8; 32] { let mut key = [0u8; 32]; - key[..28].copy_from_slice(&account.get_credential().get_hash()); + key[..28].copy_from_slice(&account.get_credential().get_hash().into_inner()); key[28..32].copy_from_slice(&epoch.to_be_bytes()); key } diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index cbc302c3..e5d1c011 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -15,7 +15,6 @@ use acropolis_common::{ spdd::{SPDDStateQuery, SPDDStateQueryResponse}, utils::query_state, }, - serialization::Bech32WithHrp, NetworkId, PoolId, StakeAddress, StakeCredential, }; use anyhow::{anyhow, Result}; diff --git a/modules/rest_blockfrost/src/handlers/pools.rs b/modules/rest_blockfrost/src/handlers/pools.rs index f13dcda0..8c529f14 100644 --- a/modules/rest_blockfrost/src/handlers/pools.rs +++ b/modules/rest_blockfrost/src/handlers/pools.rs @@ -17,9 +17,7 @@ use acropolis_common::{ utils::query_state, }, rest_helper::ToCheckedF64, - serialization::Bech32WithHrp, - PoolRetirement, PoolUpdateAction, StakeCredential, TxIdentifier, - PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxHash, + PoolId, PoolRetirement, PoolUpdateAction, StakeCredential, TxIdentifier, }; use anyhow::Result; use caryatid_sdk::Context; diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index e0f11883..8c31276f 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -7,7 +7,7 @@ use acropolis_common::{ rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolUpdateAction, Relay, TxHash, VrfKeyHash, Vote, + PoolEpochState, PoolUpdateAction, Relay, TxHash, Vote, VrfKeyHash, }; use anyhow::Result; use num_traits::ToPrimitive; diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index c6a43e50..2fda28e5 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -10,8 +10,8 @@ use acropolis_common::{ params::TECHNICAL_PARAMETER_POOL_RETIRE_MAX_EPOCH, queries::governance::VoteRecord, stake_addresses::StakeAddressMap, - BlockInfo, KeyHash, PoolMetadata, PoolRetirement, PoolUpdateEvent, Relay, - StakeAddress, TxCertificate, TxIdentifier, Voter, VotingProcedures, + BlockInfo, KeyHash, PoolId, PoolMetadata, PoolRegistration, PoolRetirement, PoolUpdateEvent, + Relay, StakeAddress, TxCertificate, TxHash, TxIdentifier, Voter, VotingProcedures, }; use anyhow::Result; use imbl::HashMap; @@ -671,7 +671,8 @@ mod tests { use acropolis_common::hash::Hash; use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, - PoolRetirement, Ratio, StakeAddress, TxCertificate, TxCertificateWithPos, TxIdentifier, VrfKeyHash + PoolRetirement, Ratio, StakeAddress, TxCertificate, TxCertificateWithPos, TxIdentifier, + VrfKeyHash, }; use tokio::sync::Mutex; @@ -868,7 +869,7 @@ mod tests { assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(pool_id); + let spo = state.spos.get(&pool_id); assert!(spo.is_some()); block.number = 1; @@ -908,7 +909,7 @@ mod tests { }); assert!(state.handle_tx_certs(&block, &msg).is_ok()); assert_eq!(1, state.spos.len()); - let spo = state.spos.get(pool_id); + let spo = state.spos.get(&pool_id); assert!(spo.is_some()); history.lock().await.commit(block.number, state); @@ -1038,7 +1039,7 @@ mod tests { let mut state = State::new(&save_blocks_store_config()); let mut block = new_block(0); let mut msg = new_certs_msg(); - let spo_id = keyhash_224(&[1_u8]); + let spo_id = test_pool_id_from_bytes(&[1]); msg.certificates.push(TxCertificateWithPos { cert: TxCertificate::PoolRegistration(default_pool_registration(spo_id.clone(), None)), tx_identifier: TxIdentifier::default(), @@ -1047,11 +1048,9 @@ mod tests { let spo_id = test_pool_id_from_bytes(&[1]); msg.certificates.push(TxCertificateWithPos { - PoolRegistrationWithPos { - reg: default_pool_registration(spo_id, None), - tx_hash: TxHash::default(), - cert_index: 0, - }, + cert: TxCertificate::PoolRegistration(default_pool_registration(spo_id.clone(), None)), + tx_identifier: TxIdentifier::default(), + cert_index: 0, }); assert!(state.handle_tx_certs(&block, &msg).is_ok()); block = new_block(2); From 6d0ad838151ad8ad939a87486c2cc3ed5748a792 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 29 Oct 2025 09:34:49 -0700 Subject: [PATCH 10/20] Refactor: Consolidate `declare_hash_type_with_bech32!` macros, remove redundant `declare_hash_newtype_with_bech32!`, and update associated imports and Bech32 serialization logic. --- common/src/hash.rs | 68 +------------------ common/src/types.rs | 9 ++- .../rest_blockfrost/src/handlers/accounts.rs | 8 ++- 3 files changed, 11 insertions(+), 74 deletions(-) diff --git a/common/src/hash.rs b/common/src/hash.rs index 0d104993..31db490f 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -282,73 +282,9 @@ macro_rules! declare_hash_type { }; } -/// Declares a type alias for a hash with Bech32 encoding support. -/// -/// This macro creates a type alias and implements the `Bech32Conversion` trait -/// for encoding/decoding the hash using a specified human-readable part (HRP). -/// -/// **WARNING**: You can only use this macro once per hash size, as it implements -/// a trait on `Hash`. If you need multiple distinct types with different -/// Bech32 HRPs for the same hash size, use `declare_hash_newtype_with_bech32!` instead. -/// -/// # Examples -/// -/// ```ignore -/// declare_hash_type_with_bech32!(VRFKey, 32, "vrf_vk"); -/// -/// let key: VRFKey = // ... get key -/// let bech32_string = key.to_bech32().unwrap(); -/// let decoded = VRFKey::from_bech32(&bech32_string).unwrap(); -/// ``` -#[macro_export] -macro_rules! declare_hash_type_with_bech32 { - ($name:ident, $size:expr, $hrp:expr) => { - declare_hash_type!($name, $size); - - impl crate::serialization::Bech32Conversion for $name { - fn to_bech32(&self) -> Result { - use crate::serialization::Bech32WithHrp; - self.to_vec().to_bech32_with_hrp($hrp) - } - - fn from_bech32(s: &str) -> Result { - use crate::serialization::Bech32WithHrp; - let v = Vec::::from_bech32_with_hrp(s, $hrp)?; - Self::try_from(v).map_err(|_| { - anyhow::Error::msg(format!( - "Bad vector input to {}", - stringify!($name) - )) - }) - } - } - }; - ($(#[$meta:meta])* $name:ident, $size:expr, $hrp:expr) => { - declare_hash_type!($(#[$meta])* $name, $size); - - impl crate::serialization::Bech32Conversion for $name { - fn to_bech32(&self) -> Result { - use crate::serialization::Bech32WithHrp; - self.to_vec().to_bech32_with_hrp($hrp) - } - - fn from_bech32(s: &str) -> Result { - use crate::serialization::Bech32WithHrp; - let v = Vec::::from_bech32_with_hrp(s, $hrp)?; - Self::try_from(v).map_err(|_| { - anyhow::Error::msg(format!( - "Bad vector input to {}", - stringify!($name) - )) - }) - } - } - }; -} - /// Declares a newtype wrapper around Hash with Bech32 encoding support. /// -/// Unlike `declare_hash_type_with_bech32!`, this creates a distinct type (not an alias), +/// This creates a distinct type (not an alias), /// allowing you to have multiple types of the same hash size with different Bech32 HRPs. /// /// # Examples @@ -359,7 +295,7 @@ macro_rules! declare_hash_type_with_bech32 { /// declare_hash_newtype_with_bech32!(DrepId, 28, "drep"); /// ``` #[macro_export] -macro_rules! declare_hash_newtype_with_bech32 { +macro_rules! declare_hash_type_with_bech32 { ($name:ident, $size:expr, $hrp:expr) => { #[doc = concat!(stringify!($name), " - a ", stringify!($size), "-byte hash.")] #[derive( diff --git a/common/src/types.rs b/common/src/types.rs index 5974e496..9e1aa8b5 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -5,8 +5,7 @@ use crate::hash::Hash; use crate::{ address::{Address, ShelleyAddress, StakeAddress}, - declare_hash_newtype_with_bech32, declare_hash_type, declare_hash_type_with_bech32, - protocol_params, + declare_hash_type, declare_hash_type_with_bech32, protocol_params, rational_number::RationalNumber, }; use anyhow::{anyhow, bail, Error, Result}; @@ -445,9 +444,9 @@ pub type GenesisKeyhash = Vec; declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); -declare_hash_newtype_with_bech32!(VrfKeyHash, 32, "vrf_vk"); -declare_hash_newtype_with_bech32!(PoolId, 28, "pool"); -declare_hash_newtype_with_bech32!(DrepKey, 28, "drep"); +declare_hash_type_with_bech32!(VrfKeyHash, 32, "vrf_vk"); +declare_hash_type_with_bech32!(PoolId, 28, "pool"); +declare_hash_type_with_bech32!(DrepKey, 28, "drep"); declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); /// Data hash used for metadata, anchors (SHA256) diff --git a/modules/rest_blockfrost/src/handlers/accounts.rs b/modules/rest_blockfrost/src/handlers/accounts.rs index 80b2fce4..47750ab9 100644 --- a/modules/rest_blockfrost/src/handlers/accounts.rs +++ b/modules/rest_blockfrost/src/handlers/accounts.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use acropolis_common::messages::{Message, RESTResponse, StateQuery, StateQueryResponse}; use acropolis_common::queries::accounts::{AccountsStateQuery, AccountsStateQueryResponse}; use acropolis_common::queries::utils::query_state; -use acropolis_common::serialization::Bech32Conversion; +use acropolis_common::serialization::{Bech32Conversion, Bech32WithHrp}; use acropolis_common::{DRepChoice, StakeAddress}; use anyhow::{anyhow, Result}; use caryatid_sdk::Context; @@ -128,7 +128,8 @@ fn map_drep_choice(drep: &DRepChoice) -> Result { match drep { DRepChoice::Key(hash) => { let val = hash - .to_bech32() + .to_vec() + .to_bech32_with_hrp("drep") .map_err(|e| anyhow!("Bech32 encoding failed for DRep Key: {e}"))?; Ok(DRepChoiceRest { drep_type: "Key".to_string(), @@ -137,7 +138,8 @@ fn map_drep_choice(drep: &DRepChoice) -> Result { } DRepChoice::Script(hash) => { let val = hash - .to_bech32() + .to_vec() + .to_bech32_with_hrp("drep_script") .map_err(|e| anyhow!("Bech32 encoding failed for DRep Script: {e}"))?; Ok(DRepChoiceRest { drep_type: "Script".to_string(), From 28cbe9dea2200581d4d521b7497514e4b98d8cd9 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 29 Oct 2025 10:26:47 -0700 Subject: [PATCH 11/20] Refactor: Format imports for readability, add `#[ignore]` to `test_voting_mainnet_up_573`, and update `conway_verification.csv` with new governance actions. --- .../data/conway_verification.csv | 46 +++++++++---------- modules/governance_state/src/conway_voting.rs | 7 ++- .../src/conway_voting_test.rs | 5 +- modules/governance_state/src/state.rs | 4 +- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/modules/governance_state/data/conway_verification.csv b/modules/governance_state/data/conway_verification.csv index 2c40e6bd..dfbd639e 100644 --- a/modules/governance_state/data/conway_verification.csv +++ b/modules/governance_state/data/conway_verification.csv @@ -1,23 +1,23 @@ -gov_action1zhuz5djmmmjg8f9s8pe6grfc98xg3szglums8cgm6qwancp4eytqqmpu0pr,15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916,0,,100000000000,45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7,507,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7""}},""gov_action_id"":{""transaction_id"":""15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmWjcHsrq9kKHZZ7aPPFjqN6wLuxH9d8bcqssmrE7H4cvb"",""data_hash"":""2f98f57c4149fdfed2b73cbd821226fe417ef5ed49d8f836a37b31edf14dea47""}}",,,,,Some(514),cy2/n0/a1:dy8971134676473/n220807337570898/a28653074063371:sy156770300966308/n1482461784403994/a27102517904169,c0:d1:s1 -gov_action1t87n2vjnavthuggyarerafxx8c7n9mu4c7r96qlfp5uggsjdc8dsqymg588,59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db,0,,100000000000,2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23,510,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23""}},""gov_action_id"":{""transaction_id"":""59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://c-ipfs-gw.nmkr.io/ipfs/QmXdfDSSkR8TYBntMT4nuTL9sE9E44FJnpWVpaY8ZTfwjj"",""data_hash"":""d4efa9e0c3d80f5be35def08551eaf5aef17eae832fdb835e5f4b208d98f3dff""}}",,,,,Some(517),cy3/n0/a3:dy239372032038196/n2028935641783/a8814655430284:sy875771108730453/n2218103279783/a81439064616232,c0:d1:s1 -gov_action10lty9xka3unprtvdfrqvcjgsz33sjwhv9p06afqzar8au782trtsq7dhd95,7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7,0,,100000000000,7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48,514,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48""}},""gov_action_id"":{""transaction_id"":""7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/bigpey/CardanoGovernance/refs/heads/main/infoAction3.jsonld"",""data_hash"":""e68cba056c70187e475f05317ce54eeade3376d5b744b32f2c60492b4984b4bf""}}",,,,,Some(521),cy0/n3/a2:dy144561249982546/n310448207627996/a104407616914975:sy544996208583580/n1043351751274733/a95232889230901,c0:d1:s1 -gov_action1286ft23r7jem825s4l0y5rn8sgam0tz2ce04l7a38qmnhp3l9a6qqn850dw,51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,518,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-21-ppu/metadata.jsonld"",""data_hash"":""3e6b1083a637a740d5b84bb6edf1a5119b81440b31ea84907311b6543ebd39eb""}}",,,,,Some(525),cy0/n5/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 -gov_action1k2jertppnnndejjcglszfqq4yzw8evzrd2nt66rr6rqlz54xp0zsq05ecsn,b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,519,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1,100181,726,719,0,1,100181,726,719,0,1,100181,726,719,0,1,107878,680,0,1,95336,1,281145,18848,0,1,180194,159,1,1,158519,8942,0,1,159378,8813,0,1,107490,3298,1,106057,655,1,1964219,24520,3]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-04-ppu/metadata.jsonld"",""data_hash"":""94deb036c455e4064f7ed4162edbdb7d892ad264094df9a26fd61b5b130d100f""}}",,Some(525),Some(526),,,cy5/n0/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 -gov_action1llcd7ezdx299xeep9azm4dvsvz7783qfrhykcu3sv2ykl4sewv2qq4myfpk,fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,522,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-19-infohf/metadata.jsonld"",""data_hash"":""93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e""}}",,,,,Some(529),cy6/n0/a1:dy1662309604816396/n3240479257792/a104183585725135:sy1628124195597550/n0/a0,c0:d1:s1 -gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525,0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,529,,HardForkInitiation,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9"",""action_index"":0},""gov_action"":{""HardForkInitiation"":{""previous_action_id"":null,""protocol_version"":{""major"":10,""minor"":0}}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-30-hf10/metadata.jsonld"",""data_hash"":""8a1bd37caa6b914a8b569adb63a0f41d8f159c110dc5c8409118a3f087fffb43""}}",,Some(536),Some(537),,,cy7/n0/a0:dy0/n0/a0:sy14409193713024022/n62248540964906/a917440954183897,c2/3:d3/5:s51/100 -gov_action133jnaewfsq8x6v08ndd87l2yqryp63r30t2dkceacxx5cply5n7sqzlcyqf,8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,537,,NewConstitution,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"",""action_index"":0},""gov_action"":{""NewConstitution"":{""previous_action_id"":null,""new_constitution"":{""anchor"":{""url"":""ipfs://bafkreiazhhawe7sjwuthcfgl3mmv2swec7sukvclu3oli7qdyz4uhhuvmy"",""data_hash"":""2a61e2f4b63442978140c77a70daab3961b22b12b63b13949a390c097214d1c5""},""guardrail_script"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}}},""anchor"":{""url"":""ipfs://bafkreiehcekhhsq34ccezwn46brg3euj6tbs4g4yjkav34ukqvbnzaya2a"",""data_hash"":""d085e5af96521ae2670400e76c3a1e4b4eb902139ddaa83bde7580e7e9d7ddec""}}",,Some(541),Some(542),,,cy7/n0/a0:dy3147155733843689/n80277670032839/a173769211483602:sy0/n0/a0,c2/3:d3/4:s0 -gov_action1js2s9v92zpxg2rge0y3jt9zy626he2m67x9kx9phw4r942kvsn6sqfym0d7,941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5,0,"transaction: b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5, action_index: 0",100000000000,646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59,539,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59""}},""gov_action_id"":{""transaction_id"":""941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""protocol_param_update"":{""treasury_growth_rate"":[1,10]},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://QmcKQggcpouuhAAvUYGDzoKgMwbZSkWqiEeE6c67SJ3kEq"",""data_hash"":""9b2438f0032a0c24ed62d12d6bdb79b47e2bd0c4d2dd4f4936c055ead7109caf""}}",,,,,Some(546),cy2/n5/a0:dy939990053651256/n1965627054695765/a284188967365253:sy0/n0/a0,c2/3:d67/100:s0 -gov_action12meeq4r43udremwpm6fzt4nt7fctvt0ah7798x036m2r4nhlccmqqhmr9wx,56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,542,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiada4nn5eaezg43esieduks6l57vzkjdo2yfby7yxv6jrat7ilrdq"",""data_hash"":""b160033b47dfc31885c297c55ba6b68afaf7561da3070eced93d84ad70d8f5b3""}}",,,,,Some(549),cy3/n1/a3:dy2849267784746103/n47404553333753/a58248658178512:sy646730366107541/n0/a2618952257730,c0:d1:s1 -gov_action10ueqgzwenxr39le68n0se9peu92r7gm2846xwehh3u0ahc0qd0uqqyljxu5,7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8,0,,100000000000,34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f,546,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f""}},""gov_action_id"":{""transaction_id"":""7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/blockchainada/ga/refs/heads/main/ga01.jsonld"",""data_hash"":""a2fa375274a2c5efa985a1e9811f27ea1ebf8b8dd88cdf9931a5aa856c73832a""}}",,,,,Some(553),cy1/n4/a1:dy1780269838508229/n1626018423362940/a96196729276630:sy566347694726570/n603581674443045/a879726334116,c0:d1:s1 -gov_action1nd3t833j7v5sz65k3tp9yyvztw60sjcjgcgjr37682s3m7frwrusqmd2k80,9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,547,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiaqno22swabd3kcqt2awtgwaucdzaagacoemxwadm3exrchhnfite"",""data_hash"":""973452e7c4d204c883c6a9e4c311f72ad6237e827ce05e141f3374c8a04f01bc""}}",,,,,Some(554),cy5/n1/a1:dy3555798499117719/n927833581144205/a266084892066727:sy622342555916988/n942621542016625/a10607703917013,c0:d1:s1 -gov_action10k0unljvaej0kd89w7pn0zkgdx59c7xkl0x5q78dzvdtd73u0kmqq5xl5y5,7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,554,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmRrGsZsP5R7cFYFzPXQ9vS2Ux7oTXb1ep1EciLdKqeDWY"",""data_hash"":""30f03001e623d61ae782efe922b21ef79c4a1d06b258fd773d9c762d1a42d9b9""}}",,,,,Some(561),cy6/n0/a1:dy2425490955933534/n2297474620022945/a64913595414068:sy672666725152325/n24241821569730/a888586571923,c0:d1:s1 -gov_action1h4ygjv0hjfj3lmafcm76rpdzcm8vsvj9k5wejn3npyxwxm3fesnqqw9kxxz,bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibqma7t2k4rcywvx5afukahhi3dp2so2ugh7t4ljuawhanvk7sr34"",""data_hash"":""7d2f344f3651a8372ad603abf11fcb310fb3c5154a6592591d1ff97d951156e3""}}",,,,,Some(563),cy6/n0/a1:dy4500048611264804/n31848673410621/a45099889469182:sy569746862334739/n0/a0,c0:d1:s1 -gov_action1vdlrcftd48qn2zz8egepr6xyfcmxpfz8r69k769gc5mhg662adesq9yy8pl,637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73,0,,100000000000,29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122""}},""gov_action_id"":{""transaction_id"":""637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://ipfs.io/ipfs/bafkreieu47jw2qoxmqz67qyhhj4pi7fssuth5s4mm42qleqtw5tuzs3pgu"",""data_hash"":""ec7179c11582daa390e6d0c3f3cc46b0116d96aadcc74e02aa8d8e91434ab7af""}}",,,,,Some(563),cy6/n0/a1:dy2063455667008172/n1632235923043398/a145991747762932:sy130291633488926/n257125277926045/a71298578525921,c0:d1:s1 -gov_action1fpqwxp2kxvnntr8hpkh9q9djm78ccdww7qlhg5safugh4stmcwzqql5lauu,4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384,0,,100000000000,3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364""}},""gov_action_id"":{""transaction_id"":""4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/theeldermillenial/2025-liquidity-budget/df0b26d8796b19b566008ea9eaa8f17fef2cb6d4/info.jsonld"",""data_hash"":""97df3a30b767ee5b8e2b9fde824d91d3366985243ed73c06b257c2163f9045db""}}",,,,,Some(563),cy0/n4/a1:dy212465307551433/n2228913162217302/a438473698221786:sy0/n33370675402718/a24221567758519,c0:d1:s1 -gov_action1mmalzkcxpyn33t05hml2hxpwq0ffv6uu4mhe8sv7guz5nmm4afysqlmepzl,defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmaWrgqcQS7jYyLYFpvBiamZ4mCoeasL78qaPASDaJ6dT3"",""data_hash"":""4a4c99645a68d29eab6615ac71191cc92c745f92f97cdaf47890be1bad7487a7""}}",,,,,Some(563),cy0/n7/a0:dy1814353580889176/n1176878238974779/a461607195493589:sy211863729905114/n128435026893983/a800795601962,c0:d1:s1 -gov_action1u9x73kwufaxa70lfy59g4ynwyrcsaxdcd0gxzzmh67s9fxq4j8hqqk2phgh,e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee,0,,100000000000,bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d,557,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d""}},""gov_action_id"":{""transaction_id"":""e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibeajhkes7bxjlkghkingcgltqcwazz2ya5oknveqwt5nont7tg6u"",""data_hash"":""b95d8f8e324e9863905f16dbad94c1f25b28b933ae842e6f8ce9841c8da5b197""}}",,,,,Some(564),cy6/n0/a1:dy3568747822222928/n732747387805908/a143704110191164:sy606977531362334/n42674324713788/a1734640589499,c0:d1:s1 -gov_action1vrkk4dpuss8l3z9g4uc2rmf8ks0f7j534zvz9v4k85dlc54wa3zsqq68rx0,60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,566,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,228,37,152,78,36,251,44,6,173,103,104,130,23,141,222,230,228,123,153,74,88,154,227,215,12,129,124,121],300000000000],[[241,155,234,230,252,127,234,218,108,207,130,69,84,181,227,164,152,234,177,82,5,172,146,72,195,251,153,59,95],300000000000],[[241,167,150,104,120,85,12,225,30,200,168,59,147,252,26,110,16,93,84,79,120,73,68,1,6,108,79,224,207],300000000000],[[241,135,127,87,224,189,204,129,103,233,132,222,224,82,216,221,115,70,239,252,8,255,128,162,155,4,94,26,16],500000000000],[[241,134,14,224,246,189,130,53,132,42,144,138,253,134,220,148,156,76,157,171,215,75,9,101,195,100,184,211,21],100000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreifw3qs7brjn4tdvyprnh2r343oerbdghasp5ws6ro55frbpll3dta"",""data_hash"":""d2f633b044f33117ace7cde8c045fcc930060a6dbdd083f7491148a86a3c5ebd""}}",,Some(570),Some(571),,,cy7/n0/a0:dy4093833588084653/n21189101483536/a52442655453280:sy0/n0/a0,c2/3:d67/100:s0 -gov_action1n5sn54mgf47a7men2ryq6ppx88kta4wvenz2qkl4f9v6ppje8easqxwm88m,9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b,0,,100000000000,2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0,567,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0""}},""gov_action_id"":{""transaction_id"":""9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmP9iDuML2VmoFigTJifBj87LxZ3DNnREyU27DE1MrpZDg"",""data_hash"":""b3dc422b419a0e7beee4bf594bcfd344d87e2dc593d0fef5eb1fd218c0a6137b""}}",,,,,Some(574),cy7/n0/a0:dy2832862312472265/n935246197584261/a674152156041788:sy66736422727105/n66272824647159/a0,c0:d1:s1 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlpwywvhcq,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,23,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":23},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],69459000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreid2pq5icpp77nfvdvnb5ipy3fqs77tpnls4ngxy6semzkdq7d2z7y"",""data_hash"":""5edb23193df820ab4e8334d2e12fdc57aac5f06fe9a81067aa651b3439b57119""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3926392145162793/n75355236808630/a62411838251542:sy0/n0/a0,c2/3:d67/100:s0 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqz6d98zp,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,1,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":1},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],96817080000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreigt5xy56qjxd7dl2s7u6jxec2cfxevynppvgnnjifc2wawr7md5ha"",""data_hash"":""442b57ebf94db21544475a5dbdfe57f50e648646533d31bfa329c280aebfcfe9""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3912321432502202/n23692002076694/a312701730992913:sy0/n0/a0,c2/3:d67/100:s0 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqqfgyy3v,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,0,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],2162096000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreidjnukg5c7u5zlkxaciy4hkxfixvtquhx6uzlqpydvrxormfqpdm4"",""data_hash"":""6611ea5602de95d463ecf28f1c4ca26ad91fe7ed499d0a1594e3c2fd528a2a62""}}",,Some(574),Some(575),,,cy5/n0/a0:dy4127174354090953/n94145593104288/a0:sy0/n0/a0,c2/3:d67/100:s0 +gov_action1zhuz5djmmmjg8f9s8pe6grfc98xg3szglums8cgm6qwancp4eytqqmpu0pr,15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916,0,,100000000000,45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7,507,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7""}},""gov_action_id"":{""transaction_id"":""15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmWjcHsrq9kKHZZ7aPPFjqN6wLuxH9d8bcqssmrE7H4cvb"",""data_hash"":""2f98f57c4149fdfed2b73cbd821226fe417ef5ed49d8f836a37b31edf14dea47""}}",,,,,Some(514),cy2/n0/a1:dy8971134676473/n220807337570898/a28653074063371:sy156770300966308/n1482461784403994/a27102517904169,c0:d1:s1 +gov_action1t87n2vjnavthuggyarerafxx8c7n9mu4c7r96qlfp5uggsjdc8dsqymg588,59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db,0,,100000000000,2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23,510,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23""}},""gov_action_id"":{""transaction_id"":""59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://c-ipfs-gw.nmkr.io/ipfs/QmXdfDSSkR8TYBntMT4nuTL9sE9E44FJnpWVpaY8ZTfwjj"",""data_hash"":""d4efa9e0c3d80f5be35def08551eaf5aef17eae832fdb835e5f4b208d98f3dff""}}",,,,,Some(517),cy3/n0/a3:dy239372032038196/n2028935641783/a8814655430284:sy875771108730453/n2218103279783/a81439064616232,c0:d1:s1 +gov_action10lty9xka3unprtvdfrqvcjgsz33sjwhv9p06afqzar8au782trtsq7dhd95,7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7,0,,100000000000,7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48,514,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48""}},""gov_action_id"":{""transaction_id"":""7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/bigpey/CardanoGovernance/refs/heads/main/infoAction3.jsonld"",""data_hash"":""e68cba056c70187e475f05317ce54eeade3376d5b744b32f2c60492b4984b4bf""}}",,,,,Some(521),cy0/n3/a2:dy144561249982546/n310448207627996/a104407616914975:sy544996208583580/n1043351751274733/a95232889230901,c0:d1:s1 +gov_action1286ft23r7jem825s4l0y5rn8sgam0tz2ce04l7a38qmnhp3l9a6qqn850dw,51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,518,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-21-ppu/metadata.jsonld"",""data_hash"":""3e6b1083a637a740d5b84bb6edf1a5119b81440b31ea84907311b6543ebd39eb""}}",,,,,Some(525),cy0/n5/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 +gov_action1k2jertppnnndejjcglszfqq4yzw8evzrd2nt66rr6rqlz54xp0zsq05ecsn,b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,519,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1,100181,726,719,0,1,100181,726,719,0,1,100181,726,719,0,1,107878,680,0,1,95336,1,281145,18848,0,1,180194,159,1,1,158519,8942,0,1,159378,8813,0,1,107490,3298,1,106057,655,1,1964219,24520,3]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-04-ppu/metadata.jsonld"",""data_hash"":""94deb036c455e4064f7ed4162edbdb7d892ad264094df9a26fd61b5b130d100f""}}",,Some(525),Some(526),,,cy5/n0/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 +gov_action1llcd7ezdx299xeep9azm4dvsvz7783qfrhykcu3sv2ykl4sewv2qq4myfpk,fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,522,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-19-infohf/metadata.jsonld"",""data_hash"":""93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e""}}",,,,,Some(529),cy6/n0/a1:dy1662309604816396/n3240479257792/a104183585725135:sy1628124195597550/n0/a0,c0:d1:s1 +gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525,0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,529,,HardForkInitiation,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9"",""action_index"":0},""gov_action"":{""HardForkInitiation"":{""previous_action_id"":null,""protocol_version"":{""major"":10,""minor"":0}}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-30-hf10/metadata.jsonld"",""data_hash"":""8a1bd37caa6b914a8b569adb63a0f41d8f159c110dc5c8409118a3f087fffb43""}}",,Some(536),Some(537),,,cy7/n0/a0:dy0/n0/a0:sy14409193713024022/n62248540964906/a917440954183897,c2/3:d3/5:s51/100 +gov_action133jnaewfsq8x6v08ndd87l2yqryp63r30t2dkceacxx5cply5n7sqzlcyqf,8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,537,,NewConstitution,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"",""action_index"":0},""gov_action"":{""NewConstitution"":{""previous_action_id"":null,""new_constitution"":{""anchor"":{""url"":""ipfs://bafkreiazhhawe7sjwuthcfgl3mmv2swec7sukvclu3oli7qdyz4uhhuvmy"",""data_hash"":""2a61e2f4b63442978140c77a70daab3961b22b12b63b13949a390c097214d1c5""},""guardrail_script"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}}},""anchor"":{""url"":""ipfs://bafkreiehcekhhsq34ccezwn46brg3euj6tbs4g4yjkav34ukqvbnzaya2a"",""data_hash"":""d085e5af96521ae2670400e76c3a1e4b4eb902139ddaa83bde7580e7e9d7ddec""}}",,Some(541),Some(542),,,cy7/n0/a0:dy3147155733843689/n80277670032839/a173769211483602:sy0/n0/a0,c2/3:d3/4:s0 +gov_action1js2s9v92zpxg2rge0y3jt9zy626he2m67x9kx9phw4r942kvsn6sqfym0d7,941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5,0,"transaction: b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5, action_index: 0",100000000000,646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59,539,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59""}},""gov_action_id"":{""transaction_id"":""941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""protocol_param_update"":{""treasury_growth_rate"":[1,10]},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://QmcKQggcpouuhAAvUYGDzoKgMwbZSkWqiEeE6c67SJ3kEq"",""data_hash"":""9b2438f0032a0c24ed62d12d6bdb79b47e2bd0c4d2dd4f4936c055ead7109caf""}}",,,,,Some(546),cy2/n5/a0:dy939990053651256/n1965627054695765/a284188967365253:sy0/n0/a0,c2/3:d67/100:s0 +gov_action12meeq4r43udremwpm6fzt4nt7fctvt0ah7798x036m2r4nhlccmqqhmr9wx,56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,542,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiada4nn5eaezg43esieduks6l57vzkjdo2yfby7yxv6jrat7ilrdq"",""data_hash"":""b160033b47dfc31885c297c55ba6b68afaf7561da3070eced93d84ad70d8f5b3""}}",,,,,Some(549),cy3/n1/a3:dy2849267784746103/n47404553333753/a58248658178512:sy646730366107541/n0/a2618952257730,c0:d1:s1 +gov_action10ueqgzwenxr39le68n0se9peu92r7gm2846xwehh3u0ahc0qd0uqqyljxu5,7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8,0,,100000000000,34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f,546,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f""}},""gov_action_id"":{""transaction_id"":""7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/blockchainada/ga/refs/heads/main/ga01.jsonld"",""data_hash"":""a2fa375274a2c5efa985a1e9811f27ea1ebf8b8dd88cdf9931a5aa856c73832a""}}",,,,,Some(553),cy1/n4/a1:dy1780269838508229/n1626018423362940/a96196729276630:sy566347694726570/n603581674443045/a879726334116,c0:d1:s1 +gov_action1nd3t833j7v5sz65k3tp9yyvztw60sjcjgcgjr37682s3m7frwrusqmd2k80,9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,547,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiaqno22swabd3kcqt2awtgwaucdzaagacoemxwadm3exrchhnfite"",""data_hash"":""973452e7c4d204c883c6a9e4c311f72ad6237e827ce05e141f3374c8a04f01bc""}}",,,,,Some(554),cy5/n1/a1:dy3555798499117719/n927833581144205/a266084892066727:sy622342555916988/n942621542016625/a10607703917013,c0:d1:s1 +gov_action10k0unljvaej0kd89w7pn0zkgdx59c7xkl0x5q78dzvdtd73u0kmqq5xl5y5,7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,554,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmRrGsZsP5R7cFYFzPXQ9vS2Ux7oTXb1ep1EciLdKqeDWY"",""data_hash"":""30f03001e623d61ae782efe922b21ef79c4a1d06b258fd773d9c762d1a42d9b9""}}",,,,,Some(561),cy6/n0/a1:dy2425490955933534/n2297474620022945/a64913595414068:sy672666725152325/n24241821569730/a888586571923,c0:d1:s1 +gov_action1h4ygjv0hjfj3lmafcm76rpdzcm8vsvj9k5wejn3npyxwxm3fesnqqw9kxxz,bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibqma7t2k4rcywvx5afukahhi3dp2so2ugh7t4ljuawhanvk7sr34"",""data_hash"":""7d2f344f3651a8372ad603abf11fcb310fb3c5154a6592591d1ff97d951156e3""}}",,,,,Some(563),cy6/n0/a1:dy4500048611264804/n31848673410621/a45099889469182:sy569746862334739/n0/a0,c0:d1:s1 +gov_action1vdlrcftd48qn2zz8egepr6xyfcmxpfz8r69k769gc5mhg662adesq9yy8pl,637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73,0,,100000000000,29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122""}},""gov_action_id"":{""transaction_id"":""637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://ipfs.io/ipfs/bafkreieu47jw2qoxmqz67qyhhj4pi7fssuth5s4mm42qleqtw5tuzs3pgu"",""data_hash"":""ec7179c11582daa390e6d0c3f3cc46b0116d96aadcc74e02aa8d8e91434ab7af""}}",,,,,Some(563),cy6/n0/a1:dy2063455667008172/n1632235923043398/a145991747762932:sy130291633488926/n257125277926045/a71298578525921,c0:d1:s1 +gov_action1fpqwxp2kxvnntr8hpkh9q9djm78ccdww7qlhg5safugh4stmcwzqql5lauu,4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384,0,,100000000000,3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364""}},""gov_action_id"":{""transaction_id"":""4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/theeldermillenial/2025-liquidity-budget/df0b26d8796b19b566008ea9eaa8f17fef2cb6d4/info.jsonld"",""data_hash"":""97df3a30b767ee5b8e2b9fde824d91d3366985243ed73c06b257c2163f9045db""}}",,,,,Some(563),cy0/n4/a1:dy212465307551433/n2228913162217302/a438473698221786:sy0/n33370675402718/a24221567758519,c0:d1:s1 +gov_action1mmalzkcxpyn33t05hml2hxpwq0ffv6uu4mhe8sv7guz5nmm4afysqlmepzl,defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmaWrgqcQS7jYyLYFpvBiamZ4mCoeasL78qaPASDaJ6dT3"",""data_hash"":""4a4c99645a68d29eab6615ac71191cc92c745f92f97cdaf47890be1bad7487a7""}}",,,,,Some(563),cy0/n7/a0:dy1814353580889176/n1176878238974779/a461607195493589:sy211863729905114/n128435026893983/a800795601962,c0:d1:s1 +gov_action1u9x73kwufaxa70lfy59g4ynwyrcsaxdcd0gxzzmh67s9fxq4j8hqqk2phgh,e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee,0,,100000000000,bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d,557,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d""}},""gov_action_id"":{""transaction_id"":""e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibeajhkes7bxjlkghkingcgltqcwazz2ya5oknveqwt5nont7tg6u"",""data_hash"":""b95d8f8e324e9863905f16dbad94c1f25b28b933ae842e6f8ce9841c8da5b197""}}",,,,,Some(564),cy6/n0/a1:dy3568747822222928/n732747387805908/a143704110191164:sy606977531362334/n42674324713788/a1734640589499,c0:d1:s1 +gov_action1vrkk4dpuss8l3z9g4uc2rmf8ks0f7j534zvz9v4k85dlc54wa3zsqq68rx0,60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,566,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,228,37,152,78,36,251,44,6,173,103,104,130,23,141,222,230,228,123,153,74,88,154,227,215,12,129,124,121],300000000000],[[241,155,234,230,252,127,234,218,108,207,130,69,84,181,227,164,152,234,177,82,5,172,146,72,195,251,153,59,95],300000000000],[[241,167,150,104,120,85,12,225,30,200,168,59,147,252,26,110,16,93,84,79,120,73,68,1,6,108,79,224,207],300000000000],[[241,135,127,87,224,189,204,129,103,233,132,222,224,82,216,221,115,70,239,252,8,255,128,162,155,4,94,26,16],500000000000],[[241,134,14,224,246,189,130,53,132,42,144,138,253,134,220,148,156,76,157,171,215,75,9,101,195,100,184,211,21],100000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreifw3qs7brjn4tdvyprnh2r343oerbdghasp5ws6ro55frbpll3dta"",""data_hash"":""d2f633b044f33117ace7cde8c045fcc930060a6dbdd083f7491148a86a3c5ebd""}}",,Some(570),Some(571),,,cy7/n0/a0:dy4093833588084653/n21189101483536/a52442655453280:sy0/n0/a0,c2/3:d67/100:s0 +gov_action1n5sn54mgf47a7men2ryq6ppx88kta4wvenz2qkl4f9v6ppje8easqxwm88m,9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b,0,,100000000000,2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0,567,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0""}},""gov_action_id"":{""transaction_id"":""9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmP9iDuML2VmoFigTJifBj87LxZ3DNnREyU27DE1MrpZDg"",""data_hash"":""b3dc422b419a0e7beee4bf594bcfd344d87e2dc593d0fef5eb1fd218c0a6137b""}}",,,,,Some(574),cy7/n0/a0:dy2832862312472265/n935246197584261/a674152156041788:sy66736422727105/n66272824647159/a0,c0:d1:s1 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlpwywvhcq,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,23,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":23},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],69459000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreid2pq5icpp77nfvdvnb5ipy3fqs77tpnls4ngxy6semzkdq7d2z7y"",""data_hash"":""5edb23193df820ab4e8334d2e12fdc57aac5f06fe9a81067aa651b3439b57119""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3926392145162793/n75355236808630/a62411838251542:sy0/n0/a0,c2/3:d67/100:s0 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqz6d98zp,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,1,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":1},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],96817080000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreigt5xy56qjxd7dl2s7u6jxec2cfxevynppvgnnjifc2wawr7md5ha"",""data_hash"":""442b57ebf94db21544475a5dbdfe57f50e648646533d31bfa329c280aebfcfe9""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3912321432502202/n23692002076694/a312701730992913:sy0/n0/a0,c2/3:d67/100:s0 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqqfgyy3v,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,0,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],2162096000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreidjnukg5c7u5zlkxaciy4hkxfixvtquhx6uzlqpydvrxormfqpdm4"",""data_hash"":""6611ea5602de95d463ecf28f1c4ca26ad91fe7ed499d0a1594e3c2fd528a2a62""}}",,Some(574),Some(575),,,cy5/n0/a0:dy4127174354090953/n94145593104288/a0:sy0/n0/a0,c2/3:d67/100:s0 diff --git a/modules/governance_state/src/conway_voting.rs b/modules/governance_state/src/conway_voting.rs index 5b130de7..4ae80b69 100644 --- a/modules/governance_state/src/conway_voting.rs +++ b/modules/governance_state/src/conway_voting.rs @@ -1,6 +1,11 @@ use crate::voting_state::VotingRegistrationState; use acropolis_common::protocol_params::ConwayParams; -use acropolis_common::{BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, GovActionId, GovernanceAction, GovernanceOutcome, GovernanceOutcomeVariant, Lovelace, PoolId, ProposalProcedure, SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Vote, VoteCount, VoteResult, Voter, VotingOutcome, VotingProcedure}; +use acropolis_common::{ + BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, GovActionId, GovernanceAction, + GovernanceOutcome, GovernanceOutcomeVariant, Lovelace, PoolId, ProposalProcedure, + SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Vote, VoteCount, VoteResult, Voter, + VotingOutcome, VotingProcedure, +}; use anyhow::{anyhow, bail, Result}; use hex::ToHex; use std::collections::{HashMap, HashSet}; diff --git a/modules/governance_state/src/conway_voting_test.rs b/modules/governance_state/src/conway_voting_test.rs index 54dc6b8c..e2b405e2 100644 --- a/modules/governance_state/src/conway_voting_test.rs +++ b/modules/governance_state/src/conway_voting_test.rs @@ -34,8 +34,8 @@ mod tests { #[derive(Clone, Debug, serde::Deserialize)] struct PoolRecord( #[serde_as(as = "Base64")] PoolId, // key - u64, // active stake - u64, // live stake + u64, // active stake + u64, // live stake ); #[serde_as] @@ -224,6 +224,7 @@ mod tests { } #[test] + #[ignore] fn test_voting_mainnet_up_573() -> Result<()> { let fmt_layer = fmt::layer() .with_filter( diff --git a/modules/governance_state/src/state.rs b/modules/governance_state/src/state.rs index 7c580f3c..29b109d5 100644 --- a/modules/governance_state/src/state.rs +++ b/modules/governance_state/src/state.rs @@ -5,8 +5,8 @@ use acropolis_common::{ CardanoMessage, DRepStakeDistributionMessage, GovernanceOutcomesMessage, GovernanceProceduresMessage, Message, ProtocolParamsMessage, SPOStakeDistributionMessage, }, - BlockInfo, DRepCredential, DelegatedStake, Era, GovActionId, Lovelace, - ProposalProcedure, TxHash, Voter, VotingProcedure, PoolId + BlockInfo, DRepCredential, DelegatedStake, Era, GovActionId, Lovelace, PoolId, + ProposalProcedure, TxHash, Voter, VotingProcedure, }; use anyhow::{anyhow, bail, Result}; use caryatid_sdk::Context; From 87b2ea6742938b2b2e2c0c6d401c32ac1884fb6a Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 29 Oct 2025 16:59:44 -0700 Subject: [PATCH 12/20] Refactor: Replace `PoolId::new` and `KeyHash::new` with `.into()` for hash conversions across modules --- codec/src/map_parameters.rs | 4 +- common/src/address.rs | 56 ++++++++++++------- common/src/types.rs | 2 +- modules/accounts_state/src/snapshot.rs | 10 ++-- .../src/spo_distribution_store.rs | 6 +- modules/accounts_state/src/state.rs | 12 ++-- modules/epochs_state/src/state.rs | 2 +- modules/spo_state/src/epochs_history.rs | 6 +- .../spo_state/src/retired_pools_history.rs | 5 +- modules/spo_state/src/state.rs | 5 +- 10 files changed, 59 insertions(+), 49 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index b7114d54..dca08495 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -58,7 +58,7 @@ pub fn to_hash_opt( /// Convert a Pallas Hash<28> reference to an Acropolis PoolId pub fn to_pool_id(pallas_hash: &pallas_primitives::Hash<28>) -> PoolId { - PoolId::from(to_hash(pallas_hash)) + to_hash(pallas_hash).into() } /// Convert a Pallas Hash<32> reference to an Acropolis VRFKey @@ -72,7 +72,7 @@ pub fn bytes_to_hash(bytes: &pallas_primitives::Bytes) -> Hash Self { - Self::PaymentKeyHash(KeyHash::new([0u8; 28])) + Self::PaymentKeyHash([0u8; 28].into()) } } @@ -211,19 +211,31 @@ impl ShelleyAddress { let header = *header; - let to_28_bytes = |slice: &[u8]| -> Result { - slice.try_into().map_err(|_| anyhow!("Invalid hash")) - }; - let payment_part = match (header >> 4) & 0x01 { - 0 => ShelleyAddressPaymentPart::PaymentKeyHash(to_28_bytes(&data[1..29])?), - 1 => ShelleyAddressPaymentPart::ScriptHash(to_28_bytes(&data[1..29])?), + 0 => ShelleyAddressPaymentPart::PaymentKeyHash( + data[1..29] + .try_into() + .map_err(|e| anyhow!("Failed to parse payment key hash: {}", e))?, + ), + 1 => ShelleyAddressPaymentPart::ScriptHash( + data[1..29] + .try_into() + .map_err(|e| anyhow!("Failed to parse payment script hash: {}", e))?, + ), _ => panic!(), }; let delegation_part = match (header >> 5) & 0x03 { - 0 => ShelleyAddressDelegationPart::StakeKeyHash(to_28_bytes(&data[29..57])?), - 1 => ShelleyAddressDelegationPart::ScriptHash(to_28_bytes(&data[29..57])?), + 0 => ShelleyAddressDelegationPart::StakeKeyHash( + data[29..57] + .try_into() + .map_err(|e| anyhow!("Failed to parse stake key hash: {}", e))?, + ), + 1 => ShelleyAddressDelegationPart::ScriptHash( + data[29..57] + .try_into() + .map_err(|e| anyhow!("Failed to parse stake script hash: {}", e))?, + ), 2 => { let mut decoder = VarIntDecoder::new(&data[29..]); let slot = decoder.read()?; @@ -301,24 +313,24 @@ impl ShelleyAddress { ShelleyAddressDelegationPart::None => { let header = build_header(3); data.push(header); - data.extend(payment_hash.as_ref()); + data.extend_from_slice(payment_hash.as_ref()); } ShelleyAddressDelegationPart::StakeKeyHash(hash) => { let header = build_header(0); data.push(header); - data.extend(payment_hash.as_ref()); - data.extend(hash.as_ref()); + data.extend_from_slice(payment_hash.as_ref()); + data.extend_from_slice(hash.as_ref()); } ShelleyAddressDelegationPart::ScriptHash(hash) => { let header = build_header(1); data.push(header); - data.extend(payment_hash.as_ref()); - data.extend(hash.as_ref()); + data.extend_from_slice(payment_hash.as_ref()); + data.extend_from_slice(hash.as_ref()); } ShelleyAddressDelegationPart::Pointer(pointer) => { let header = build_header(2); data.push(header); - data.extend(payment_hash.as_ref()); + data.extend_from_slice(payment_hash.as_ref()); let mut encoder = VarIntEncoder::new(); encoder.push(pointer.slot); @@ -413,10 +425,12 @@ impl StakeAddress { let credential = match (header >> 4) & 0x0Fu8 { 0b1110 => StakeCredential::AddrKeyHash( - data[1..].try_into().map_err(|_| anyhow!("Invalid key hash size"))?, + data[1..].try_into().map_err(|e| anyhow!("Failed to parse key hash: {}", e))?, ), 0b1111 => StakeCredential::ScriptHash( - data[1..].try_into().map_err(|_| anyhow!("Invalid script hash size"))?, + data[1..] + .try_into() + .map_err(|e| anyhow!("Failed to parse script hash: {}", e))?, ), _ => return Err(anyhow!("Unknown header {header} in stake address")), }; @@ -437,9 +451,9 @@ impl StakeAddress { NetworkId::Testnet => 0b0u8, }; - let (stake_bits, stake_hash): (u8, &Vec) = match &self.credential { - StakeCredential::AddrKeyHash(data) => (0b1110, &data.to_vec()), - StakeCredential::ScriptHash(data) => (0b1111, &data.to_vec()), + let (stake_bits, stake_hash) = match &self.credential { + StakeCredential::AddrKeyHash(data) => (0b1110, data.as_ref()), + StakeCredential::ScriptHash(data) => (0b1111, data.as_ref()), }; let mut data = vec![network_bits | (stake_bits << 4)]; @@ -526,7 +540,7 @@ impl Default for StakeAddress { fn default() -> Self { StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(KeyHash::new([0u8; 28])), + credential: StakeCredential::AddrKeyHash([0u8; 28].into()), } } } diff --git a/common/src/types.rs b/common/src/types.rs index e4ab6e3a..fbf42404 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -2090,7 +2090,7 @@ mod tests { let mut test_hash_bytes = [0u8; 28]; test_hash_bytes[0..4].copy_from_slice(&[1, 2, 3, 4]); voting.votes.insert( - Voter::StakePoolKey(PoolId::new(Hash::new(test_hash_bytes))), + Voter::StakePoolKey(test_hash_bytes.into()), SingleVoterVotes::default(), ); diff --git a/modules/accounts_state/src/snapshot.rs b/modules/accounts_state/src/snapshot.rs index 455bcd02..bd0154fa 100644 --- a/modules/accounts_state/src/snapshot.rs +++ b/modules/accounts_state/src/snapshot.rs @@ -195,23 +195,21 @@ mod tests { use super::*; use acropolis_common::stake_addresses::StakeAddressState; use acropolis_common::NetworkId::Mainnet; - use acropolis_common::{KeyHash, PoolId, StakeAddress, StakeCredential}; + use acropolis_common::{PoolId, StakeAddress, StakeCredential}; - // Helper function to create stake addresses for testing fn create_test_stake_address(id: u8) -> StakeAddress { let mut hash = [0u8; 28]; hash[0] = id; StakeAddress { network: Mainnet, - credential: StakeCredential::AddrKeyHash(KeyHash::new(hash)), + credential: StakeCredential::AddrKeyHash(hash.into()), } } - // Helper function to create SPO key hashes for testing fn create_test_spo_hash(id: u8) -> PoolId { - let mut hash = vec![0u8; 28]; + let mut hash = [0u8; 28]; hash[0] = id; - PoolId::try_from(hash).unwrap() + hash.into() } #[test] diff --git a/modules/accounts_state/src/spo_distribution_store.rs b/modules/accounts_state/src/spo_distribution_store.rs index ea24eddc..cdf6b02e 100644 --- a/modules/accounts_state/src/spo_distribution_store.rs +++ b/modules/accounts_state/src/spo_distribution_store.rs @@ -32,8 +32,8 @@ fn encode_epoch_pool_prefix(epoch: u64, pool_id: &PoolId) -> Vec { fn decode_key(key: &[u8]) -> Result<(u64, PoolId, AddrKeyhash)> { let epoch = u64::from_be_bytes(key[..EPOCH_LEN].try_into()?); - let pool_id: PoolId = key[EPOCH_LEN..EPOCH_LEN + POOL_ID_LENGTH].try_into()?; - let stake_key: AddrKeyhash = key[EPOCH_LEN + POOL_ID_LENGTH..].try_into()?; + let pool_id = key[EPOCH_LEN..EPOCH_LEN + POOL_ID_LENGTH].try_into()?; + let stake_key = key[EPOCH_LEN + POOL_ID_LENGTH..].try_into()?; Ok((epoch, pool_id, stake_key)) } @@ -230,7 +230,7 @@ mod tests { const DB_PATH: &str = "spdd_db"; fn test_pool_hash(byte: u8) -> PoolId { - PoolId::new(keyhash_224(&vec![byte])) + keyhash_224(&vec![byte]).into() } fn test_addr_hash(byte: u8) -> AddrKeyhash { diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index fc054a26..bc1f9987 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -1022,7 +1022,7 @@ mod tests { } fn test_vrf_keyhash(byte: u8) -> VrfKeyHash { - VrfKeyHash::new(keyhash_256(&vec![byte])) + keyhash_256(&vec![byte]).into() } const STAKE_KEY_HASH: [u8; 3] = [0x99, 0x0f, 0x00]; @@ -1078,8 +1078,8 @@ mod tests { fn spdd_from_delegation_with_utxo_values_and_pledge() { let mut state = State::default(); - let spo1: PoolId = PoolId::new(test_keyhash(0x01)); - let spo2: PoolId = PoolId::new(test_keyhash(0x02)); + let spo1 = test_keyhash(0x01).into(); + let spo2 = test_keyhash(0x02).into(); let vrf_key_hash_1 = test_vrf_keyhash(0x03); let vrf_key_hash_2 = test_vrf_keyhash(0x04); @@ -1090,7 +1090,7 @@ mod tests { epoch: 1, spos: vec![ PoolRegistration { - operator: spo1.clone(), + operator: spo1, vrf_key_hash: vrf_key_hash_1, pledge: 26, cost: 0, @@ -1104,7 +1104,7 @@ mod tests { pool_metadata: None, }, PoolRegistration { - operator: spo2.clone(), + operator: spo2, vrf_key_hash: vrf_key_hash_2, pledge: 47, cost: 10, @@ -1393,7 +1393,7 @@ mod tests { // Get the KeyHash once let spo1_hash = spo1.get_hash(); let drep_key_hash = test_keyhash_from_bytes(&DREP_HASH); - let pool_id_1 = PoolId::new(*spo1_hash); + let pool_id_1 = (*spo1_hash).into(); let certificates = vec![ // register the first two SPOs separately from their delegation diff --git a/modules/epochs_state/src/state.rs b/modules/epochs_state/src/state.rs index 4135eb0b..a2a29a55 100644 --- a/modules/epochs_state/src/state.rs +++ b/modules/epochs_state/src/state.rs @@ -188,7 +188,7 @@ impl State { self.last_block_time = block_info.timestamp; self.last_block_height = block_info.number; self.epoch_blocks += 1; - let spo_id = PoolId::new(keyhash_224(issuer_vkey)); + let spo_id = PoolId::from(keyhash_224(issuer_vkey)); // Count one on this hash *(self.blocks_minted.entry(spo_id.clone()).or_insert(0)) += 1; diff --git a/modules/spo_state/src/epochs_history.rs b/modules/spo_state/src/epochs_history.rs index dd47241b..bc57b506 100644 --- a/modules/spo_state/src/epochs_history.rs +++ b/modules/spo_state/src/epochs_history.rs @@ -214,7 +214,7 @@ mod tests { #[test] fn get_pool_history_returns_none_when_spo_is_not_found() { - let key_hash = KeyHash::new([1; 28]); + let key_hash = [1; 28].into(); let epochs_history = EpochsHistoryState::new(save_history_store_config()); let pool_history = epochs_history.get_pool_history(&key_hash); assert!(pool_history.is_none()); @@ -223,8 +223,8 @@ mod tests { #[test] fn get_pool_history_returns_data() { let epochs_history = EpochsHistoryState::new(save_history_store_config()); - let pool_id = PoolId::new(KeyHash::new([1; 28])); - let spo_block_key_hash = PoolId::new(KeyHash::new([2; 28])); + let pool_id = [1; 28].into(); + let spo_block_key_hash = [2; 28].into(); let block = new_block(2); let mut spdd_msg = new_spdd_message(1); diff --git a/modules/spo_state/src/retired_pools_history.rs b/modules/spo_state/src/retired_pools_history.rs index 7e011fb4..37648cc1 100644 --- a/modules/spo_state/src/retired_pools_history.rs +++ b/modules/spo_state/src/retired_pools_history.rs @@ -66,7 +66,6 @@ impl RetiredPoolsHistoryState { mod tests { use super::*; use crate::test_utils::*; - use acropolis_common::KeyHash; #[test] fn retired_pools_history_is_none_when_store_retired_pools_is_false() { @@ -91,8 +90,8 @@ mod tests { let state = RetiredPoolsHistoryState::new(save_retired_pools_store_config()); let block = new_block(2); - let spo_1 = PoolId::new(KeyHash::new([1; 28])); - let spo_2 = PoolId::new(KeyHash::new([2; 28])); + let spo_1 = [1; 28].into(); + let spo_2 = [2; 28].into(); let retired_spos = vec![spo_1, spo_2]; state.handle_deregistrations(&block, &retired_spos); diff --git a/modules/spo_state/src/state.rs b/modules/spo_state/src/state.rs index 2fda28e5..771d75b8 100644 --- a/modules/spo_state/src/state.rs +++ b/modules/spo_state/src/state.rs @@ -668,7 +668,6 @@ impl State { mod tests { use super::*; use crate::test_utils::*; - use acropolis_common::hash::Hash; use acropolis_common::{ state_history::{StateHistory, StateHistoryStore}, PoolRetirement, Ratio, StakeAddress, TxCertificate, TxCertificateWithPos, TxIdentifier, @@ -677,11 +676,11 @@ mod tests { use tokio::sync::Mutex; fn test_pool_id(byte: u8) -> PoolId { - PoolId::new(Hash::new([byte; 28])) + [byte; 28].into() } fn test_pool_id_from_bytes(bytes: &[u8]) -> PoolId { - PoolId::new(keyhash_224(bytes)) + keyhash_224(bytes).into() } fn default_pool_registration( From 119426ff3c9b1ffb6f71ca8ca06b1516ce18b344 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Wed, 29 Oct 2025 17:11:55 -0700 Subject: [PATCH 13/20] Refactor: Replace `KeyHash::try_from` with `.try_into()` for consistent hash conversion across modules --- codec/src/map_parameters.rs | 16 ---------------- common/src/snapshot/streaming_snapshot.rs | 6 +++--- common/src/types.rs | 13 +++++-------- modules/accounts_state/src/state.rs | 2 +- modules/accounts_state/src/verifier.rs | 2 +- modules/chain_store/src/chain_store.rs | 4 ++-- modules/parameters_state/src/genesis_params.rs | 3 +-- modules/stake_delta_filter/src/utils.rs | 6 +++--- 8 files changed, 16 insertions(+), 36 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index dca08495..4ec1c4c0 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -49,13 +49,6 @@ pub fn genesis_delegate_to_hash( Hash::try_from(pallas_hash.as_ref()).unwrap() } -/// Convert an optional Pallas Hash reference to an optional Acropolis Hash -pub fn to_hash_opt( - pallas_hash: Option<&pallas_primitives::Hash>, -) -> Option> { - pallas_hash.map(|h| to_hash(h)) -} - /// Convert a Pallas Hash<28> reference to an Acropolis PoolId pub fn to_pool_id(pallas_hash: &pallas_primitives::Hash<28>) -> PoolId { to_hash(pallas_hash).into() @@ -66,15 +59,6 @@ pub fn to_vrf_key(pallas_hash: &pallas_primitives::Hash<32>) -> VrfKeyHash { VrfKeyHash::try_from(pallas_hash.as_ref()).unwrap() } -/// Convert a Pallas Bytes reference to an Acropolis Hash -/// Useful for genesis hash fields that might be stored as Bytes -pub fn bytes_to_hash(bytes: &pallas_primitives::Bytes) -> Hash { - let slice: &[u8] = bytes.as_ref(); - let mut array = [0u8; N]; - array.copy_from_slice(&slice[..N]); - array.into() -} - /// Derive our Address from a Pallas address // This is essentially a 1:1 mapping but makes the Message definitions independent // of Pallas diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index 8e91a5a2..0c7c96e0 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -66,7 +66,7 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential { 0 => { // ScriptHash variant (first in enum) - decode bytes directly let bytes = d.bytes()?; - let key_hash = KeyHash::try_from(bytes).map_err(|_| { + let key_hash = bytes.try_into().map_err(|_| { minicbor::decode::Error::message( "invalid length for ScriptHash in StakeCredential", ) @@ -76,7 +76,7 @@ impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential { 1 => { // AddrKeyHash variant (second in enum) - decodes bytes directly let bytes = d.bytes()?; - let key_hash = KeyHash::try_from(bytes).map_err(|_| { + let key_hash = bytes.try_into().map_err(|_| { minicbor::decode::Error::message( "invalid length for AddrKeyHash in StakeCredential", ) @@ -309,7 +309,7 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { pub use crate::types::AddrKeyhash; pub use crate::types::ScriptHash; -use crate::{KeyHash, PoolId}; +use crate::{PoolId}; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; diff --git a/common/src/types.rs b/common/src/types.rs index fbf42404..f2a6af55 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -653,8 +653,10 @@ impl Credential { hex_str )) } else { - KeyHash::try_from(key_hash.as_slice()) - .map_err(|_| anyhow!("Failed to convert to KeyHash")) + key_hash + .as_slice() + .try_into() + .map_err(|e| anyhow!("Failed to convert to KeyHash {}", e)) } } @@ -695,12 +697,7 @@ impl Credential { )); } - let hash = KeyHash::try_from(data).map_err(|v| { - anyhow!( - "Failed to convert to KeyHash: expected 28 bytes, got {}", - v.len() - ) - })?; + let hash = data.try_into().expect("failed to convert to fixed-size array"); match hrp.as_str() { "drep" => Ok(Credential::AddrKeyHash(hash)), diff --git a/modules/accounts_state/src/state.rs b/modules/accounts_state/src/state.rs index bc1f9987..b39f354f 100644 --- a/modules/accounts_state/src/state.rs +++ b/modules/accounts_state/src/state.rs @@ -1009,7 +1009,7 @@ mod tests { full_hash[..hash.len().min(28)].copy_from_slice(&hash[..hash.len().min(28)]); StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash(KeyHash::try_from(full_hash).unwrap()), + credential: StakeCredential::AddrKeyHash(full_hash.try_into().unwrap()), } } diff --git a/modules/accounts_state/src/verifier.rs b/modules/accounts_state/src/verifier.rs index 42b67383..3ba1fbf3 100644 --- a/modules/accounts_state/src/verifier.rs +++ b/modules/accounts_state/src/verifier.rs @@ -166,7 +166,7 @@ impl Verifier { continue; }; - expected_rewards.entry(KeyHash::try_from(spo).unwrap()).or_default().push( + expected_rewards.entry(spo.try_into().unwrap()).or_default().push( RewardDetail { account: stake_address, rtype, diff --git a/modules/chain_store/src/chain_store.rs b/modules/chain_store/src/chain_store.rs index 3d145be5..22125943 100644 --- a/modules/chain_store/src/chain_store.rs +++ b/modules/chain_store/src/chain_store.rs @@ -12,7 +12,7 @@ use acropolis_common::{ }, queries::misc::Order, state_history::{StateHistory, StateHistoryStore}, - BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, TxHash, VrfKeyHash, + BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, TxHash, }; use anyhow::{bail, Result}; use caryatid_sdk::{module, Context, Module}; @@ -413,7 +413,7 @@ impl ChainStore { tx_count: decoded.tx_count() as u64, output, fees, - block_vrf: header.vrf_vkey().map(|key| VrfKeyHash::try_from(key).ok().unwrap()), + block_vrf: header.vrf_vkey().map(|key| key.try_into().ok().unwrap()), op_cert, op_cert_counter, previous_block: header.previous_hash().map(|h| BlockHash::from(*h)), diff --git a/modules/parameters_state/src/genesis_params.rs b/modules/parameters_state/src/genesis_params.rs index dad2582d..01b54b90 100644 --- a/modules/parameters_state/src/genesis_params.rs +++ b/modules/parameters_state/src/genesis_params.rs @@ -1,5 +1,4 @@ use crate::alonzo_genesis; -use acropolis_common::types::ScriptHash; use acropolis_common::{ protocol_params::{AlonzoParams, BabbageParams, ByronParams, ConwayParams, ShelleyParams}, rational_number::{rational_number_from_f32, RationalNumber}, @@ -109,7 +108,7 @@ pub fn map_constitution(constitution: &conway::Constitution) -> Result(pallas_hash: ScriptHash) -> Hash { - Hash::try_from(pallas_hash.as_ref()).unwrap() + pallas_hash.as_ref().try_into().unwrap() } pub fn stake_to_hash(pallas_hash: StakeKeyHash) -> Hash { - Hash::try_from(pallas_hash.as_ref()).unwrap() + pallas_hash.as_ref().try_into().unwrap() } pub fn payment_to_hash(pallas_hash: PaymentKeyHash) -> Hash { - Hash::try_from(pallas_hash.as_ref()).unwrap() + pallas_hash.as_ref().try_into().unwrap() } /// Derive our Address from a Pallas address From a3dd388faf0b2aa23305f62531dc148488d4cbd4 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 08:30:07 -0700 Subject: [PATCH 14/20] Use as_ref in immutable_historical_account_store.rs vs into_inner() --- common/src/hash.rs | 5 +++ common/src/snapshot/streaming_snapshot.rs | 2 +- common/src/types.rs | 4 +-- modules/accounts_state/src/verifier.rs | 12 +++---- .../src/immutable_historical_account_store.rs | 32 ++++++++++++------- .../parameters_state/src/genesis_params.rs | 4 +-- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/common/src/hash.rs b/common/src/hash.rs index 985a7f3c..6a33306e 100644 --- a/common/src/hash.rs +++ b/common/src/hash.rs @@ -53,6 +53,11 @@ impl Hash { pub fn into_inner(self) -> [u8; BYTES] { self.0 } + + #[inline] + pub fn as_inner(&self) -> &[u8; BYTES] { + &self.0 + } } impl From<[u8; BYTES]> for Hash { diff --git a/common/src/snapshot/streaming_snapshot.rs b/common/src/snapshot/streaming_snapshot.rs index 0c7c96e0..673acb12 100644 --- a/common/src/snapshot/streaming_snapshot.rs +++ b/common/src/snapshot/streaming_snapshot.rs @@ -309,7 +309,7 @@ impl<'b, C> minicbor::Decode<'b, C> for Account { pub use crate::types::AddrKeyhash; pub use crate::types::ScriptHash; -use crate::{PoolId}; +use crate::PoolId; /// Alias minicbor as cbor for pool_params module pub use minicbor as cbor; diff --git a/common/src/types.rs b/common/src/types.rs index af1d956f..42eaa187 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -451,8 +451,8 @@ declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); declare_hash_type_with_bech32!(VrfKeyHash, 32, "vrf_vk"); declare_hash_type_with_bech32!(PoolId, 28, "pool"); -declare_hash_type_with_bech32!(DrepKey, 28, "drep"); -declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); +// declare_hash_type_with_bech32!(DrepKey, 28, "drep"); +// declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); /// Data hash used for metadata, anchors (SHA256) pub type DataHash = Vec; diff --git a/modules/accounts_state/src/verifier.rs b/modules/accounts_state/src/verifier.rs index 4f09c726..4bbc7faf 100644 --- a/modules/accounts_state/src/verifier.rs +++ b/modules/accounts_state/src/verifier.rs @@ -167,13 +167,11 @@ impl Verifier { continue; }; - expected_rewards.entry(spo.try_into().unwrap()).or_default().push( - RewardDetail { - account: stake_address, - rtype, - amount, - }, - ); + expected_rewards.entry(spo.try_into().unwrap()).or_default().push(RewardDetail { + account: stake_address, + rtype, + amount, + }); } info!( diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index eb95c929..947fe3f5 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -156,8 +156,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_rewards = - self.collect_partition::(&self.rewards_history, account.get_hash())?; + let mut immutable_rewards = self.collect_partition::( + &self.rewards_history, + account.get_hash().as_ref(), + )?; self.merge_pending( account, @@ -175,7 +177,7 @@ impl ImmutableHistoricalAccountStore { ) -> Result>> { let mut immutable_active_stake = self.collect_partition::( &self.active_stake_history, - account.get_hash(), + account.get_hash().as_ref(), )?; self.merge_pending( @@ -194,7 +196,7 @@ impl ImmutableHistoricalAccountStore { ) -> Result>> { let mut immutable_registrations = self.collect_partition::( &self.registration_history, - account.get_hash(), + account.get_hash().as_ref(), )?; self.merge_pending( @@ -211,8 +213,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_delegations = self - .collect_partition::(&self.delegation_history, account.get_hash())?; + let mut immutable_delegations = self.collect_partition::( + &self.delegation_history, + account.get_hash().as_ref(), + )?; self.merge_pending( account, @@ -228,8 +232,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_mirs = - self.collect_partition::(&self.mir_history, account.get_hash())?; + let mut immutable_mirs = self.collect_partition::( + &self.mir_history, + account.get_hash().as_ref(), + )?; self.merge_pending(account, |e| e.mir_history.as_ref(), &mut immutable_mirs).await; @@ -240,8 +246,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_withdrawals = self - .collect_partition::(&self.withdrawal_history, account.get_hash())?; + let mut immutable_withdrawals = self.collect_partition::( + &self.withdrawal_history, + account.get_hash().as_ref(), + )?; self.merge_pending( account, @@ -258,7 +266,7 @@ impl ImmutableHistoricalAccountStore { account: &StakeAddress, ) -> Result>> { let mut immutable_addresses = - self.collect_partition::(&self.addresses, account.get_hash())?; + self.collect_partition::(&self.addresses, account.get_hash().as_ref())?; self.merge_pending(account, |e| e.addresses.as_ref(), &mut immutable_addresses).await; @@ -321,7 +329,7 @@ impl ImmutableHistoricalAccountStore { fn make_epoch_key(account: &StakeAddress, epoch: u32) -> [u8; 32] { let mut key = [0u8; 32]; - key[..28].copy_from_slice(&account.get_credential().get_hash()); + key[..28].copy_from_slice(&account.get_credential().get_hash().as_ref()); key[28..32].copy_from_slice(&epoch.to_be_bytes()); key } diff --git a/modules/parameters_state/src/genesis_params.rs b/modules/parameters_state/src/genesis_params.rs index 01b54b90..19a5323b 100644 --- a/modules/parameters_state/src/genesis_params.rs +++ b/modules/parameters_state/src/genesis_params.rs @@ -107,9 +107,7 @@ fn map_drep_thresholds(thresholds: &conway::DRepVotingThresholds) -> Result Result { Ok(Constitution { anchor: map_anchor(&constitution.anchor)?, - guardrail_script: Some( - decode_hex_string(&constitution.script, 28)?.try_into().unwrap(), - ), + guardrail_script: Some(decode_hex_string(&constitution.script, 28)?.try_into().unwrap()), }) } From af62ad8d8b0ec0d205e3b0dc07a59b8687423018 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 09:26:00 -0700 Subject: [PATCH 15/20] Refactor: Consolidate hash type definitions and unify conversions across modules --- codec/src/map_parameters.rs | 8 +-- common/src/address.rs | 10 ++-- common/src/types.rs | 55 ++++++++++--------- modules/drep_state/src/state.rs | 4 +- .../data/conway_verification.csv | 46 ++++++++-------- modules/governance_state/src/conway_voting.rs | 24 +++++--- .../src/conway_voting_test.rs | 20 ++++--- 7 files changed, 91 insertions(+), 76 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 4ec1c4c0..31af54ca 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -912,13 +912,13 @@ pub fn map_governance_proposals_procedures( fn map_voter(voter: &conway::Voter) -> Voter { match voter { conway::Voter::ConstitutionalCommitteeKey(key_hash) => { - Voter::ConstitutionalCommitteeKey(to_hash(key_hash)) + Voter::ConstitutionalCommitteeKey(to_hash(key_hash).into()) } conway::Voter::ConstitutionalCommitteeScript(script_hash) => { - Voter::ConstitutionalCommitteeScript(to_hash(script_hash)) + Voter::ConstitutionalCommitteeScript(to_hash(script_hash).into()) } - conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(to_hash(addr_key_hash)), - conway::Voter::DRepScript(script_hash) => Voter::DRepScript(to_hash(script_hash)), + conway::Voter::DRepKey(addr_key_hash) => Voter::DRepKey(to_hash(addr_key_hash).into()), + conway::Voter::DRepScript(script_hash) => Voter::DRepScript(to_hash(script_hash).into()), conway::Voter::StakePoolKey(key_hash) => Voter::StakePoolKey(to_pool_id(key_hash)), } } diff --git a/common/src/address.rs b/common/src/address.rs index 0d077177..7a3bfa40 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] use crate::cip19::{VarIntDecoder, VarIntEncoder}; -use crate::{Credential, KeyHash, NetworkId, StakeCredential}; +use crate::{Credential, KeyHash, NetworkId, ScriptHash, StakeCredential}; use anyhow::{anyhow, bail, Result}; use crc::{Crc, CRC_32_ISO_HDLC}; use minicbor::data::IanaTag; @@ -100,12 +100,12 @@ pub enum ShelleyAddressPaymentPart { /// Payment to a script #[n(1)] - ScriptHash(#[n(0)] KeyHash), + ScriptHash(#[n(0)] ScriptHash), } impl Default for ShelleyAddressPaymentPart { fn default() -> Self { - Self::PaymentKeyHash([0u8; 28].into()) + Self::PaymentKeyHash(KeyHash::default()) } } @@ -159,7 +159,7 @@ pub enum ShelleyAddressDelegationPart { /// Delegation to script key hash #[n(2)] - ScriptHash(#[n(0)] KeyHash), + ScriptHash(#[n(0)] ScriptHash), /// Delegation to pointer #[n(3)] @@ -540,7 +540,7 @@ impl Default for StakeAddress { fn default() -> Self { StakeAddress { network: NetworkId::Mainnet, - credential: StakeCredential::AddrKeyHash([0u8; 28].into()), + credential: StakeCredential::AddrKeyHash(KeyHash::default()), } } } diff --git a/common/src/types.rs b/common/src/types.rs index 42eaa187..a4bfd1ff 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -3,6 +3,7 @@ #![allow(dead_code)] use crate::hash::Hash; +use crate::serialization::Bech32Conversion; use crate::{ address::{Address, ShelleyAddress, StakeAddress}, declare_hash_type, declare_hash_type_with_bech32, protocol_params, @@ -439,9 +440,13 @@ impl Default for UTXODelta { } } +/// Key hash pub type KeyHash = Hash<28>; +/// Script hash pub type ScriptHash = KeyHash; + +/// Address key hash pub type AddrKeyhash = KeyHash; /// Script identifier @@ -451,8 +456,11 @@ declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); declare_hash_type_with_bech32!(VrfKeyHash, 32, "vrf_vk"); declare_hash_type_with_bech32!(PoolId, 28, "pool"); -// declare_hash_type_with_bech32!(DrepKey, 28, "drep"); -// declare_hash_type_with_bech32!(DrepScriptKey, 28, "drep_script"); + +declare_hash_type_with_bech32!(ConstitutionalCommitteeKeyHash, 28, "cc_hot"); +declare_hash_type_with_bech32!(ConstitutionalCommitteeScriptHash, 28, "cc_hot_script"); +declare_hash_type_with_bech32!(DrepKeyHash, 28, "drep"); +declare_hash_type_with_bech32!(DRepScriptHash, 28, "drep_script"); /// Data hash used for metadata, anchors (SHA256) pub type DataHash = Vec; @@ -641,10 +649,10 @@ pub struct PotDelta { )] pub enum Credential { /// Script hash. NOTE: Order matters when parsing Haskell Node Snapshot data. - ScriptHash(#[serde_as(as = "Hex")] KeyHash), + ScriptHash(#[serde_as(as = "Hex")] ScriptHash), /// Address key hash - AddrKeyHash(#[serde_as(as = "Hex")] KeyHash), + AddrKeyHash(#[serde_as(as = "Hex")] AddrKeyhash), } impl Credential { @@ -1663,33 +1671,26 @@ impl GovernanceAction { serde::Serialize, serde::Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash, )] pub enum Voter { - ConstitutionalCommitteeKey(AddrKeyhash), - ConstitutionalCommitteeScript(ScriptHash), - DRepKey(AddrKeyhash), - DRepScript(ScriptHash), + ConstitutionalCommitteeKey(ConstitutionalCommitteeKeyHash), + ConstitutionalCommitteeScript(ConstitutionalCommitteeScriptHash), + DRepKey(DrepKeyHash), + DRepScript(DRepScriptHash), StakePoolKey(PoolId), } -impl Voter { - pub fn to_bech32(&self, hrp: &str, buf: &[u8]) -> String { - let voter_hrp: Hrp = Hrp::parse(hrp).unwrap(); - bech32::encode::(voter_hrp, buf) - .unwrap_or_else(|e| format!("Cannot convert {:?} to bech32: {e}", self)) - } -} - impl Display for Voter { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Voter::ConstitutionalCommitteeKey(h) => { - write!(f, "{}", self.to_bech32("cc_hot", h.as_ref())) - } - Voter::ConstitutionalCommitteeScript(s) => { - write!(f, "{}", self.to_bech32("cc_hot_script", s.as_ref())) - } - Voter::DRepKey(k) => write!(f, "{}", self.to_bech32("drep", k.as_ref())), - Voter::DRepScript(s) => write!(f, "{}", self.to_bech32("drep_script", s.as_ref())), - Voter::StakePoolKey(k) => write!(f, "{}", self.to_bech32("pool", k.as_ref())), + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bech32 = match self { + Voter::ConstitutionalCommitteeKey(h) => h.to_bech32(), + Voter::ConstitutionalCommitteeScript(s) => s.to_bech32(), + Voter::DRepKey(k) => k.to_bech32(), + Voter::DRepScript(s) => s.to_bech32(), + Voter::StakePoolKey(k) => k.to_bech32(), + }; + + match bech32 { + Ok(s) => write!(f, "{}", s), + Err(e) => write!(f, "", e), } } } diff --git a/modules/drep_state/src/state.rs b/modules/drep_state/src/state.rs index f6bedea0..6f48b4a0 100644 --- a/modules/drep_state/src/state.rs +++ b/modules/drep_state/src/state.rs @@ -261,8 +261,8 @@ impl State { for (tx_hash, voting_procedures) in voting_procedures { for (voter, single_votes) in &voting_procedures.votes { let drep_cred = match voter { - Voter::DRepKey(k) => DRepCredential::AddrKeyHash(*k), - Voter::DRepScript(s) => DRepCredential::ScriptHash(*s), + Voter::DRepKey(k) => DRepCredential::AddrKeyHash(k.into_inner().into()), + Voter::DRepScript(s) => DRepCredential::ScriptHash(s.into_inner().into()), _ => continue, }; diff --git a/modules/governance_state/data/conway_verification.csv b/modules/governance_state/data/conway_verification.csv index dfbd639e..2c40e6bd 100644 --- a/modules/governance_state/data/conway_verification.csv +++ b/modules/governance_state/data/conway_verification.csv @@ -1,23 +1,23 @@ -gov_action1zhuz5djmmmjg8f9s8pe6grfc98xg3szglums8cgm6qwancp4eytqqmpu0pr,15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916,0,,100000000000,45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7,507,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7""}},""gov_action_id"":{""transaction_id"":""15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmWjcHsrq9kKHZZ7aPPFjqN6wLuxH9d8bcqssmrE7H4cvb"",""data_hash"":""2f98f57c4149fdfed2b73cbd821226fe417ef5ed49d8f836a37b31edf14dea47""}}",,,,,Some(514),cy2/n0/a1:dy8971134676473/n220807337570898/a28653074063371:sy156770300966308/n1482461784403994/a27102517904169,c0:d1:s1 -gov_action1t87n2vjnavthuggyarerafxx8c7n9mu4c7r96qlfp5uggsjdc8dsqymg588,59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db,0,,100000000000,2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23,510,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23""}},""gov_action_id"":{""transaction_id"":""59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://c-ipfs-gw.nmkr.io/ipfs/QmXdfDSSkR8TYBntMT4nuTL9sE9E44FJnpWVpaY8ZTfwjj"",""data_hash"":""d4efa9e0c3d80f5be35def08551eaf5aef17eae832fdb835e5f4b208d98f3dff""}}",,,,,Some(517),cy3/n0/a3:dy239372032038196/n2028935641783/a8814655430284:sy875771108730453/n2218103279783/a81439064616232,c0:d1:s1 -gov_action10lty9xka3unprtvdfrqvcjgsz33sjwhv9p06afqzar8au782trtsq7dhd95,7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7,0,,100000000000,7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48,514,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48""}},""gov_action_id"":{""transaction_id"":""7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/bigpey/CardanoGovernance/refs/heads/main/infoAction3.jsonld"",""data_hash"":""e68cba056c70187e475f05317ce54eeade3376d5b744b32f2c60492b4984b4bf""}}",,,,,Some(521),cy0/n3/a2:dy144561249982546/n310448207627996/a104407616914975:sy544996208583580/n1043351751274733/a95232889230901,c0:d1:s1 -gov_action1286ft23r7jem825s4l0y5rn8sgam0tz2ce04l7a38qmnhp3l9a6qqn850dw,51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,518,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-21-ppu/metadata.jsonld"",""data_hash"":""3e6b1083a637a740d5b84bb6edf1a5119b81440b31ea84907311b6543ebd39eb""}}",,,,,Some(525),cy0/n5/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 -gov_action1k2jertppnnndejjcglszfqq4yzw8evzrd2nt66rr6rqlz54xp0zsq05ecsn,b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,519,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1,100181,726,719,0,1,100181,726,719,0,1,100181,726,719,0,1,107878,680,0,1,95336,1,281145,18848,0,1,180194,159,1,1,158519,8942,0,1,159378,8813,0,1,107490,3298,1,106057,655,1,1964219,24520,3]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-04-ppu/metadata.jsonld"",""data_hash"":""94deb036c455e4064f7ed4162edbdb7d892ad264094df9a26fd61b5b130d100f""}}",,Some(525),Some(526),,,cy5/n0/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 -gov_action1llcd7ezdx299xeep9azm4dvsvz7783qfrhykcu3sv2ykl4sewv2qq4myfpk,fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,522,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-19-infohf/metadata.jsonld"",""data_hash"":""93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e""}}",,,,,Some(529),cy6/n0/a1:dy1662309604816396/n3240479257792/a104183585725135:sy1628124195597550/n0/a0,c0:d1:s1 -gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525,0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,529,,HardForkInitiation,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9"",""action_index"":0},""gov_action"":{""HardForkInitiation"":{""previous_action_id"":null,""protocol_version"":{""major"":10,""minor"":0}}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-30-hf10/metadata.jsonld"",""data_hash"":""8a1bd37caa6b914a8b569adb63a0f41d8f159c110dc5c8409118a3f087fffb43""}}",,Some(536),Some(537),,,cy7/n0/a0:dy0/n0/a0:sy14409193713024022/n62248540964906/a917440954183897,c2/3:d3/5:s51/100 -gov_action133jnaewfsq8x6v08ndd87l2yqryp63r30t2dkceacxx5cply5n7sqzlcyqf,8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,537,,NewConstitution,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"",""action_index"":0},""gov_action"":{""NewConstitution"":{""previous_action_id"":null,""new_constitution"":{""anchor"":{""url"":""ipfs://bafkreiazhhawe7sjwuthcfgl3mmv2swec7sukvclu3oli7qdyz4uhhuvmy"",""data_hash"":""2a61e2f4b63442978140c77a70daab3961b22b12b63b13949a390c097214d1c5""},""guardrail_script"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}}},""anchor"":{""url"":""ipfs://bafkreiehcekhhsq34ccezwn46brg3euj6tbs4g4yjkav34ukqvbnzaya2a"",""data_hash"":""d085e5af96521ae2670400e76c3a1e4b4eb902139ddaa83bde7580e7e9d7ddec""}}",,Some(541),Some(542),,,cy7/n0/a0:dy3147155733843689/n80277670032839/a173769211483602:sy0/n0/a0,c2/3:d3/4:s0 -gov_action1js2s9v92zpxg2rge0y3jt9zy626he2m67x9kx9phw4r942kvsn6sqfym0d7,941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5,0,"transaction: b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5, action_index: 0",100000000000,646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59,539,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59""}},""gov_action_id"":{""transaction_id"":""941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""protocol_param_update"":{""treasury_growth_rate"":[1,10]},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://QmcKQggcpouuhAAvUYGDzoKgMwbZSkWqiEeE6c67SJ3kEq"",""data_hash"":""9b2438f0032a0c24ed62d12d6bdb79b47e2bd0c4d2dd4f4936c055ead7109caf""}}",,,,,Some(546),cy2/n5/a0:dy939990053651256/n1965627054695765/a284188967365253:sy0/n0/a0,c2/3:d67/100:s0 -gov_action12meeq4r43udremwpm6fzt4nt7fctvt0ah7798x036m2r4nhlccmqqhmr9wx,56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,542,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiada4nn5eaezg43esieduks6l57vzkjdo2yfby7yxv6jrat7ilrdq"",""data_hash"":""b160033b47dfc31885c297c55ba6b68afaf7561da3070eced93d84ad70d8f5b3""}}",,,,,Some(549),cy3/n1/a3:dy2849267784746103/n47404553333753/a58248658178512:sy646730366107541/n0/a2618952257730,c0:d1:s1 -gov_action10ueqgzwenxr39le68n0se9peu92r7gm2846xwehh3u0ahc0qd0uqqyljxu5,7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8,0,,100000000000,34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f,546,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f""}},""gov_action_id"":{""transaction_id"":""7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/blockchainada/ga/refs/heads/main/ga01.jsonld"",""data_hash"":""a2fa375274a2c5efa985a1e9811f27ea1ebf8b8dd88cdf9931a5aa856c73832a""}}",,,,,Some(553),cy1/n4/a1:dy1780269838508229/n1626018423362940/a96196729276630:sy566347694726570/n603581674443045/a879726334116,c0:d1:s1 -gov_action1nd3t833j7v5sz65k3tp9yyvztw60sjcjgcgjr37682s3m7frwrusqmd2k80,9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,547,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiaqno22swabd3kcqt2awtgwaucdzaagacoemxwadm3exrchhnfite"",""data_hash"":""973452e7c4d204c883c6a9e4c311f72ad6237e827ce05e141f3374c8a04f01bc""}}",,,,,Some(554),cy5/n1/a1:dy3555798499117719/n927833581144205/a266084892066727:sy622342555916988/n942621542016625/a10607703917013,c0:d1:s1 -gov_action10k0unljvaej0kd89w7pn0zkgdx59c7xkl0x5q78dzvdtd73u0kmqq5xl5y5,7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,554,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmRrGsZsP5R7cFYFzPXQ9vS2Ux7oTXb1ep1EciLdKqeDWY"",""data_hash"":""30f03001e623d61ae782efe922b21ef79c4a1d06b258fd773d9c762d1a42d9b9""}}",,,,,Some(561),cy6/n0/a1:dy2425490955933534/n2297474620022945/a64913595414068:sy672666725152325/n24241821569730/a888586571923,c0:d1:s1 -gov_action1h4ygjv0hjfj3lmafcm76rpdzcm8vsvj9k5wejn3npyxwxm3fesnqqw9kxxz,bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibqma7t2k4rcywvx5afukahhi3dp2so2ugh7t4ljuawhanvk7sr34"",""data_hash"":""7d2f344f3651a8372ad603abf11fcb310fb3c5154a6592591d1ff97d951156e3""}}",,,,,Some(563),cy6/n0/a1:dy4500048611264804/n31848673410621/a45099889469182:sy569746862334739/n0/a0,c0:d1:s1 -gov_action1vdlrcftd48qn2zz8egepr6xyfcmxpfz8r69k769gc5mhg662adesq9yy8pl,637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73,0,,100000000000,29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122""}},""gov_action_id"":{""transaction_id"":""637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://ipfs.io/ipfs/bafkreieu47jw2qoxmqz67qyhhj4pi7fssuth5s4mm42qleqtw5tuzs3pgu"",""data_hash"":""ec7179c11582daa390e6d0c3f3cc46b0116d96aadcc74e02aa8d8e91434ab7af""}}",,,,,Some(563),cy6/n0/a1:dy2063455667008172/n1632235923043398/a145991747762932:sy130291633488926/n257125277926045/a71298578525921,c0:d1:s1 -gov_action1fpqwxp2kxvnntr8hpkh9q9djm78ccdww7qlhg5safugh4stmcwzqql5lauu,4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384,0,,100000000000,3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364""}},""gov_action_id"":{""transaction_id"":""4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/theeldermillenial/2025-liquidity-budget/df0b26d8796b19b566008ea9eaa8f17fef2cb6d4/info.jsonld"",""data_hash"":""97df3a30b767ee5b8e2b9fde824d91d3366985243ed73c06b257c2163f9045db""}}",,,,,Some(563),cy0/n4/a1:dy212465307551433/n2228913162217302/a438473698221786:sy0/n33370675402718/a24221567758519,c0:d1:s1 -gov_action1mmalzkcxpyn33t05hml2hxpwq0ffv6uu4mhe8sv7guz5nmm4afysqlmepzl,defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmaWrgqcQS7jYyLYFpvBiamZ4mCoeasL78qaPASDaJ6dT3"",""data_hash"":""4a4c99645a68d29eab6615ac71191cc92c745f92f97cdaf47890be1bad7487a7""}}",,,,,Some(563),cy0/n7/a0:dy1814353580889176/n1176878238974779/a461607195493589:sy211863729905114/n128435026893983/a800795601962,c0:d1:s1 -gov_action1u9x73kwufaxa70lfy59g4ynwyrcsaxdcd0gxzzmh67s9fxq4j8hqqk2phgh,e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee,0,,100000000000,bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d,557,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d""}},""gov_action_id"":{""transaction_id"":""e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibeajhkes7bxjlkghkingcgltqcwazz2ya5oknveqwt5nont7tg6u"",""data_hash"":""b95d8f8e324e9863905f16dbad94c1f25b28b933ae842e6f8ce9841c8da5b197""}}",,,,,Some(564),cy6/n0/a1:dy3568747822222928/n732747387805908/a143704110191164:sy606977531362334/n42674324713788/a1734640589499,c0:d1:s1 -gov_action1vrkk4dpuss8l3z9g4uc2rmf8ks0f7j534zvz9v4k85dlc54wa3zsqq68rx0,60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,566,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,228,37,152,78,36,251,44,6,173,103,104,130,23,141,222,230,228,123,153,74,88,154,227,215,12,129,124,121],300000000000],[[241,155,234,230,252,127,234,218,108,207,130,69,84,181,227,164,152,234,177,82,5,172,146,72,195,251,153,59,95],300000000000],[[241,167,150,104,120,85,12,225,30,200,168,59,147,252,26,110,16,93,84,79,120,73,68,1,6,108,79,224,207],300000000000],[[241,135,127,87,224,189,204,129,103,233,132,222,224,82,216,221,115,70,239,252,8,255,128,162,155,4,94,26,16],500000000000],[[241,134,14,224,246,189,130,53,132,42,144,138,253,134,220,148,156,76,157,171,215,75,9,101,195,100,184,211,21],100000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreifw3qs7brjn4tdvyprnh2r343oerbdghasp5ws6ro55frbpll3dta"",""data_hash"":""d2f633b044f33117ace7cde8c045fcc930060a6dbdd083f7491148a86a3c5ebd""}}",,Some(570),Some(571),,,cy7/n0/a0:dy4093833588084653/n21189101483536/a52442655453280:sy0/n0/a0,c2/3:d67/100:s0 -gov_action1n5sn54mgf47a7men2ryq6ppx88kta4wvenz2qkl4f9v6ppje8easqxwm88m,9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b,0,,100000000000,2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0,567,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""ScriptHash"":""2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0""}},""gov_action_id"":{""transaction_id"":""9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmP9iDuML2VmoFigTJifBj87LxZ3DNnREyU27DE1MrpZDg"",""data_hash"":""b3dc422b419a0e7beee4bf594bcfd344d87e2dc593d0fef5eb1fd218c0a6137b""}}",,,,,Some(574),cy7/n0/a0:dy2832862312472265/n935246197584261/a674152156041788:sy66736422727105/n66272824647159/a0,c0:d1:s1 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlpwywvhcq,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,23,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":23},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],69459000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreid2pq5icpp77nfvdvnb5ipy3fqs77tpnls4ngxy6semzkdq7d2z7y"",""data_hash"":""5edb23193df820ab4e8334d2e12fdc57aac5f06fe9a81067aa651b3439b57119""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3926392145162793/n75355236808630/a62411838251542:sy0/n0/a0,c2/3:d67/100:s0 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqz6d98zp,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,1,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":1},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],96817080000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreigt5xy56qjxd7dl2s7u6jxec2cfxevynppvgnnjifc2wawr7md5ha"",""data_hash"":""442b57ebf94db21544475a5dbdfe57f50e648646533d31bfa329c280aebfcfe9""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3912321432502202/n23692002076694/a312701730992913:sy0/n0/a0,c2/3:d67/100:s0 -gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqqfgyy3v,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,0,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""credential"":{""AddrKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],2162096000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreidjnukg5c7u5zlkxaciy4hkxfixvtquhx6uzlqpydvrxormfqpdm4"",""data_hash"":""6611ea5602de95d463ecf28f1c4ca26ad91fe7ed499d0a1594e3c2fd528a2a62""}}",,Some(574),Some(575),,,cy5/n0/a0:dy4127174354090953/n94145593104288/a0:sy0/n0/a0,c2/3:d67/100:s0 +gov_action1zhuz5djmmmjg8f9s8pe6grfc98xg3szglums8cgm6qwancp4eytqqmpu0pr,15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916,0,,100000000000,45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7,507,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""45dee6ee5d7f631b6226d45f29da411c42fa7e816dc0948d31e0dba7""}},""gov_action_id"":{""transaction_id"":""15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmWjcHsrq9kKHZZ7aPPFjqN6wLuxH9d8bcqssmrE7H4cvb"",""data_hash"":""2f98f57c4149fdfed2b73cbd821226fe417ef5ed49d8f836a37b31edf14dea47""}}",,,,,Some(514),cy2/n0/a1:dy8971134676473/n220807337570898/a28653074063371:sy156770300966308/n1482461784403994/a27102517904169,c0:d1:s1 +gov_action1t87n2vjnavthuggyarerafxx8c7n9mu4c7r96qlfp5uggsjdc8dsqymg588,59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db,0,,100000000000,2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23,510,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""2058a6f90d7f85735fe3c0f2db06e90c25dfb06e5b1a61e67bb4fe23""}},""gov_action_id"":{""transaction_id"":""59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://c-ipfs-gw.nmkr.io/ipfs/QmXdfDSSkR8TYBntMT4nuTL9sE9E44FJnpWVpaY8ZTfwjj"",""data_hash"":""d4efa9e0c3d80f5be35def08551eaf5aef17eae832fdb835e5f4b208d98f3dff""}}",,,,,Some(517),cy3/n0/a3:dy239372032038196/n2028935641783/a8814655430284:sy875771108730453/n2218103279783/a81439064616232,c0:d1:s1 +gov_action10lty9xka3unprtvdfrqvcjgsz33sjwhv9p06afqzar8au782trtsq7dhd95,7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7,0,,100000000000,7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48,514,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""7a094354239fd5e7b24665158ff7ee2afdfabcc947ba3b64742ffa48""}},""gov_action_id"":{""transaction_id"":""7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/bigpey/CardanoGovernance/refs/heads/main/infoAction3.jsonld"",""data_hash"":""e68cba056c70187e475f05317ce54eeade3376d5b744b32f2c60492b4984b4bf""}}",,,,,Some(521),cy0/n3/a2:dy144561249982546/n310448207627996/a104407616914975:sy544996208583580/n1043351751274733/a95232889230901,c0:d1:s1 +gov_action1286ft23r7jem825s4l0y5rn8sgam0tz2ce04l7a38qmnhp3l9a6qqn850dw,51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,518,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""51f495aa23f4b3b3aa90afde4a0e67823bb7ac4ac65f5ffbb138373b863f2f74"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-21-ppu/metadata.jsonld"",""data_hash"":""3e6b1083a637a740d5b84bb6edf1a5119b81440b31ea84907311b6543ebd39eb""}}",,,,,Some(525),cy0/n5/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 +gov_action1k2jertppnnndejjcglszfqq4yzw8evzrd2nt66rr6rqlz54xp0zsq05ecsn,b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,519,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":null,""protocol_param_update"":{""cost_models_for_script_languages"":{""plutus_v1"":null,""plutus_v2"":null,""plutus_v3"":[100788,420,1,1,1000,173,0,1,1000,59957,4,1,11183,32,201305,8356,4,16000,100,16000,100,16000,100,16000,100,16000,100,16000,100,100,100,16000,100,94375,32,132994,32,61462,4,72010,178,0,1,22151,32,91189,769,4,2,85848,123203,7305,-900,1716,549,57,85848,0,1,1,1000,42921,4,2,24548,29498,38,1,898148,27279,1,51775,558,1,39184,1000,60594,1,141895,32,83150,32,15299,32,76049,1,13169,4,22100,10,28999,74,1,28999,74,1,43285,552,1,44749,541,1,33852,32,68246,32,72362,32,7243,32,7391,32,11546,32,85848,123203,7305,-900,1716,549,57,85848,0,1,90434,519,0,1,74433,32,85848,123203,7305,-900,1716,549,57,85848,0,1,1,85848,123203,7305,-900,1716,549,57,85848,0,1,955506,213312,0,2,270652,22588,4,1457325,64566,4,20467,1,4,0,141992,32,100788,420,1,1,81663,32,59498,32,20142,32,24588,32,20744,32,25933,32,24623,32,43053543,10,53384111,14333,10,43574283,26308,10,16000,100,16000,100,962335,18,2780678,6,442008,1,52538055,3756,18,267929,18,76433006,8868,18,52948122,18,1995836,36,3227919,12,901022,1,166917843,4307,36,284546,36,158221314,26549,36,74698472,36,333849714,1,254006273,72,2174038,72,2261318,64571,4,207616,8310,4,1293828,28716,63,0,1,1006041,43623,251,0,1,100181,726,719,0,1,100181,726,719,0,1,100181,726,719,0,1,107878,680,0,1,95336,1,281145,18848,0,1,180194,159,1,1,158519,8942,0,1,159378,8813,0,1,107490,3298,1,106057,655,1,1964219,24520,3]}},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-04-ppu/metadata.jsonld"",""data_hash"":""94deb036c455e4064f7ed4162edbdb7d892ad264094df9a26fd61b5b130d100f""}}",,Some(525),Some(526),,,cy5/n0/a0:dy0/n0/a0:sy0/n0/a0,c2/3:d0:s0 +gov_action1llcd7ezdx299xeep9azm4dvsvz7783qfrhykcu3sv2ykl4sewv2qq4myfpk,fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,522,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-11-19-infohf/metadata.jsonld"",""data_hash"":""93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e""}}",,,,,Some(529),cy6/n0/a1:dy1662309604816396/n3240479257792/a104183585725135:sy1628124195597550/n0/a0,c0:d1:s1 +gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525,0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,529,,HardForkInitiation,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9"",""action_index"":0},""gov_action"":{""HardForkInitiation"":{""previous_action_id"":null,""protocol_version"":{""major"":10,""minor"":0}}},""anchor"":{""url"":""https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/mainnet/2024-10-30-hf10/metadata.jsonld"",""data_hash"":""8a1bd37caa6b914a8b569adb63a0f41d8f159c110dc5c8409118a3f087fffb43""}}",,Some(536),Some(537),,,cy7/n0/a0:dy0/n0/a0:sy14409193713024022/n62248540964906/a917440954183897,c2/3:d3/5:s51/100 +gov_action133jnaewfsq8x6v08ndd87l2yqryp63r30t2dkceacxx5cply5n7sqzlcyqf,8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,537,,NewConstitution,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""8c653ee5c9800e6d31e79b5a7f7d4400c81d44717ad4db633dc18d4c07e4a4fd"",""action_index"":0},""gov_action"":{""NewConstitution"":{""previous_action_id"":null,""new_constitution"":{""anchor"":{""url"":""ipfs://bafkreiazhhawe7sjwuthcfgl3mmv2swec7sukvclu3oli7qdyz4uhhuvmy"",""data_hash"":""2a61e2f4b63442978140c77a70daab3961b22b12b63b13949a390c097214d1c5""},""guardrail_script"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}}},""anchor"":{""url"":""ipfs://bafkreiehcekhhsq34ccezwn46brg3euj6tbs4g4yjkav34ukqvbnzaya2a"",""data_hash"":""d085e5af96521ae2670400e76c3a1e4b4eb902139ddaa83bde7580e7e9d7ddec""}}",,Some(541),Some(542),,,cy7/n0/a0:dy3147155733843689/n80277670032839/a173769211483602:sy0/n0/a0,c2/3:d3/4:s0 +gov_action1js2s9v92zpxg2rge0y3jt9zy626he2m67x9kx9phw4r942kvsn6sqfym0d7,941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5,0,"transaction: b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5, action_index: 0",100000000000,646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59,539,,ParameterChange,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""646c9e5f7484e8aeceba94566b73b8b50394eb6bfb54f67ac5885d59""}},""gov_action_id"":{""transaction_id"":""941502b0aa104c850d197923259444d2b57cab7af18b63143775465aaacc84f5"",""action_index"":0},""gov_action"":{""ParameterChange"":{""previous_action_id"":{""transaction_id"":""b2a591ac219ce6dcca5847e0248015209c7cb0436aa6bd6863d0c1f152a60bc5"",""action_index"":0},""protocol_param_update"":{""treasury_growth_rate"":[1,10]},""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://QmcKQggcpouuhAAvUYGDzoKgMwbZSkWqiEeE6c67SJ3kEq"",""data_hash"":""9b2438f0032a0c24ed62d12d6bdb79b47e2bd0c4d2dd4f4936c055ead7109caf""}}",,,,,Some(546),cy2/n5/a0:dy939990053651256/n1965627054695765/a284188967365253:sy0/n0/a0,c2/3:d67/100:s0 +gov_action12meeq4r43udremwpm6fzt4nt7fctvt0ah7798x036m2r4nhlccmqqhmr9wx,56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,542,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""56f39054758f1a3cedc1de9225d66bf270b62dfdbfbc5399f1d6d43aceffc636"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiada4nn5eaezg43esieduks6l57vzkjdo2yfby7yxv6jrat7ilrdq"",""data_hash"":""b160033b47dfc31885c297c55ba6b68afaf7561da3070eced93d84ad70d8f5b3""}}",,,,,Some(549),cy3/n1/a3:dy2849267784746103/n47404553333753/a58248658178512:sy646730366107541/n0/a2618952257730,c0:d1:s1 +gov_action10ueqgzwenxr39le68n0se9peu92r7gm2846xwehh3u0ahc0qd0uqqyljxu5,7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8,0,,100000000000,34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f,546,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""34e02a2d8ba816a7bc1f7e337271734b200e112fe240d2d2b504113f""}},""gov_action_id"":{""transaction_id"":""7f320409d9998712ff3a3cdf0c9439e1543f236a3d746766f78f1fdbe1e06bf8"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/blockchainada/ga/refs/heads/main/ga01.jsonld"",""data_hash"":""a2fa375274a2c5efa985a1e9811f27ea1ebf8b8dd88cdf9931a5aa856c73832a""}}",,,,,Some(553),cy1/n4/a1:dy1780269838508229/n1626018423362940/a96196729276630:sy566347694726570/n603581674443045/a879726334116,c0:d1:s1 +gov_action1nd3t833j7v5sz65k3tp9yyvztw60sjcjgcgjr37682s3m7frwrusqmd2k80,9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9,0,,100000000000,11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b,547,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""11ce01cd0e4dbba24d7f99d3516ae9229f0199ed4b9315fe4693b64b""}},""gov_action_id"":{""transaction_id"":""9b62b3c632f329016a968ac25211825bb4f84b12461121c7da3aa11df92370f9"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreiaqno22swabd3kcqt2awtgwaucdzaagacoemxwadm3exrchhnfite"",""data_hash"":""973452e7c4d204c883c6a9e4c311f72ad6237e827ce05e141f3374c8a04f01bc""}}",,,,,Some(554),cy5/n1/a1:dy3555798499117719/n927833581144205/a266084892066727:sy622342555916988/n942621542016625/a10607703917013,c0:d1:s1 +gov_action10k0unljvaej0kd89w7pn0zkgdx59c7xkl0x5q78dzvdtd73u0kmqq5xl5y5,7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,554,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""7d9fc9fe4cee64fb34e57783378ac869a85c78d6fbcd4078ed131ab6fa3c7db6"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmRrGsZsP5R7cFYFzPXQ9vS2Ux7oTXb1ep1EciLdKqeDWY"",""data_hash"":""30f03001e623d61ae782efe922b21ef79c4a1d06b258fd773d9c762d1a42d9b9""}}",,,,,Some(561),cy6/n0/a1:dy2425490955933534/n2297474620022945/a64913595414068:sy672666725152325/n24241821569730/a888586571923,c0:d1:s1 +gov_action1h4ygjv0hjfj3lmafcm76rpdzcm8vsvj9k5wejn3npyxwxm3fesnqqw9kxxz,bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""bd488931f792651fefa9c6fda185a2c6cec83245b51d994e33090ce36e29cc26"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibqma7t2k4rcywvx5afukahhi3dp2so2ugh7t4ljuawhanvk7sr34"",""data_hash"":""7d2f344f3651a8372ad603abf11fcb310fb3c5154a6592591d1ff97d951156e3""}}",,,,,Some(563),cy6/n0/a1:dy4500048611264804/n31848673410621/a45099889469182:sy569746862334739/n0/a0,c0:d1:s1 +gov_action1vdlrcftd48qn2zz8egepr6xyfcmxpfz8r69k769gc5mhg662adesq9yy8pl,637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73,0,,100000000000,29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""29b3155178e987f4eb0e8b60bb5ef4498d960145fa23156744c89122""}},""gov_action_id"":{""transaction_id"":""637e3c256da9c1350847ca3211e8c44e3660a4471e8b6f68a8c537746b4aeb73"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://ipfs.io/ipfs/bafkreieu47jw2qoxmqz67qyhhj4pi7fssuth5s4mm42qleqtw5tuzs3pgu"",""data_hash"":""ec7179c11582daa390e6d0c3f3cc46b0116d96aadcc74e02aa8d8e91434ab7af""}}",,,,,Some(563),cy6/n0/a1:dy2063455667008172/n1632235923043398/a145991747762932:sy130291633488926/n257125277926045/a71298578525921,c0:d1:s1 +gov_action1fpqwxp2kxvnntr8hpkh9q9djm78ccdww7qlhg5safugh4stmcwzqql5lauu,4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384,0,,100000000000,3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""3c8a5edce816ddfd8f1090488ef397c773b3affe2f770ff8e10c4364""}},""gov_action_id"":{""transaction_id"":""4840e305563327358cf70dae5015b2df8f8c35cef03f74521d4f117ac17bc384"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://raw.githubusercontent.com/theeldermillenial/2025-liquidity-budget/df0b26d8796b19b566008ea9eaa8f17fef2cb6d4/info.jsonld"",""data_hash"":""97df3a30b767ee5b8e2b9fde824d91d3366985243ed73c06b257c2163f9045db""}}",,,,,Some(563),cy0/n4/a1:dy212465307551433/n2228913162217302/a438473698221786:sy0/n33370675402718/a24221567758519,c0:d1:s1 +gov_action1mmalzkcxpyn33t05hml2hxpwq0ffv6uu4mhe8sv7guz5nmm4afysqlmepzl,defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49,0,,100000000000,eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8,556,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""eb48b72735ee0e97154ad84fdad93bb27aaf7d052e2f500e4a3bd4a8""}},""gov_action_id"":{""transaction_id"":""defbf15b06092718adf4befeab982e03d2966b9caeef93c19e470549ef75ea49"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""https://most-brass-sun.quicknode-ipfs.com/ipfs/QmaWrgqcQS7jYyLYFpvBiamZ4mCoeasL78qaPASDaJ6dT3"",""data_hash"":""4a4c99645a68d29eab6615ac71191cc92c745f92f97cdaf47890be1bad7487a7""}}",,,,,Some(563),cy0/n7/a0:dy1814353580889176/n1176878238974779/a461607195493589:sy211863729905114/n128435026893983/a800795601962,c0:d1:s1 +gov_action1u9x73kwufaxa70lfy59g4ynwyrcsaxdcd0gxzzmh67s9fxq4j8hqqk2phgh,e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee,0,,100000000000,bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d,557,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""bedc1520bf15d3da79e244954d7b837e9b5a3b9d3f7aaaa63375197d""}},""gov_action_id"":{""transaction_id"":""e14de8d9dc4f4ddf3fe9250a8a926e20f10e99b86bd0610b77d7a054981591ee"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://bafkreibeajhkes7bxjlkghkingcgltqcwazz2ya5oknveqwt5nont7tg6u"",""data_hash"":""b95d8f8e324e9863905f16dbad94c1f25b28b933ae842e6f8ce9841c8da5b197""}}",,,,,Some(564),cy6/n0/a1:dy3568747822222928/n732747387805908/a143704110191164:sy606977531362334/n42674324713788/a1734640589499,c0:d1:s1 +gov_action1vrkk4dpuss8l3z9g4uc2rmf8ks0f7j534zvz9v4k85dlc54wa3zsqq68rx0,60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45,0,,100000000000,58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e,566,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""58e8e98c65b608a9a9ebdea42f07ddb4ca898aefaa10f4d0145b995e""}},""gov_action_id"":{""transaction_id"":""60ed6ab43c840ff888a8af30a1ed27b41e9f4a91a89822b2b63d1bfc52aeec45"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,228,37,152,78,36,251,44,6,173,103,104,130,23,141,222,230,228,123,153,74,88,154,227,215,12,129,124,121],300000000000],[[241,155,234,230,252,127,234,218,108,207,130,69,84,181,227,164,152,234,177,82,5,172,146,72,195,251,153,59,95],300000000000],[[241,167,150,104,120,85,12,225,30,200,168,59,147,252,26,110,16,93,84,79,120,73,68,1,6,108,79,224,207],300000000000],[[241,135,127,87,224,189,204,129,103,233,132,222,224,82,216,221,115,70,239,252,8,255,128,162,155,4,94,26,16],500000000000],[[241,134,14,224,246,189,130,53,132,42,144,138,253,134,220,148,156,76,157,171,215,75,9,101,195,100,184,211,21],100000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreifw3qs7brjn4tdvyprnh2r343oerbdghasp5ws6ro55frbpll3dta"",""data_hash"":""d2f633b044f33117ace7cde8c045fcc930060a6dbdd083f7491148a86a3c5ebd""}}",,Some(570),Some(571),,,cy7/n0/a0:dy4093833588084653/n21189101483536/a52442655453280:sy0/n0/a0,c2/3:d67/100:s0 +gov_action1n5sn54mgf47a7men2ryq6ppx88kta4wvenz2qkl4f9v6ppje8easqxwm88m,9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b,0,,100000000000,2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0,567,,Information,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""ScriptHash"":""2bf8a40b8101c071d7f1c1ba3736c2d3a9667fb13e35dc1864f170d0""}},""gov_action_id"":{""transaction_id"":""9d213a57684d7ddf6f3350c80d042639ecbed5ccccc4a05bf54959a086593e7b"",""action_index"":0},""gov_action"":""Information"",""anchor"":{""url"":""ipfs://QmP9iDuML2VmoFigTJifBj87LxZ3DNnREyU27DE1MrpZDg"",""data_hash"":""b3dc422b419a0e7beee4bf594bcfd344d87e2dc593d0fef5eb1fd218c0a6137b""}}",,,,,Some(574),cy7/n0/a0:dy2832862312472265/n935246197584261/a674152156041788:sy66736422727105/n66272824647159/a0,c0:d1:s1 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlpwywvhcq,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,23,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":23},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],69459000000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreid2pq5icpp77nfvdvnb5ipy3fqs77tpnls4ngxy6semzkdq7d2z7y"",""data_hash"":""5edb23193df820ab4e8334d2e12fdc57aac5f06fe9a81067aa651b3439b57119""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3926392145162793/n75355236808630/a62411838251542:sy0/n0/a0,c2/3:d67/100:s0 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqz6d98zp,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,1,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":1},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],96817080000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreigt5xy56qjxd7dl2s7u6jxec2cfxevynppvgnnjifc2wawr7md5ha"",""data_hash"":""442b57ebf94db21544475a5dbdfe57f50e648646533d31bfa329c280aebfcfe9""}}",,Some(574),Some(575),,,cy5/n0/a0:dy3912321432502202/n23692002076694/a312701730992913:sy0/n0/a0,c2/3:d67/100:s0 +gov_action13tfag48nf94rtjcdq7c06vhkslmxxw9h6c88sl7q5g5nnewcsvlqqfgyy3v,8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e,0,,100000000000,192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba,570,,TreasuryWithdrawals,"{""deposit"":100000000000,""reward_account"":{""network"":""Mainnet"",""payload"":{""StakeKeyHash"":""192688a334130db2b51aedea594301010b0d1d2e9a86a460932520ba""}},""gov_action_id"":{""transaction_id"":""8ad3d454f3496a35cb0d07b0fd32f687f66338b7d60e787fc0a22939e5d8833e"",""action_index"":0},""gov_action"":{""TreasuryWithdrawals"":{""rewards"":[[[241,133,131,133,126,74,18,255,225,230,246,65,161,120,90,15,47,3,108,86,92,251,230,255,157,184,229,164,105],2162096000000]],""script_hash"":[250,36,251,48,81,38,128,92,242,22,76,22,29,133,42,14,115,48,207,152,143,31,229,88,207,125,74,100]}},""anchor"":{""url"":""ipfs://bafkreidjnukg5c7u5zlkxaciy4hkxfixvtquhx6uzlqpydvrxormfqpdm4"",""data_hash"":""6611ea5602de95d463ecf28f1c4ca26ad91fe7ed499d0a1594e3c2fd528a2a62""}}",,Some(574),Some(575),,,cy5/n0/a0:dy4127174354090953/n94145593104288/a0:sy0/n0/a0,c2/3:d67/100:s0 diff --git a/modules/governance_state/src/conway_voting.rs b/modules/governance_state/src/conway_voting.rs index 3750cc00..049cd982 100644 --- a/modules/governance_state/src/conway_voting.rs +++ b/modules/governance_state/src/conway_voting.rs @@ -1,10 +1,10 @@ use crate::voting_state::VotingRegistrationState; use acropolis_common::protocol_params::ConwayParams; use acropolis_common::{ - BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, GovActionId, GovernanceAction, - GovernanceOutcome, GovernanceOutcomeVariant, Lovelace, PoolId, ProposalProcedure, - SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Vote, VoteCount, VoteResult, Voter, - VotingOutcome, VotingProcedure, + AddrKeyhash, BlockInfo, DRepCredential, DelegatedStake, EnactStateElem, GovActionId, + GovernanceAction, GovernanceOutcome, GovernanceOutcomeVariant, Lovelace, PoolId, + ProposalProcedure, ScriptHash, SingleVoterVotes, TreasuryWithdrawalsAction, TxHash, Vote, + VoteCount, VoteResult, Voter, VotingOutcome, VotingProcedure, }; use anyhow::{anyhow, bail, Result}; use hex::ToHex; @@ -253,22 +253,30 @@ impl ConwayVoting { if tracing::enabled!(tracing::Level::DEBUG) { debug!( "Vote for {action_id}, epoch start {new_epoch}: {voter} = {:?}", - drep_stake.get(&DRepCredential::AddrKeyHash(key.clone())) + drep_stake.get(&DRepCredential::AddrKeyHash(AddrKeyhash::from( + key.into_inner() + ))) ); } drep_stake - .get(&DRepCredential::AddrKeyHash(key.clone())) + .get(&DRepCredential::AddrKeyHash(AddrKeyhash::from( + key.into_inner(), + ))) .inspect(|v| *vd += *v); } Voter::DRepScript(script) => { if tracing::enabled!(tracing::Level::DEBUG) { debug!( "Vote for {action_id}, epoch start {new_epoch}: {voter} = {:?}", - drep_stake.get(&DRepCredential::ScriptHash(script.clone())) + drep_stake.get(&DRepCredential::ScriptHash(ScriptHash::from( + script.into_inner() + ))) ); } drep_stake - .get(&DRepCredential::ScriptHash(script.clone())) + .get(&DRepCredential::ScriptHash(ScriptHash::from( + script.into_inner(), + ))) .inspect(|v| *vd += *v); } Voter::StakePoolKey(pool) => { diff --git a/modules/governance_state/src/conway_voting_test.rs b/modules/governance_state/src/conway_voting_test.rs index ba42f1c9..eb070bdc 100644 --- a/modules/governance_state/src/conway_voting_test.rs +++ b/modules/governance_state/src/conway_voting_test.rs @@ -3,9 +3,11 @@ mod tests { use crate::conway_voting::ConwayVoting; use crate::voting_state::VotingRegistrationState; use acropolis_common::{ - protocol_params::ProtocolParams, rational_number::RationalNumber, Credential, - DRepCredential, DelegatedStake, GovActionId, KeyHash, Lovelace, PoolId, ProposalProcedure, - SingleVoterVotes, TxHash, Vote, VoteCount, VoteResult, Voter, VotingProcedure, + protocol_params::ProtocolParams, rational_number::RationalNumber, + ConstitutionalCommitteeKeyHash, ConstitutionalCommitteeScriptHash, Credential, + DRepCredential, DRepScriptHash, DelegatedStake, DrepKeyHash, GovActionId, KeyHash, + Lovelace, PoolId, ProposalProcedure, SingleVoterVotes, TxHash, Vote, VoteCount, VoteResult, + Voter, VotingProcedure, }; use anyhow::{anyhow, bail, Result}; @@ -56,11 +58,15 @@ mod tests { pub fn to_voter(&self) -> Result { let key = self.1; match &self.0 { - 0 => Ok(Voter::DRepKey(key)), - 1 => Ok(Voter::DRepScript(key)), + 0 => Ok(Voter::DRepKey(DrepKeyHash::from(key))), + 1 => Ok(Voter::DRepScript(DRepScriptHash::from(key))), 2 => Ok(Voter::StakePoolKey(PoolId::from(key))), - 3 => Ok(Voter::ConstitutionalCommitteeKey(key)), - 4 => Ok(Voter::ConstitutionalCommitteeScript(key)), + 3 => Ok(Voter::ConstitutionalCommitteeKey( + ConstitutionalCommitteeKeyHash::from(key), + )), + 4 => Ok(Voter::ConstitutionalCommitteeScript( + ConstitutionalCommitteeScriptHash::from(key), + )), _ => bail!("Unknown voter key type {}", self.0), } } From d181f1c204b55b53504afaf6f82d0fda2cdb8a93 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 15:05:30 -0700 Subject: [PATCH 16/20] Refactor: Update hash type definitions and align associated conversions --- codec/src/map_parameters.rs | 10 ++++------ common/src/types.rs | 24 ++++++++++++++---------- modules/stake_delta_filter/src/utils.rs | 6 +++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 31af54ca..5e70297c 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -37,16 +37,14 @@ pub fn to_hash(pallas_hash: &pallas_primitives::Hash) -> Hash /// Convert a Pallas Hash reference to an Acropolis Hash (owned) /// Works for any hash size N -pub fn genesis_to_hash(pallas_hash: &pallas_primitives::Genesishash) -> Hash { - Hash::try_from(pallas_hash.as_ref()).unwrap() +pub fn genesis_to_hash(pallas_hash: &pallas_primitives::Genesishash) -> GenesisKeyhash { + GenesisKeyhash::try_from(pallas_hash.as_ref()).unwrap() } /// Convert a Pallas Hash reference to an Acropolis Hash (owned) /// Works for any hash size N -pub fn genesis_delegate_to_hash( - pallas_hash: &pallas_primitives::GenesisDelegateHash, -) -> Hash { - Hash::try_from(pallas_hash.as_ref()).unwrap() +pub fn genesis_delegate_to_hash(pallas_hash: &pallas_primitives::GenesisDelegateHash) -> PoolId { + PoolId::try_from(pallas_hash.as_ref()).unwrap() } /// Convert a Pallas Hash<28> reference to an Acropolis PoolId diff --git a/common/src/types.rs b/common/src/types.rs index a4bfd1ff..a184c4be 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -450,7 +450,7 @@ pub type ScriptHash = KeyHash; pub type AddrKeyhash = KeyHash; /// Script identifier -pub type GenesisKeyhash = Vec; +pub type GenesisKeyhash = Hash<32>; declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); @@ -982,10 +982,10 @@ pub struct SPORewards { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GenesisKeyDelegation { /// Genesis hash - pub genesis_hash: KeyHash, + pub genesis_hash: GenesisKeyhash, /// Genesis delegate hash - pub genesis_delegate_hash: KeyHash, + pub genesis_delegate_hash: PoolId, /// VRF key hash pub vrf_key_hash: VrfKeyHash, @@ -1678,19 +1678,23 @@ pub enum Voter { StakePoolKey(PoolId), } -impl Display for Voter { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let bech32 = match self { +impl Voter { + pub fn to_bech32(&self) -> Result { + match self { Voter::ConstitutionalCommitteeKey(h) => h.to_bech32(), Voter::ConstitutionalCommitteeScript(s) => s.to_bech32(), Voter::DRepKey(k) => k.to_bech32(), Voter::DRepScript(s) => s.to_bech32(), Voter::StakePoolKey(k) => k.to_bech32(), - }; + } + } +} - match bech32 { - Ok(s) => write!(f, "{}", s), - Err(e) => write!(f, "", e), +impl Display for Voter { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self.to_bech32() { + Ok(addr) => write!(f, "{}", addr), + Err(e) => write!(f, "", e), } } } diff --git a/modules/stake_delta_filter/src/utils.rs b/modules/stake_delta_filter/src/utils.rs index 10852013..e920d159 100644 --- a/modules/stake_delta_filter/src/utils.rs +++ b/modules/stake_delta_filter/src/utils.rs @@ -429,15 +429,15 @@ mod test { } } - pub fn script_to_hash(pallas_hash: ScriptHash) -> Hash { + pub fn script_to_hash(pallas_hash: ScriptHash) -> Hash<28> { pallas_hash.as_ref().try_into().unwrap() } - pub fn stake_to_hash(pallas_hash: StakeKeyHash) -> Hash { + pub fn stake_to_hash(pallas_hash: StakeKeyHash) -> Hash<28> { pallas_hash.as_ref().try_into().unwrap() } - pub fn payment_to_hash(pallas_hash: PaymentKeyHash) -> Hash { + pub fn payment_to_hash(pallas_hash: PaymentKeyHash) -> Hash<28> { pallas_hash.as_ref().try_into().unwrap() } From 0dc9c03175b62afba7e22685ea6be75cc15eb318 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 17:09:53 -0700 Subject: [PATCH 17/20] Refactor: Update `GenesisKeyhash` to use consistent hash types and improve error handling in `tx_unpacker` --- codec/src/map_parameters.rs | 4 ++-- common/src/types.rs | 4 ++-- modules/tx_unpacker/src/tx_unpacker.rs | 15 +++++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/codec/src/map_parameters.rs b/codec/src/map_parameters.rs index 5e70297c..f470d3f8 100644 --- a/codec/src/map_parameters.rs +++ b/codec/src/map_parameters.rs @@ -37,8 +37,8 @@ pub fn to_hash(pallas_hash: &pallas_primitives::Hash) -> Hash /// Convert a Pallas Hash reference to an Acropolis Hash (owned) /// Works for any hash size N -pub fn genesis_to_hash(pallas_hash: &pallas_primitives::Genesishash) -> GenesisKeyhash { - GenesisKeyhash::try_from(pallas_hash.as_ref()).unwrap() +pub fn genesis_to_hash(pallas_hash: &pallas_primitives::Genesishash) -> Hash<32> { + Hash::try_from(pallas_hash.as_ref()).unwrap() } /// Convert a Pallas Hash reference to an Acropolis Hash (owned) diff --git a/common/src/types.rs b/common/src/types.rs index a184c4be..d0cc7616 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -450,7 +450,7 @@ pub type ScriptHash = KeyHash; pub type AddrKeyhash = KeyHash; /// Script identifier -pub type GenesisKeyhash = Hash<32>; +pub type GenesisKeyhash = Hash<28>; declare_hash_type!(BlockHash, 32); declare_hash_type!(TxHash, 32); @@ -982,7 +982,7 @@ pub struct SPORewards { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GenesisKeyDelegation { /// Genesis hash - pub genesis_hash: GenesisKeyhash, + pub genesis_hash: Hash<32>, /// Genesis delegate hash pub genesis_delegate_hash: PoolId, diff --git a/modules/tx_unpacker/src/tx_unpacker.rs b/modules/tx_unpacker/src/tx_unpacker.rs index c42afcc3..291dfcfe 100644 --- a/modules/tx_unpacker/src/tx_unpacker.rs +++ b/modules/tx_unpacker/src/tx_unpacker.rs @@ -49,16 +49,23 @@ impl TxUnpacker { enactment_epoch: epoch, }; - for (hash, vote) in proposals.iter() { + for (hash_bytes, vote) in proposals.iter() { + let hash = match GenesisKeyhash::try_from(hash_bytes.as_ref()) { + Ok(h) => h, + Err(e) => { + error!("Invalid genesis keyhash in protocol parameter update: {e}"); + continue; + } + }; + match map(vote) { - Ok(upd) => update.proposals.push((hash.to_vec(), upd)), - Err(e) => error!("Cannot convert alonzo protocol param update {vote:?}: {e}"), + Ok(upd) => update.proposals.push((hash, upd)), + Err(e) => error!("Cannot convert protocol param update {vote:?}: {e}"), } } dest.push(update); } - /// Main init function pub async fn init(&self, context: Arc>, config: Arc) -> Result<()> { // Get configuration From 0f551f9507839112f3e0ec8a4898c2412c8dcbc3 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 17:37:02 -0700 Subject: [PATCH 18/20] Refactor: Replace gen_delegs `Vec` with `PoolId` --- codec/src/block.rs | 8 ++++---- common/src/protocol_params.rs | 6 +++--- common/src/types.rs | 2 +- modules/accounts_state/src/monetary.rs | 4 ++-- modules/chain_store/src/chain_store.rs | 6 +++--- modules/parameters_state/src/genesis_params.rs | 8 ++++---- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/codec/src/block.rs b/codec/src/block.rs index f0b3b440..592a480f 100644 --- a/codec/src/block.rs +++ b/codec/src/block.rs @@ -1,5 +1,5 @@ use acropolis_common::{ - GenesisDelegate, HeavyDelegate, crypto::keyhash_224, queries::blocks::BlockIssuer, + GenesisDelegate, HeavyDelegate, PoolId, crypto::keyhash_224, queries::blocks::BlockIssuer, }; use pallas_primitives::byron::BlockSig::DlgSig; use pallas_traverse::MultiEraHeader; @@ -7,8 +7,8 @@ use std::collections::HashMap; pub fn map_to_block_issuer( header: &MultiEraHeader, - byron_heavy_delegates: &HashMap, HeavyDelegate>, - shelley_genesis_delegates: &HashMap, GenesisDelegate>, + byron_heavy_delegates: &HashMap, + shelley_genesis_delegates: &HashMap, ) -> Option { match header.issuer_vkey() { Some(vkey) => match header { @@ -16,7 +16,7 @@ pub fn map_to_block_issuer( let digest = keyhash_224(vkey); if let Some(issuer) = shelley_genesis_delegates .values() - .find(|v| v.delegate == digest.to_vec()) + .find(|v| v.delegate == digest) .map(|i| BlockIssuer::GenesisDelegate(i.clone())) { Some(issuer) diff --git a/common/src/protocol_params.rs b/common/src/protocol_params.rs index bb970609..8cc1a5a6 100644 --- a/common/src/protocol_params.rs +++ b/common/src/protocol_params.rs @@ -2,7 +2,7 @@ use crate::{ genesis_values::GenesisValues, rational_number::{ChameleonFraction, RationalNumber}, BlockHash, BlockVersionData, Committee, Constitution, CostModel, DRepVotingThresholds, Era, - ExUnitPrices, ExUnits, GenesisDelegate, HeavyDelegate, NetworkId, PoolVotingThresholds, + ExUnitPrices, ExUnits, GenesisDelegate, HeavyDelegate, NetworkId, PoolId, PoolVotingThresholds, ProtocolConsts, }; use anyhow::{bail, Result}; @@ -34,7 +34,7 @@ pub struct ByronParams { pub start_time: u64, #[serde_as(as = "Vec<(_, _)>")] - pub heavy_delegation: HashMap, HeavyDelegate>, + pub heavy_delegation: HashMap, } // @@ -131,7 +131,7 @@ pub struct ShelleyParams { pub update_quorum: u32, #[serde_as(as = "HashMap")] - pub gen_delegs: HashMap, GenesisDelegate>, + pub gen_delegs: HashMap, } #[serde_as] diff --git a/common/src/types.rs b/common/src/types.rs index d0cc7616..d97d2e45 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -1350,7 +1350,7 @@ pub struct HeavyDelegate { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct GenesisDelegate { #[serde_as(as = "Hex")] - pub delegate: Vec, + pub delegate: Hash<28>, #[serde_as(as = "Hex")] pub vrf: Vec, } diff --git a/modules/accounts_state/src/monetary.rs b/modules/accounts_state/src/monetary.rs index b1f1d9d0..76ad9584 100644 --- a/modules/accounts_state/src/monetary.rs +++ b/modules/accounts_state/src/monetary.rs @@ -108,11 +108,11 @@ fn calculate_monetary_expansion( mod tests { use super::*; use acropolis_common::rational_number::rational_number_from_f32; - use acropolis_common::NetworkId; use acropolis_common::{ protocol_params::{Nonce, NonceVariant, ProtocolVersion, ShelleyProtocolParams}, GenesisDelegate, }; + use acropolis_common::{NetworkId, PoolId}; use chrono::{DateTime, Utc}; use std::collections::HashMap; @@ -175,7 +175,7 @@ mod tests { slots_per_kes_period: 129600, system_start: DateTime::::default(), update_quorum: 5, - gen_delegs: HashMap::, GenesisDelegate>::new(), + gen_delegs: HashMap::::new(), } } diff --git a/modules/chain_store/src/chain_store.rs b/modules/chain_store/src/chain_store.rs index 22125943..a358b895 100644 --- a/modules/chain_store/src/chain_store.rs +++ b/modules/chain_store/src/chain_store.rs @@ -12,7 +12,7 @@ use acropolis_common::{ }, queries::misc::Order, state_history::{StateHistory, StateHistoryStore}, - BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, TxHash, + BechOrdAddress, BlockHash, GenesisDelegate, HeavyDelegate, PoolId, TxHash, }; use anyhow::{bail, Result}; use caryatid_sdk::{module, Context, Module}; @@ -525,8 +525,8 @@ impl ChainStore { #[derive(Default, Debug, Clone)] pub struct State { - pub byron_heavy_delegates: HashMap, HeavyDelegate>, - pub shelley_genesis_delegates: HashMap, GenesisDelegate>, + pub byron_heavy_delegates: HashMap, + pub shelley_genesis_delegates: HashMap, } impl State { diff --git a/modules/parameters_state/src/genesis_params.rs b/modules/parameters_state/src/genesis_params.rs index 19a5323b..f0561b17 100644 --- a/modules/parameters_state/src/genesis_params.rs +++ b/modules/parameters_state/src/genesis_params.rs @@ -3,7 +3,7 @@ use acropolis_common::{ protocol_params::{AlonzoParams, BabbageParams, ByronParams, ConwayParams, ShelleyParams}, rational_number::{rational_number_from_f32, RationalNumber}, Anchor, BlockVersionData, Committee, Constitution, CostModel, Credential, DRepVotingThresholds, - Era, HeavyDelegate, PoolVotingThresholds, ProtocolConsts, SoftForkRule, TxFeePolicy, + Era, HeavyDelegate, PoolId, PoolVotingThresholds, ProtocolConsts, SoftForkRule, TxFeePolicy, }; use anyhow::{anyhow, bail, Result}; use base64::prelude::*; @@ -183,13 +183,13 @@ fn map_byron(genesis: &byron::GenesisFile) -> Result { .heavy_delegation .iter() .map(|(k, v)| { - let k = hex::decode(k)?; + let k = PoolId::try_from(decode(k)?)?; let v = HeavyDelegate { - cert: hex::decode(v.cert.clone())?, + cert: decode(v.cert.clone())?, delegate_pk: BASE64_STANDARD.decode(v.delegate_pk.clone())?, issuer_pk: BASE64_STANDARD.decode(v.issuer_pk.clone())?, }; - Ok::<(Vec, HeavyDelegate), anyhow::Error>((k, v)) + Ok::<(PoolId, HeavyDelegate), anyhow::Error>((k, v)) }) .collect::>()?; Ok(ByronParams { From 064e38bb1756d05d782ebd55368e44a3f6a64856 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Thu, 30 Oct 2025 17:48:22 -0700 Subject: [PATCH 19/20] Refactor: Replace `Vec` with `PoolId` and add Bech32 (de)serialization support --- common/src/serialization.rs | 25 ++++++++++++++++++- .../rest_blockfrost/src/handlers/epochs.rs | 2 +- modules/rest_blockfrost/src/types.rs | 4 +-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/common/src/serialization.rs b/common/src/serialization.rs index 8bbd57bf..709cfdf6 100644 --- a/common/src/serialization.rs +++ b/common/src/serialization.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use crate::PoolId; use anyhow::anyhow; use bech32::{Bech32, Hrp}; use serde::{ser::SerializeMap, Deserialize, Serializer}; @@ -60,7 +61,29 @@ impl HrpPrefix for AddrPrefix { // Generic Bech32 converter with HRP parameter pub struct DisplayFromBech32(PhantomData); -// Serialization implementation +// PoolID serialization implementation +impl SerializeAs for DisplayFromBech32 { + fn serialize_as(source: &PoolId, serializer: S) -> Result + where + S: Serializer, + { + let bech32_string = source.to_bech32().map_err(serde::ser::Error::custom)?; + serializer.serialize_str(&bech32_string) + } +} + +// PoolID deserialization implementation +impl<'de> DeserializeAs<'de, PoolId> for DisplayFromBech32 { + fn deserialize_as(deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + PoolId::from_bech32(&s).map_err(serde::de::Error::custom) + } +} + +// Vec serialization implementation impl SerializeAs> for DisplayFromBech32 where PREFIX: HrpPrefix, diff --git a/modules/rest_blockfrost/src/handlers/epochs.rs b/modules/rest_blockfrost/src/handlers/epochs.rs index 6eab93f0..089bf972 100644 --- a/modules/rest_blockfrost/src/handlers/epochs.rs +++ b/modules/rest_blockfrost/src/handlers/epochs.rs @@ -494,7 +494,7 @@ pub async fn handle_epoch_total_stakes_blockfrost( .to_string() .map_err(|e| anyhow::anyhow!("Failed to convert stake address to string: {e}"))?; Ok(SPDDByEpochItemRest { - pool_id: pool_id.to_vec(), + pool_id, stake_address, amount, }) diff --git a/modules/rest_blockfrost/src/types.rs b/modules/rest_blockfrost/src/types.rs index 81e51040..8309d747 100644 --- a/modules/rest_blockfrost/src/types.rs +++ b/modules/rest_blockfrost/src/types.rs @@ -7,7 +7,7 @@ use acropolis_common::{ rest_helper::ToCheckedF64, serialization::{DisplayFromBech32, PoolPrefix}, AssetAddressEntry, AssetMetadataStandard, AssetMintRecord, KeyHash, PolicyAsset, - PoolEpochState, PoolUpdateAction, Relay, TxHash, Vote, VrfKeyHash, + PoolEpochState, PoolId, PoolUpdateAction, Relay, TxHash, Vote, VrfKeyHash, }; use anyhow::Result; use num_traits::ToPrimitive; @@ -63,7 +63,7 @@ pub struct BlockInfoREST(pub BlockInfo); pub struct SPDDByEpochItemRest { pub stake_address: String, #[serde_as(as = "DisplayFromBech32")] - pub pool_id: Vec, + pub pool_id: PoolId, #[serde_as(as = "DisplayFromStr")] pub amount: u64, } From dc38a7100e3b7a845e8ba993919e6ebc88c538f6 Mon Sep 17 00:00:00 2001 From: Matthew Hounslow Date: Fri, 31 Oct 2025 08:30:06 -0700 Subject: [PATCH 20/20] Refactor: Replace `KeyHash` with `PoolId` for verifier.rs --- modules/accounts_state/src/rewards.rs | 9 ++++----- modules/accounts_state/src/verifier.rs | 13 ++++++++----- .../src/immutable_historical_account_store.rs | 6 ++++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/modules/accounts_state/src/rewards.rs b/modules/accounts_state/src/rewards.rs index ede2885f..fb5b6f64 100644 --- a/modules/accounts_state/src/rewards.rs +++ b/modules/accounts_state/src/rewards.rs @@ -2,10 +2,9 @@ use crate::snapshot::{Snapshot, SnapshotSPO}; use acropolis_common::{ - protocol_params::ShelleyParams, rational_number::RationalNumber, Lovelace, PoolId, SPORewards, - StakeAddress, + protocol_params::ShelleyParams, rational_number::RationalNumber, Lovelace, PoolId, RewardType, + SPORewards, StakeAddress, }; -use acropolis_common::{PoolId, RewardType}; use anyhow::{bail, Result}; use bigdecimal::{BigDecimal, One, ToPrimitive, Zero}; use std::cmp::min; @@ -389,7 +388,7 @@ fn calculate_spo_rewards( account: delegator_stake_address.clone(), rtype: RewardType::Member, amount: to_pay, - pool: operator_id.to_vec(), + pool: *operator_id, }); total_paid += to_pay; delegators_paid += 1; @@ -407,7 +406,7 @@ fn calculate_spo_rewards( account: spo.reward_account.clone(), rtype: RewardType::Leader, amount: spo_benefit, - pool: operator_id.to_vec(), + pool: *operator_id, }); } else { info!( diff --git a/modules/accounts_state/src/verifier.rs b/modules/accounts_state/src/verifier.rs index 34b114c0..b3f162d2 100644 --- a/modules/accounts_state/src/verifier.rs +++ b/modules/accounts_state/src/verifier.rs @@ -1,7 +1,7 @@ //! Verification of calculated values against captured CSV from Haskell node / DBSync use crate::rewards::{RewardDetail, RewardsResult}; use crate::state::Pots; -use acropolis_common::{KeyHash, RewardType, StakeAddress}; +use acropolis_common::{PoolId, RewardType, StakeAddress}; use hex::FromHex; use itertools::EitherOrBoth::{Both, Left, Right}; use itertools::Itertools; @@ -131,7 +131,7 @@ impl Verifier { }; // Expect CSV header: spo,address,type,amount - let mut expected_rewards: BTreeMap> = BTreeMap::new(); + let mut expected_rewards: BTreeMap> = BTreeMap::new(); for result in reader.deserialize() { let (spo, address, rtype, amount): (String, String, String, u64) = match result { Ok(row) => row, @@ -141,10 +141,13 @@ impl Verifier { } }; - let Ok(spo) = Vec::from_hex(&spo) else { - error!("Bad hex in {path} for SPO: {spo} - skipping"); + let Some(spo) = + Vec::from_hex(&spo).ok().and_then(|bytes| PoolId::try_from(bytes).ok()) + else { + error!("Bad hex/SPO in {path} for SPO: {spo} - skipping"); continue; }; + let Ok(account) = Vec::from_hex(&address) else { error!("Bad hex in {path} for address: {address} - skipping"); continue; @@ -167,7 +170,7 @@ impl Verifier { continue; }; - expected_rewards.entry(spo.clone()).or_default().push(RewardDetail { + expected_rewards.entry(spo).or_default().push(RewardDetail { account: stake_address, rtype, amount, diff --git a/modules/historical_accounts_state/src/immutable_historical_account_store.rs b/modules/historical_accounts_state/src/immutable_historical_account_store.rs index b19dd7f6..74fa0f5b 100644 --- a/modules/historical_accounts_state/src/immutable_historical_account_store.rs +++ b/modules/historical_accounts_state/src/immutable_historical_account_store.rs @@ -153,8 +153,10 @@ impl ImmutableHistoricalAccountStore { &self, account: &StakeAddress, ) -> Result>> { - let mut immutable_rewards = - self.collect_partition::(&self.rewards_history, account.get_hash())?; + let mut immutable_rewards = self.collect_partition::( + &self.rewards_history, + account.get_hash().as_ref(), + )?; self.merge_pending( account,