rns_core/resource/
assembly.rs1use super::{
3 parts::extract_metadata_owned,
4 proof::{build_proof_data, data_hash_state, finish_with},
5 ResourceAction, ResourceError,
6};
7use crate::{
8 buffer::types::{Compressor, DecompressError},
9 constants::RESOURCE_RANDOM_HASH_SIZE,
10};
11use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
12use rns_crypto::sha256::Sha256;
13
14#[derive(Clone, Debug)]
16pub struct AssemblyId(Arc<()>);
17impl AssemblyId {
18 pub(super) fn new() -> Self {
19 Self(Arc::new(()))
20 }
21}
22impl PartialEq for AssemblyId {
23 fn eq(&self, other: &Self) -> bool {
24 Arc::ptr_eq(&self.0, &other.0)
25 }
26}
27impl Eq for AssemblyId {}
28
29pub struct ResourceAssembly {
32 pub(super) id: AssemblyId,
33 pub(super) data: AssemblyData,
34}
35pub struct AssemblyResult {
37 pub(super) id: AssemblyId,
38 pub(super) result: Result<Vec<ResourceAction>, ResourceError>,
39}
40fn decompress_error(error: DecompressError) -> ResourceError {
41 match error {
42 DecompressError::TooLarge => ResourceError::TooLarge,
43 DecompressError::InvalidData => ResourceError::DecompressionFailed,
44 }
45}
46
47impl ResourceAssembly {
48 pub fn id(&self) -> &AssemblyId {
49 &self.id
50 }
51 pub fn is_compressed(&self) -> bool {
53 self.data.compressed
54 }
55 pub fn take_compressed_data(&mut self) -> Vec<u8> {
59 core::mem::take(&mut self.data.plaintext)
60 }
61 pub fn finish_decompressed(
65 self,
66 decompressed: Vec<u8>,
67 data_state: Option<Sha256>,
68 ) -> AssemblyResult {
69 AssemblyResult {
70 id: self.id,
71 result: self.data.finish(decompressed, data_state),
72 }
73 }
74 pub fn decompression_failed(self, too_large: bool) -> AssemblyResult {
77 AssemblyResult {
78 id: self.id,
79 result: Err(decompress_error(if too_large {
80 DecompressError::TooLarge
81 } else {
82 DecompressError::InvalidData
83 })),
84 }
85 }
86 pub fn input_capacity(&self) -> usize {
88 self.data.plaintext.capacity()
89 }
90 pub fn max_output_size(&self) -> usize {
92 self.data.limit
93 }
94 pub fn run(self, compressor: &dyn Compressor) -> AssemblyResult {
95 AssemblyResult {
96 id: self.id,
97 result: self.data.run(compressor),
98 }
99 }
100}
101
102pub(super) struct AssemblyData {
103 pub plaintext: Vec<u8>,
104 pub data_state: Option<Box<Sha256>>,
106 pub random_hash: [u8; RESOURCE_RANDOM_HASH_SIZE],
107 pub resource_hash: [u8; 32],
108 pub compressed: bool,
109 pub metadata: bool,
110 pub app_flag: bool,
111 pub limit: usize,
112}
113impl AssemblyData {
114 pub fn run(
115 mut self,
116 compressor: &dyn Compressor,
117 ) -> Result<Vec<ResourceAction>, ResourceError> {
118 let plaintext = core::mem::take(&mut self.plaintext);
120 let (decompressed, data_state) = if self.compressed {
121 let decompressed = compressor
122 .decompress_bounded(&plaintext, self.limit)
123 .map_err(decompress_error)?;
124 (decompressed, None)
125 } else {
126 (plaintext, self.data_state.take().map(|state| *state))
127 };
128 self.finish(decompressed, data_state)
129 }
130
131 fn finish(
134 self,
135 decompressed: Vec<u8>,
136 data_state: Option<Sha256>,
137 ) -> Result<Vec<ResourceAction>, ResourceError> {
138 let data_state = data_state.unwrap_or_else(|| data_hash_state(&decompressed));
139 let hash = finish_with(&data_state, &self.random_hash);
140 if hash != self.resource_hash {
141 return Err(ResourceError::HashMismatch);
142 }
143 let proof = build_proof_data(&hash, &finish_with(&data_state, &hash));
145 let (data, metadata) = if self.metadata {
146 let (metadata, data) =
147 extract_metadata_owned(decompressed).ok_or(ResourceError::InvalidPart)?;
148 (data, Some(metadata))
149 } else {
150 (decompressed, None)
151 };
152 Ok(vec![
153 ResourceAction::SendProof(proof),
154 ResourceAction::DataReceived {
155 data,
156 metadata,
157 app_flag: self.app_flag,
158 },
159 ResourceAction::Completed,
160 ])
161 }
162}