miden_protocol/protocol_config/
next_protocol_config.rs1use alloc::string::ToString;
2
3use super::ProtocolConfigError;
4use crate::block::BlockNumber;
5use crate::utils::serde::{
6 ByteReader,
7 ByteWriter,
8 Deserializable,
9 DeserializationError,
10 Serializable,
11};
12use crate::{Hasher, Word, ZERO};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct NextProtocolConfig {
23 effective_from: BlockNumber,
25
26 protocol_config: Word,
28}
29
30impl NextProtocolConfig {
31 pub fn new(
42 effective_from: BlockNumber,
43 protocol_config: Word,
44 ) -> Result<Self, ProtocolConfigError> {
45 if effective_from == BlockNumber::GENESIS {
46 return Err(ProtocolConfigError::NextConfigEffectiveAtGenesis);
47 }
48
49 Ok(Self { effective_from, protocol_config })
50 }
51
52 pub fn effective_from(&self) -> BlockNumber {
57 self.effective_from
58 }
59
60 pub fn protocol_config(&self) -> Word {
63 self.protocol_config
64 }
65
66 pub fn to_commitment(&self) -> Word {
71 let effective_from = Word::new([self.effective_from.into(), ZERO, ZERO, ZERO]);
72 Hasher::merge(&[effective_from, self.protocol_config])
73 }
74}
75
76impl Serializable for NextProtocolConfig {
80 fn write_into<W: ByteWriter>(&self, target: &mut W) {
81 let Self { effective_from, protocol_config } = self;
82
83 effective_from.write_into(target);
84 protocol_config.write_into(target);
85 }
86}
87
88impl Deserializable for NextProtocolConfig {
89 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
90 let effective_from = source.read()?;
91 let protocol_config = source.read()?;
92
93 Self::new(effective_from, protocol_config)
94 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
95 }
96}
97
98#[cfg(test)]
102mod tests {
103 use assert_matches::assert_matches;
104 use miden_crypto::rand::test_utils::rand_value;
105
106 use super::*;
107
108 #[test]
109 fn commitment_binds_both_fields() {
110 let config = rand_value::<Word>();
111 let next = NextProtocolConfig::new(BlockNumber::from(10u32), config).unwrap();
112 let other_block = NextProtocolConfig::new(BlockNumber::from(11u32), config).unwrap();
113 let other_config =
114 NextProtocolConfig::new(BlockNumber::from(10u32), rand_value::<Word>()).unwrap();
115
116 assert_ne!(next.to_commitment(), other_block.to_commitment());
117 assert_ne!(next.to_commitment(), other_config.to_commitment());
118 }
119
120 #[test]
121 fn new_rejects_genesis() {
122 let error = NextProtocolConfig::new(BlockNumber::GENESIS, Word::empty()).unwrap_err();
123 assert_matches!(error, ProtocolConfigError::NextConfigEffectiveAtGenesis);
124 }
125
126 #[test]
127 fn serde_round_trip() -> anyhow::Result<()> {
128 let next = NextProtocolConfig::new(BlockNumber::from(42u32), rand_value::<Word>())?;
129
130 let deserialized = NextProtocolConfig::read_from_bytes(&next.to_bytes())
131 .map_err(|err| anyhow::anyhow!("{err}"))?;
132
133 assert_eq!(next, deserialized);
134 Ok(())
135 }
136}