1#![deny(missing_docs)]
7
8mod db_storage;
9mod migration;
10
11use std::sync::Arc as StdArc;
12
13use async_trait::async_trait;
14use itertools::Itertools;
15use linera_base::{
16 crypto::CryptoHash,
17 data_types::{
18 ApplicationDescription, Blob, BlockHeight, ChainDescription, CompressedBytecode, Epoch,
19 NetworkDescription, TimeDelta, Timestamp,
20 },
21 identifiers::{ApplicationId, BlobId, BlobType, ChainId, EventId, IndexAndEvent, StreamId},
22 time::Duration,
23 vm::VmRuntime,
24};
25pub use linera_cache::{Arc, DEFAULT_CLEANUP_INTERVAL_SECS};
26use linera_chain::{
27 types::{ConfirmedBlock, ConfirmedBlockCertificate},
28 ChainError, ChainStateView,
29};
30use linera_execution::{
31 committee::Committee, system::EPOCH_STREAM_NAME, BlobState, ExecutionError,
32 ExecutionRuntimeConfig, ExecutionRuntimeContext, SharedCommittees, TransactionTracker,
33 UserContractCode, UserServiceCode, WasmRuntime,
34};
35#[cfg(with_revm)]
36use linera_execution::{
37 evm::revm::{EvmContractModule, EvmServiceModule},
38 EvmRuntime,
39};
40#[cfg(with_wasm_runtime)]
41use linera_execution::{WasmContractModule, WasmServiceModule};
42use linera_views::{context::Context, views::RootView, ViewError};
43
44#[cfg(with_metrics)]
45pub use crate::db_storage::metrics;
46#[cfg(with_testing)]
47pub use crate::db_storage::TestClock;
48pub use crate::db_storage::{
49 ChainStatesFirstAssignment, DbStorage, RootKey, StorageCacheConfig, StorageCaches, WallClock,
50};
51
52pub const DEFAULT_NAMESPACE: &str = "table_linera";
54
55#[cfg_attr(not(web), async_trait)]
57#[cfg_attr(web, async_trait(?Send))]
58pub trait Storage: linera_base::util::traits::AutoTraits + Sized {
59 type Context: Context<Extra = ChainRuntimeContext<Self>> + Clone + 'static;
61
62 type Clock: Clock + Clone + Send + Sync;
64
65 type BlockExporterContext: Context<Extra = u32> + Clone;
67
68 fn clock(&self) -> &Self::Clock;
70
71 fn thread_pool(&self) -> &StdArc<linera_execution::ThreadPool>;
73
74 async fn load_chain(&self, id: ChainId) -> Result<ChainStateView<Self::Context>, ViewError>;
82
83 async fn contains_blob(&self, blob_id: BlobId) -> Result<bool, ViewError>;
85
86 async fn missing_blobs(&self, blob_ids: &[BlobId]) -> Result<Vec<BlobId>, ViewError>;
88
89 async fn contains_blob_state(&self, blob_id: BlobId) -> Result<bool, ViewError>;
91
92 async fn read_confirmed_block(
94 &self,
95 hash: CryptoHash,
96 ) -> Result<Option<Arc<ConfirmedBlock>>, ViewError>;
97
98 async fn read_confirmed_blocks<I: IntoIterator<Item = CryptoHash> + Send>(
100 &self,
101 hashes: I,
102 ) -> Result<Vec<Option<Arc<ConfirmedBlock>>>, ViewError>;
103
104 async fn read_blob(&self, blob_id: BlobId) -> Result<Option<Arc<Blob>>, ViewError>;
106
107 async fn read_blobs(&self, blob_ids: &[BlobId]) -> Result<Vec<Option<Arc<Blob>>>, ViewError>;
109
110 async fn read_blob_state(&self, blob_id: BlobId) -> Result<Option<BlobState>, ViewError>;
112
113 async fn read_blob_states(
115 &self,
116 blob_ids: &[BlobId],
117 ) -> Result<Vec<Option<BlobState>>, ViewError>;
118
119 async fn write_blob(&self, blob: &Blob) -> Result<(), ViewError>;
121
122 async fn write_blobs_and_certificate(
124 &self,
125 blobs: &[Blob],
126 certificate: &ConfirmedBlockCertificate,
127 ) -> Result<(), ViewError>;
128
129 async fn maybe_write_blobs(&self, blobs: &[Blob]) -> Result<Vec<bool>, ViewError>;
132
133 async fn maybe_write_blob_states(
135 &self,
136 blob_ids: &[BlobId],
137 blob_state: BlobState,
138 ) -> Result<(), ViewError>;
139
140 async fn write_blobs(&self, blobs: &[Blob]) -> Result<(), ViewError>;
142
143 async fn contains_certificate(&self, hash: CryptoHash) -> Result<bool, ViewError>;
145
146 fn cache_certificate(
153 &self,
154 certificate: ConfirmedBlockCertificate,
155 ) -> Arc<ConfirmedBlockCertificate>;
156
157 fn cache_blob(&self, blob: Blob) -> Arc<Blob>;
164
165 fn cache_confirmed_block(&self, block: ConfirmedBlock) -> Arc<ConfirmedBlock>;
172
173 async fn read_certificate(
175 &self,
176 hash: CryptoHash,
177 ) -> Result<Option<Arc<ConfirmedBlockCertificate>>, ViewError>;
178
179 async fn read_certificates(
181 &self,
182 hashes: &[CryptoHash],
183 ) -> Result<Vec<Option<Arc<ConfirmedBlockCertificate>>>, ViewError>;
184
185 async fn read_certificates_raw(
191 &self,
192 hashes: &[CryptoHash],
193 ) -> Result<Vec<Option<Arc<(Vec<u8>, Vec<u8>)>>>, ViewError>;
194
195 async fn read_certificates_by_heights(
199 &self,
200 chain_id: ChainId,
201 heights: &[BlockHeight],
202 ) -> Result<Vec<Option<Arc<ConfirmedBlockCertificate>>>, ViewError>;
203
204 async fn read_certificates_by_heights_raw(
209 &self,
210 chain_id: ChainId,
211 heights: &[BlockHeight],
212 ) -> Result<Vec<Option<Arc<(Vec<u8>, Vec<u8>)>>>, ViewError>;
213
214 async fn read_certificate_hashes_by_heights(
218 &self,
219 chain_id: ChainId,
220 heights: &[BlockHeight],
221 ) -> Result<Vec<Option<CryptoHash>>, ViewError>;
222
223 async fn write_certificate_height_indices(
227 &self,
228 chain_id: ChainId,
229 indices: &[(BlockHeight, CryptoHash)],
230 ) -> Result<(), ViewError>;
231
232 async fn read_event(&self, id: EventId) -> Result<Option<Arc<Vec<u8>>>, ViewError>;
234
235 async fn contains_event(&self, id: EventId) -> Result<bool, ViewError>;
237
238 async fn read_events_from_index(
240 &self,
241 chain_id: &ChainId,
242 stream_id: &StreamId,
243 start_index: u32,
244 ) -> Result<Vec<IndexAndEvent>, ViewError>;
245
246 async fn write_events(
248 &self,
249 events: impl IntoIterator<Item = (EventId, Vec<u8>)> + Send,
250 ) -> Result<(), ViewError>;
251
252 async fn read_network_description(&self) -> Result<Option<NetworkDescription>, ViewError>;
254
255 async fn write_network_description(
257 &self,
258 information: &NetworkDescription,
259 ) -> Result<(), ViewError>;
260
261 fn shared_committees(&self) -> &SharedCommittees;
263
264 async fn get_or_load_committee(
270 &self,
271 epoch: Epoch,
272 ) -> Result<Option<StdArc<Committee>>, ViewError> {
273 if let Some(committee) = self.shared_committees().get(epoch) {
274 return Ok(Some(committee));
275 }
276 let Some(net_description) = self.read_network_description().await? else {
277 tracing::warn!(
278 ?epoch,
279 "get_or_load_committee: NetworkDescription missing in storage"
280 );
281 return Ok(None);
282 };
283 let blob_hash = if epoch.0 == 0 {
284 net_description.genesis_committee_blob_hash
285 } else {
286 let event_id = EventId {
287 chain_id: net_description.admin_chain_id,
288 stream_id: StreamId::system(EPOCH_STREAM_NAME),
289 index: epoch.0,
290 };
291 match self.read_event(event_id.clone()).await? {
292 Some(bytes) => bcs::from_bytes(&bytes)?,
293 None => {
294 tracing::warn!(
295 ?epoch,
296 ?event_id,
297 "get_or_load_committee: NewCommittee event missing in storage"
298 );
299 return Ok(None);
300 }
301 }
302 };
303 let blob_id = BlobId::new(blob_hash, BlobType::Committee);
304 let Some(blob) = self.read_blob(blob_id).await? else {
305 tracing::warn!(
306 ?epoch,
307 ?blob_id,
308 "get_or_load_committee: committee blob missing in storage"
309 );
310 return Ok(None);
311 };
312 let committee: Committee = bcs::from_bytes(blob.bytes())?;
313 Ok(Some(
314 self.shared_committees()
315 .insert(epoch, StdArc::new(committee)),
316 ))
317 }
318
319 async fn create_chain(&self, description: ChainDescription) -> Result<(), ChainError>
327 where
328 ChainRuntimeContext<Self>: ExecutionRuntimeContext,
329 {
330 let id = description.id();
331 self.write_blob(&Blob::new_chain_description(&description))
333 .await?;
334 let mut chain = self.load_chain(id).await?;
335 assert!(
336 !chain.is_active().await?,
337 "Attempting to create a chain twice"
338 );
339 let current_time = self.clock().current_time();
340 chain.initialize_if_needed(current_time).await?;
341 chain.save().await?;
342 Ok(())
343 }
344
345 fn wasm_runtime(&self) -> Option<WasmRuntime>;
347
348 async fn load_contract(
351 &self,
352 application_description: &ApplicationDescription,
353 txn_tracker: &TransactionTracker,
354 ) -> Result<UserContractCode, ExecutionError> {
355 let contract_bytecode_blob_id = application_description.contract_bytecode_blob_id();
356 let content = match txn_tracker.get_blob_content(&contract_bytecode_blob_id) {
357 Some(content) => content.clone(),
358 None => self
359 .read_blob(contract_bytecode_blob_id)
360 .await?
361 .ok_or(ExecutionError::BlobsNotFound(vec![
362 contract_bytecode_blob_id,
363 ]))?
364 .content()
365 .clone(),
366 };
367 let compressed_contract_bytecode = CompressedBytecode {
368 compressed_bytes: content.into_arc_bytes(),
369 };
370 #[cfg_attr(not(any(with_wasm_runtime, with_revm)), allow(unused_variables))]
371 let contract_bytecode = self
372 .thread_pool()
373 .run_send((), move |()| async move {
374 compressed_contract_bytecode.decompress()
375 })
376 .await
377 .await??;
378 match application_description.module_id.vm_runtime {
379 VmRuntime::Wasm => {
380 cfg_if::cfg_if! {
381 if #[cfg(with_wasm_runtime)] {
382 let Some(wasm_runtime) = self.wasm_runtime() else {
383 panic!("A Wasm runtime is required to load user applications.");
384 };
385 Ok(WasmContractModule::new(contract_bytecode, wasm_runtime)
386 .await?
387 .into())
388 } else {
389 panic!(
390 "A Wasm runtime is required to load user applications. \
391 Please enable the `wasmer` or the `wasmtime` feature flags \
392 when compiling `linera-storage`."
393 );
394 }
395 }
396 }
397 VmRuntime::Evm => {
398 cfg_if::cfg_if! {
399 if #[cfg(with_revm)] {
400 let evm_runtime = EvmRuntime::Revm;
401 Ok(EvmContractModule::new(contract_bytecode, evm_runtime)?
402 .into())
403 } else {
404 panic!(
405 "An Evm runtime is required to load user applications. \
406 Please enable the `revm` feature flag \
407 when compiling `linera-storage`."
408 );
409 }
410 }
411 }
412 }
413 }
414
415 async fn load_service(
418 &self,
419 application_description: &ApplicationDescription,
420 txn_tracker: &TransactionTracker,
421 ) -> Result<UserServiceCode, ExecutionError> {
422 let service_bytecode_blob_id = application_description.service_bytecode_blob_id();
423 let content = match txn_tracker.get_blob_content(&service_bytecode_blob_id) {
424 Some(content) => content.clone(),
425 None => self
426 .read_blob(service_bytecode_blob_id)
427 .await?
428 .ok_or(ExecutionError::BlobsNotFound(vec![
429 service_bytecode_blob_id,
430 ]))?
431 .content()
432 .clone(),
433 };
434 let compressed_service_bytecode = CompressedBytecode {
435 compressed_bytes: content.into_arc_bytes(),
436 };
437 #[cfg_attr(not(any(with_wasm_runtime, with_revm)), allow(unused_variables))]
438 let service_bytecode = self
439 .thread_pool()
440 .run_send((), move |()| async move {
441 compressed_service_bytecode.decompress()
442 })
443 .await
444 .await??;
445 match application_description.module_id.vm_runtime {
446 VmRuntime::Wasm => {
447 cfg_if::cfg_if! {
448 if #[cfg(with_wasm_runtime)] {
449 let Some(wasm_runtime) = self.wasm_runtime() else {
450 panic!("A Wasm runtime is required to load user applications.");
451 };
452 Ok(WasmServiceModule::new(service_bytecode, wasm_runtime)
453 .await?
454 .into())
455 } else {
456 panic!(
457 "A Wasm runtime is required to load user applications. \
458 Please enable the `wasmer` or the `wasmtime` feature flags \
459 when compiling `linera-storage`."
460 );
461 }
462 }
463 }
464 VmRuntime::Evm => {
465 cfg_if::cfg_if! {
466 if #[cfg(with_revm)] {
467 let evm_runtime = EvmRuntime::Revm;
468 Ok(EvmServiceModule::new(service_bytecode, evm_runtime)?
469 .into())
470 } else {
471 panic!(
472 "An Evm runtime is required to load user applications. \
473 Please enable the `revm` feature flag \
474 when compiling `linera-storage`."
475 );
476 }
477 }
478 }
479 }
480 }
481
482 async fn block_exporter_context(
484 &self,
485 block_exporter_id: u32,
486 ) -> Result<Self::BlockExporterContext, ViewError>;
487}
488
489pub enum ResultReadCertificates {
491 Certificates(Vec<ConfirmedBlockCertificate>),
493 InvalidHashes(Vec<CryptoHash>),
495}
496
497impl ResultReadCertificates {
498 pub fn new(
500 certificates: Vec<Option<Arc<ConfirmedBlockCertificate>>>,
501 hashes: Vec<CryptoHash>,
502 ) -> Self {
503 let (certificates, invalid_hashes) = certificates
504 .into_iter()
505 .zip(hashes)
506 .partition_map::<Vec<_>, Vec<_>, _, _, _>(|(certificate, hash)| match certificate {
507 Some(cert) => itertools::Either::Left(Arc::unwrap_or_clone(cert)),
508 None => itertools::Either::Right(hash),
509 });
510 if invalid_hashes.is_empty() {
511 Self::Certificates(certificates)
512 } else {
513 Self::InvalidHashes(invalid_hashes)
514 }
515 }
516}
517
518#[derive(Clone)]
520pub struct ChainRuntimeContext<S> {
521 storage: S,
522 chain_id: ChainId,
523 thread_pool: StdArc<linera_execution::ThreadPool>,
524 execution_runtime_config: ExecutionRuntimeConfig,
525 user_contracts: StdArc<papaya::HashMap<ApplicationId, UserContractCode>>,
526 user_services: StdArc<papaya::HashMap<ApplicationId, UserServiceCode>>,
527}
528
529#[cfg_attr(not(web), async_trait)]
530#[cfg_attr(web, async_trait(?Send))]
531impl<S: Storage> ExecutionRuntimeContext for ChainRuntimeContext<S> {
532 fn chain_id(&self) -> ChainId {
533 self.chain_id
534 }
535
536 fn thread_pool(&self) -> &StdArc<linera_execution::ThreadPool> {
537 &self.thread_pool
538 }
539
540 fn execution_runtime_config(&self) -> linera_execution::ExecutionRuntimeConfig {
541 self.execution_runtime_config
542 }
543
544 fn user_contracts(&self) -> &StdArc<papaya::HashMap<ApplicationId, UserContractCode>> {
545 &self.user_contracts
546 }
547
548 fn user_services(&self) -> &StdArc<papaya::HashMap<ApplicationId, UserServiceCode>> {
549 &self.user_services
550 }
551
552 async fn get_user_contract(
553 &self,
554 description: &ApplicationDescription,
555 txn_tracker: &TransactionTracker,
556 ) -> Result<UserContractCode, ExecutionError> {
557 let application_id = description.into();
558 let pinned = self.user_contracts.pin_owned();
559 if let Some(contract) = pinned.get(&application_id) {
560 return Ok(contract.clone());
561 }
562 let contract = self.storage.load_contract(description, txn_tracker).await?;
563 pinned.insert(application_id, contract.clone());
564 Ok(contract)
565 }
566
567 async fn get_user_service(
568 &self,
569 description: &ApplicationDescription,
570 txn_tracker: &TransactionTracker,
571 ) -> Result<UserServiceCode, ExecutionError> {
572 let application_id = description.into();
573 let pinned = self.user_services.pin_owned();
574 if let Some(service) = pinned.get(&application_id) {
575 return Ok(service.clone());
576 }
577 let service = self.storage.load_service(description, txn_tracker).await?;
578 pinned.insert(application_id, service.clone());
579 Ok(service)
580 }
581
582 async fn get_blob(&self, blob_id: BlobId) -> Result<Option<StdArc<Blob>>, ViewError> {
583 Ok(self.storage.read_blob(blob_id).await?.map(Arc::into_std))
584 }
585
586 async fn get_event(&self, event_id: EventId) -> Result<Option<StdArc<Vec<u8>>>, ViewError> {
587 Ok(self.storage.read_event(event_id).await?.map(Arc::into_std))
588 }
589
590 async fn get_network_description(&self) -> Result<Option<NetworkDescription>, ViewError> {
591 self.storage.read_network_description().await
592 }
593
594 async fn get_or_load_committee(
595 &self,
596 epoch: Epoch,
597 ) -> Result<Option<StdArc<Committee>>, ViewError> {
598 self.storage.get_or_load_committee(epoch).await
599 }
600
601 async fn contains_blob(&self, blob_id: BlobId) -> Result<bool, ViewError> {
602 self.storage.contains_blob(blob_id).await
603 }
604
605 async fn contains_event(&self, event_id: EventId) -> Result<bool, ViewError> {
606 self.storage.contains_event(event_id).await
607 }
608
609 #[cfg(with_testing)]
610 async fn add_blobs(
611 &self,
612 blobs: impl IntoIterator<Item = Blob> + Send,
613 ) -> Result<(), ViewError> {
614 let blobs = Vec::from_iter(blobs);
615 self.storage.write_blobs(&blobs).await
616 }
617
618 #[cfg(with_testing)]
619 async fn add_events(
620 &self,
621 events: impl IntoIterator<Item = (EventId, Vec<u8>)> + Send,
622 ) -> Result<(), ViewError> {
623 self.storage.write_events(events).await
624 }
625}
626
627#[cfg_attr(not(web), async_trait)]
629#[cfg_attr(web, async_trait(?Send))]
630pub trait Clock {
631 fn current_time(&self) -> Timestamp;
633
634 async fn sleep_until(&self, timestamp: Timestamp);
636
637 async fn sleep_for(&self, duration: Duration) {
642 self.sleep_until(
643 self.current_time()
644 .saturating_add(TimeDelta::from_duration(duration)),
645 )
646 .await
647 }
648}