|
| 1 | +//! Messages representing Protocol Configurations converted into CBOR format, for Cardano chain datum |
| 2 | +
|
| 3 | +use anyhow::Context; |
| 4 | +use fixed::types::U8F24; |
| 5 | +use hex::FromHex; |
| 6 | +use serde::{Deserialize, Serialize}; |
| 7 | +use std::collections::BTreeSet; |
| 8 | +use thiserror::Error; |
| 9 | + |
| 10 | +use mithril_common::{ |
| 11 | + StdError, |
| 12 | + entities::{ |
| 13 | + BlockNumber, BlockNumberOffset, CardanoBlocksTransactionsSigningConfig, |
| 14 | + CardanoTransactionsSigningConfig, Epoch, ProtocolParameters, |
| 15 | + }, |
| 16 | + messages::SignedEntityTypeDiscriminantsMessage, |
| 17 | +}; |
| 18 | + |
| 19 | +/// The cbor representation of a [ProtocolConfigurationForEpochMessage] |
| 20 | +pub type CborProtocolConfigurationForEpochMessage = String; |
| 21 | + |
| 22 | +/// Value object that represents a tag of Protocol Configuration. |
| 23 | +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] |
| 24 | +pub struct ProtocolConfigurationMarker { |
| 25 | + /// Epoch |
| 26 | + pub epoch: Epoch, |
| 27 | + |
| 28 | + /// Protocol parameters |
| 29 | + pub configuration: CborProtocolConfigurationForEpochMessage, |
| 30 | +} |
| 31 | + |
| 32 | +impl ProtocolConfigurationMarker { |
| 33 | + /// instantiate a new [ProtocolConfigurationMarker]. |
| 34 | + pub fn new( |
| 35 | + epoch: Epoch, |
| 36 | + protocol_configuration: CborProtocolConfigurationForEpochMessage, |
| 37 | + ) -> Self { |
| 38 | + ProtocolConfigurationMarker { |
| 39 | + epoch, |
| 40 | + configuration: protocol_configuration, |
| 41 | + } |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +/// Parse error |
| 46 | +#[derive(Error, Debug)] |
| 47 | +#[error("Codec parse error")] |
| 48 | +pub struct ProtocolConfigurationForEpochMessageParseError(#[source] StdError); |
| 49 | + |
| 50 | +/// Protocol cryptographic parameters Message |
| 51 | +/// |
| 52 | +/// used for the CBOR representation of [ProtocolConfigurationForEpochMessage] |
| 53 | +#[derive(Clone, Debug, Serialize, Deserialize)] |
| 54 | +pub struct ProtocolParametersMessage { |
| 55 | + /// Quorum parameter |
| 56 | + pub k: u64, |
| 57 | + |
| 58 | + /// Security parameter (number of lotteries) |
| 59 | + pub m: u64, |
| 60 | + |
| 61 | + /// f in phi(w) = 1 - (1 - f)^w, where w is the stake of a participant |
| 62 | + pub phi_f: f64, |
| 63 | +} |
| 64 | + |
| 65 | +impl ProtocolParametersMessage { |
| 66 | + /// phi_f_fixed is a fixed decimal representation of phi_f |
| 67 | + /// used for PartialEq and Hash implementation |
| 68 | + pub fn phi_f_fixed(&self) -> U8F24 { |
| 69 | + U8F24::from_num(self.phi_f) |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +impl PartialEq<ProtocolParametersMessage> for ProtocolParametersMessage { |
| 74 | + fn eq(&self, other: &ProtocolParametersMessage) -> bool { |
| 75 | + self.k == other.k && self.m == other.m && self.phi_f_fixed() == other.phi_f_fixed() |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +impl From<ProtocolParameters> for ProtocolParametersMessage { |
| 80 | + fn from(params: ProtocolParameters) -> Self { |
| 81 | + ProtocolParametersMessage { |
| 82 | + k: params.k, |
| 83 | + m: params.m, |
| 84 | + phi_f: params.phi_f, |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +/// Configuration for the signing of Cardano transactions |
| 90 | +/// |
| 91 | +/// used for the CBOR representation of [ProtocolConfigurationForEpochMessage] |
| 92 | +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] |
| 93 | +pub struct CardanoTransactionsSigningConfigMessage { |
| 94 | + /// Number of blocks to discard from the tip of the chain when importing transactions. |
| 95 | + pub security_parameter: BlockNumberOffset, |
| 96 | + |
| 97 | + /// The number of blocks between signature of the transactions. |
| 98 | + pub step: BlockNumber, |
| 99 | +} |
| 100 | + |
| 101 | +impl From<CardanoTransactionsSigningConfig> for CardanoTransactionsSigningConfigMessage { |
| 102 | + fn from(config: CardanoTransactionsSigningConfig) -> Self { |
| 103 | + CardanoTransactionsSigningConfigMessage { |
| 104 | + security_parameter: config.security_parameter, |
| 105 | + step: config.step, |
| 106 | + } |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +/// Configuration for the signing of Cardano blocks and transactions |
| 111 | +/// |
| 112 | +/// used for the CBOR representation of [ProtocolConfigurationForEpochMessage] |
| 113 | +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] |
| 114 | +pub struct CardanoBlocksTransactionsSigningConfigMessage { |
| 115 | + /// Number of blocks to discard from the tip of the chain when importing blocks and transactions. |
| 116 | + pub security_parameter: BlockNumberOffset, |
| 117 | + |
| 118 | + /// The number of blocks between signature of the blocks and transactions. |
| 119 | + pub step: BlockNumber, |
| 120 | +} |
| 121 | + |
| 122 | +impl From<CardanoBlocksTransactionsSigningConfig> |
| 123 | + for CardanoBlocksTransactionsSigningConfigMessage |
| 124 | +{ |
| 125 | + fn from(config: CardanoBlocksTransactionsSigningConfig) -> Self { |
| 126 | + CardanoBlocksTransactionsSigningConfigMessage { |
| 127 | + security_parameter: config.security_parameter, |
| 128 | + step: config.step, |
| 129 | + } |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +//A epoch configuration used for the CBOR representation in the [ProtocolConfigurationMarker] |
| 134 | +#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] |
| 135 | +/// A network configuration available for an epoch |
| 136 | +pub struct ProtocolConfigurationForEpochMessage { |
| 137 | + /// Cryptographic protocol parameters (`k`, `m` and `phi_f`) |
| 138 | + pub protocol_parameters: ProtocolParametersMessage, |
| 139 | + |
| 140 | + /// List of available types of certifications |
| 141 | + pub enabled_signed_entity_types: BTreeSet<SignedEntityTypeDiscriminantsMessage>, |
| 142 | + |
| 143 | + /// Signing configuration for Cardano transactions |
| 144 | + pub cardano_transactions: Option<CardanoTransactionsSigningConfigMessage>, |
| 145 | + |
| 146 | + /// Signing configuration for Cardano blocks and transactions |
| 147 | + pub cardano_blocks_transactions: Option<CardanoBlocksTransactionsSigningConfigMessage>, |
| 148 | +} |
| 149 | + |
| 150 | +impl ProtocolConfigurationForEpochMessage { |
| 151 | + /// Serialize the structure to a CBOR bytes representation. |
| 152 | + fn to_cbor_bytes(&self) -> Result<Vec<u8>, ProtocolConfigurationForEpochMessageParseError> { |
| 153 | + let mut cursor = std::io::Cursor::new(Vec::new()); |
| 154 | + ciborium::ser::into_writer(&self, &mut cursor) |
| 155 | + .with_context(|| "ProtocolConfigurationForEpoch can not serialize data to cbor") |
| 156 | + .map_err(ProtocolConfigurationForEpochMessageParseError)?; |
| 157 | + |
| 158 | + Ok(cursor.into_inner()) |
| 159 | + } |
| 160 | + |
| 161 | + /// Serialize the structure to a CBOR hex representation. |
| 162 | + pub fn to_cbor_hex(&self) -> Result<String, ProtocolConfigurationForEpochMessageParseError> { |
| 163 | + Ok(hex::encode(self.to_cbor_bytes()?)) |
| 164 | + } |
| 165 | + |
| 166 | + /// Deserialize a type `T: Serialize + DeserializeOwned` from CBOR bytes representation. |
| 167 | + fn from_cbor_bytes( |
| 168 | + bytes: &[u8], |
| 169 | + ) -> Result<Self, ProtocolConfigurationForEpochMessageParseError> { |
| 170 | + let mut cursor = std::io::Cursor::new(&bytes); |
| 171 | + let a: Self = ciborium::de::from_reader(&mut cursor) |
| 172 | + .with_context(|| "ProtocolConfigurationForEpoch can not unserialize cbor data") |
| 173 | + .map_err(ProtocolConfigurationForEpochMessageParseError)?; |
| 174 | + |
| 175 | + Ok(a) |
| 176 | + } |
| 177 | + |
| 178 | + /// Deserialize a type `T: Serialize + DeserializeOwned` from CBOR hex representation. |
| 179 | + pub fn from_cbor_hex( |
| 180 | + hex: &str, |
| 181 | + ) -> Result<Self, ProtocolConfigurationForEpochMessageParseError> { |
| 182 | + let hex_vector = Vec::from_hex(hex) |
| 183 | + .with_context(|| "ProtocolConfigurationForEpochMessage can not unserialize hex data") |
| 184 | + .map_err(ProtocolConfigurationForEpochMessageParseError)?; |
| 185 | + |
| 186 | + Self::from_cbor_bytes(&hex_vector) |
| 187 | + .with_context(|| "ProtocolConfigurationForEpochMessage can not unserialize cbor data") |
| 188 | + .map_err(ProtocolConfigurationForEpochMessageParseError) |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +#[cfg(test)] |
| 193 | +mod tests { |
| 194 | + use mithril_common::test::double::Dummy; |
| 195 | + |
| 196 | + use super::*; |
| 197 | + |
| 198 | + #[test] |
| 199 | + fn to_cbor_from_cbor_conversion() { |
| 200 | + let mithril_network_configuration_for_epoch = ProtocolConfigurationForEpochMessage::dummy(); |
| 201 | + let cbor = mithril_network_configuration_for_epoch.to_cbor_hex().unwrap(); |
| 202 | + let mithril_network_configuration_for_epoch_from_cbor = |
| 203 | + ProtocolConfigurationForEpochMessage::from_cbor_hex(&cbor).unwrap(); |
| 204 | + assert_eq!( |
| 205 | + mithril_network_configuration_for_epoch, |
| 206 | + mithril_network_configuration_for_epoch_from_cbor |
| 207 | + ); |
| 208 | + } |
| 209 | +} |
0 commit comments