Skip to content

Commit 9de6306

Browse files
authored
Don't cache blobs that are too large. (#2726)
* Don't cache blobs that are too large. * Check size first, then decompress.
1 parent 36121f0 commit 9de6306

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

linera-base/src/data_types.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,17 @@ impl BlobContent {
10621062
pub fn blob_bytes(&self) -> BlobBytes {
10631063
BlobBytes(self.inner_bytes())
10641064
}
1065+
1066+
/// Returns the size of the blob content in bytes.
1067+
pub fn size(&self) -> usize {
1068+
match self {
1069+
BlobContent::Data(bytes) => bytes.len(),
1070+
BlobContent::ContractBytecode(compressed_bytecode)
1071+
| BlobContent::ServiceBytecode(compressed_bytecode) => {
1072+
compressed_bytecode.compressed_bytes.len()
1073+
}
1074+
}
1075+
}
10651076
}
10661077

10671078
impl From<Blob> for BlobContent {

linera-core/src/chain_worker/state/temporary_changes.rs

+34-23
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
//! Operations that don't persist any changes to the chain state.
55
6-
use std::borrow::Cow;
6+
use std::{borrow::Cow, collections::BTreeSet};
77

88
use linera_base::{
99
data_types::{ArithmeticError, BlobContent, Timestamp, UserApplicationDescription},
@@ -17,7 +17,7 @@ use linera_chain::{
1717
},
1818
manager,
1919
};
20-
use linera_execution::{ChannelSubscription, Query, Response};
20+
use linera_execution::{ChannelSubscription, Query, ResourceControlPolicy, Response};
2121
use linera_storage::{Clock as _, Storage};
2222
use linera_views::views::View;
2323
#[cfg(with_testing)]
@@ -178,9 +178,8 @@ where
178178
.system
179179
.current_committee()
180180
.expect("chain is active");
181+
let policy = committee.policy().clone();
181182
check_block_epoch(epoch, block)?;
182-
let maximum_blob_size = committee.policy().maximum_blob_size;
183-
let maximum_bytecode_size = committee.policy().maximum_bytecode_size;
184183
// Check the authentication of the block.
185184
let public_key = self
186185
.0
@@ -209,30 +208,19 @@ where
209208
self.0.chain.remove_bundles_from_inboxes(block).await?;
210209
// Verify that all required bytecode hashed certificate values and blobs are available, and no
211210
// unrelated ones provided.
211+
let published_blob_ids = block.published_blob_ids();
212212
self.0
213-
.check_no_missing_blobs(block.published_blob_ids(), blobs)
213+
.check_no_missing_blobs(published_blob_ids.clone(), blobs)
214214
.await?;
215215
for blob in blobs {
216+
Self::check_blob_size(blob.content(), &policy)?;
216217
self.0.cache_recent_blob(Cow::Borrowed(blob)).await;
217218
}
218-
for blob in self.0.get_blobs(block.published_blob_ids()).await? {
219-
let blob_size = match blob.content() {
220-
BlobContent::Data(bytes) => bytes.len(),
221-
BlobContent::ContractBytecode(compressed_bytecode)
222-
| BlobContent::ServiceBytecode(compressed_bytecode) => {
223-
ensure!(
224-
compressed_bytecode.decompressed_size_at_most(maximum_bytecode_size)?,
225-
WorkerError::BytecodeTooLarge
226-
);
227-
compressed_bytecode.compressed_bytes.len()
228-
}
229-
};
230-
ensure!(
231-
u64::try_from(blob_size)
232-
.ok()
233-
.is_some_and(|size| size <= maximum_blob_size),
234-
WorkerError::BlobTooLarge
235-
)
219+
let checked_blobs = blobs.iter().map(|blob| blob.id()).collect::<BTreeSet<_>>();
220+
for blob in self.0.get_blobs(published_blob_ids).await? {
221+
if !checked_blobs.contains(&blob.id()) {
222+
Self::check_blob_size(blob.content(), &policy)?;
223+
}
236224
}
237225

238226
let local_time = self.0.storage.clock().current_time();
@@ -354,6 +342,29 @@ where
354342
}
355343
Ok(ChainInfoResponse::new(info, self.0.config.key_pair()))
356344
}
345+
346+
fn check_blob_size(
347+
content: &BlobContent,
348+
policy: &ResourceControlPolicy,
349+
) -> Result<(), WorkerError> {
350+
ensure!(
351+
u64::try_from(content.size())
352+
.ok()
353+
.is_some_and(|size| size <= policy.maximum_blob_size),
354+
WorkerError::BlobTooLarge
355+
);
356+
match content {
357+
BlobContent::ContractBytecode(compressed_bytecode)
358+
| BlobContent::ServiceBytecode(compressed_bytecode) => {
359+
ensure!(
360+
compressed_bytecode.decompressed_size_at_most(policy.maximum_bytecode_size)?,
361+
WorkerError::BytecodeTooLarge
362+
);
363+
}
364+
BlobContent::Data(_) => {}
365+
}
366+
Ok(())
367+
}
357368
}
358369

359370
impl<StorageClient> Drop for ChainWorkerStateWithTemporaryChanges<'_, StorageClient>

0 commit comments

Comments
 (0)