use super::{
IcSnapshotUploadError, IcSnapshotUploadKind, IcSnapshotUploadRequest,
MAX_IC_SNAPSHOT_UPLOAD_REPLY_BYTES, validate_destination,
};
use crate::model::{
artifacts::ArtifactChecksumRecord, ic_lifecycle_reply::EMPTY_CANDID_REPLY,
ic_snapshot_reply::SnapshotId,
};
use ic_platform::candid_codec::decoder::{Limits, decode_one_with_skip_limit};
use std::fmt;
struct WireMetadataReply {
snapshot_id: SnapshotId,
}
ic_platform::candid_record!(WireMetadataReply {
4_045_790_262 => snapshot_id: SnapshotId,
});
#[derive(Debug, Eq, PartialEq)]
pub enum IcSnapshotUploadReplyKind {
Metadata {
snapshot_id: Vec<u8>,
},
DataAcknowledgement,
}
pub struct IcSnapshotUploadReply<'request, 'source> {
request: &'request IcSnapshotUploadRequest<'source>,
kind: IcSnapshotUploadReplyKind,
payload_checksum: ArtifactChecksumRecord,
}
impl<'request, 'source> IcSnapshotUploadReply<'request, 'source> {
pub fn decode(
request: &'request IcSnapshotUploadRequest<'source>,
bytes: &[u8],
) -> Result<Self, IcSnapshotUploadError> {
if bytes.len() > MAX_IC_SNAPSHOT_UPLOAD_REPLY_BYTES {
return Err(IcSnapshotUploadError::ReplyTooLarge);
}
let kind = match request.kind() {
IcSnapshotUploadKind::Metadata => {
let reply: WireMetadataReply = decode_one_with_skip_limit(
bytes,
Limits {
bytes: MAX_IC_SNAPSHOT_UPLOAD_REPLY_BYTES,
header: 4096,
types: 16,
work: 64 * 1024,
allocation: 64 * 1024,
},
0,
)
.map_err(|_| IcSnapshotUploadError::InvalidReply)?;
validate_destination(request.source(), &reply.snapshot_id.0)?;
IcSnapshotUploadReplyKind::Metadata {
snapshot_id: reply.snapshot_id.0,
}
}
IcSnapshotUploadKind::Data { .. } => {
if bytes != EMPTY_CANDID_REPLY {
return Err(IcSnapshotUploadError::InvalidReply);
}
IcSnapshotUploadReplyKind::DataAcknowledgement
}
};
Ok(Self {
request,
kind,
payload_checksum: ArtifactChecksumRecord::from_bytes(bytes),
})
}
#[must_use]
pub const fn request(&self) -> &'request IcSnapshotUploadRequest<'source> {
self.request
}
#[must_use]
pub const fn kind(&self) -> &IcSnapshotUploadReplyKind {
&self.kind
}
#[must_use]
pub const fn payload_checksum(&self) -> &ArtifactChecksumRecord {
&self.payload_checksum
}
#[must_use]
pub fn digest(&self) -> ArtifactChecksumRecord {
crate::model::evidence_digest::reply(
b"ic-backup/ic-snapshot-upload-reply/v1\0",
[&self.request.binding_digest(), &self.payload_checksum],
)
}
}
impl fmt::Debug for IcSnapshotUploadReply<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IcSnapshotUploadReply")
.field("method", &self.request.method())
.field("payload_checksum", &self.payload_checksum)
.finish_non_exhaustive()
}
}