use super::*;
impl<N: Network> FromBytes for Deployment<N> {
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let version = match u8::read_le(&mut reader)? {
1 => DeploymentVersion::V1,
2 => DeploymentVersion::V2,
3 => DeploymentVersion::V3,
version => return Err(error(format!("Invalid deployment version: {version}"))),
};
let edition = u16::read_le(&mut reader)?;
let program = Program::read_le(&mut reader)?;
let num_entries = u16::read_le(&mut reader)?;
let max_entries = N::MAX_FUNCTIONS + N::MAX_RECORDS;
if num_entries as usize > max_entries {
return Err(error(format!(
"Deployment (from 'read_le') has too many entries ({num_entries} > {max_entries})"
)));
}
let mut verifying_keys = Vec::with_capacity(num_entries as usize);
for _ in 0..num_entries {
let identifier = Identifier::<N>::read_le(&mut reader)?;
let verifying_key = VerifyingKey::<N>::read_le(&mut reader)?;
let certificate = Certificate::<N>::read_le(&mut reader)?;
verifying_keys.push((identifier, (verifying_key, certificate)));
}
let program_checksum = match version {
DeploymentVersion::V1 => None,
DeploymentVersion::V2 | DeploymentVersion::V3 => {
let bytes: [u8; 32] = FromBytes::read_le(&mut reader)?;
let checksum = bytes.map(U8::new);
if checksum != program.to_checksum() {
return Err(error(format!(
"Invalid checksum in the deployment: expected [{}], got [{}]",
program.to_checksum().iter().join(", "),
checksum.iter().join(", ")
)));
}
Some(checksum)
}
};
let program_owner = match version {
DeploymentVersion::V1 | DeploymentVersion::V3 => None,
DeploymentVersion::V2 => {
let owner = Address::<N>::read_le(&mut reader)?;
Some(owner)
}
};
Self::new(edition, program, verifying_keys, program_checksum, program_owner)
.map_err(|err| error(format!("{err}")))
}
}
impl<N: Network> ToBytes for Deployment<N> {
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
let version = self.version().map_err(error)?;
(version as u8).write_le(&mut writer)?;
self.edition.write_le(&mut writer)?;
self.program.write_le(&mut writer)?;
(u16::try_from(self.verifying_keys.len()).map_err(|e| error(e.to_string()))?).write_le(&mut writer)?;
for (name, (verifying_key, certificate)) in &self.verifying_keys {
name.write_le(&mut writer)?;
verifying_key.write_le(&mut writer)?;
certificate.write_le(&mut writer)?;
}
if matches!(version, DeploymentVersion::V2 | DeploymentVersion::V3) {
for byte in &self.program_checksum.unwrap() {
byte.write_le(&mut writer)?;
}
}
if matches!(version, DeploymentVersion::V2) {
self.program_owner.unwrap().write_le(&mut writer)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bytes() -> Result<()> {
let rng = &mut TestRng::default();
for expected in [
test_helpers::sample_deployment_v1(Uniform::rand(rng), rng),
test_helpers::sample_deployment_v2_without_translation_keys(Uniform::rand(rng), rng),
test_helpers::sample_deployment_v2_with_translation_keys(Uniform::rand(rng), rng),
test_helpers::sample_deployment_v3(Uniform::rand(rng), rng),
] {
let expected_bytes = expected.to_bytes_le()?;
assert_eq!(expected, Deployment::read_le(&expected_bytes[..])?);
}
Ok(())
}
}