3
3
4
4
//! Operations that don't persist any changes to the chain state.
5
5
6
- use std:: borrow:: Cow ;
6
+ use std:: { borrow:: Cow , collections :: BTreeSet } ;
7
7
8
8
use linera_base:: {
9
9
data_types:: { ArithmeticError , BlobContent , Timestamp , UserApplicationDescription } ,
@@ -17,7 +17,7 @@ use linera_chain::{
17
17
} ,
18
18
manager,
19
19
} ;
20
- use linera_execution:: { ChannelSubscription , Query , Response } ;
20
+ use linera_execution:: { ChannelSubscription , Query , ResourceControlPolicy , Response } ;
21
21
use linera_storage:: { Clock as _, Storage } ;
22
22
use linera_views:: views:: View ;
23
23
#[ cfg( with_testing) ]
@@ -178,9 +178,8 @@ where
178
178
. system
179
179
. current_committee ( )
180
180
. expect ( "chain is active" ) ;
181
+ let policy = committee. policy ( ) . clone ( ) ;
181
182
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 ;
184
183
// Check the authentication of the block.
185
184
let public_key = self
186
185
. 0
@@ -209,30 +208,19 @@ where
209
208
self . 0 . chain . remove_bundles_from_inboxes ( block) . await ?;
210
209
// Verify that all required bytecode hashed certificate values and blobs are available, and no
211
210
// unrelated ones provided.
211
+ let published_blob_ids = block. published_blob_ids ( ) ;
212
212
self . 0
213
- . check_no_missing_blobs ( block . published_blob_ids ( ) , blobs)
213
+ . check_no_missing_blobs ( published_blob_ids. clone ( ) , blobs)
214
214
. await ?;
215
215
for blob in blobs {
216
+ Self :: check_blob_size ( blob. content ( ) , & policy) ?;
216
217
self . 0 . cache_recent_blob ( Cow :: Borrowed ( blob) ) . await ;
217
218
}
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
+ }
236
224
}
237
225
238
226
let local_time = self . 0 . storage . clock ( ) . current_time ( ) ;
@@ -354,6 +342,29 @@ where
354
342
}
355
343
Ok ( ChainInfoResponse :: new ( info, self . 0 . config . key_pair ( ) ) )
356
344
}
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
+ }
357
368
}
358
369
359
370
impl < StorageClient > Drop for ChainWorkerStateWithTemporaryChanges < ' _ , StorageClient >
0 commit comments