Skip to content

Commit

Permalink
cnidarium: update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
hdevalence committed Dec 12, 2023
1 parent 3123b9d commit d77cd10
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 30 deletions.
22 changes: 18 additions & 4 deletions crates/cnidarium-component/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ use async_trait::async_trait;
use cnidarium::StateWrite;
use tendermint::abci;

/// A component of the Penumbra application.
/// A component of a [`cnidarium`]-based application.
///
/// The use of `&mut Arc<S>` may seem unintuitive at first. However, it allows
/// component implementations to optionally share state with
/// concurrently-executing subtasks they spawn, without requiring additional
/// locking. Components can clone the `Arc` and pass clones to concurrent,
/// read-only subtasks, then later once the subtasks complete, use `.get_mut()`
/// to obtain a mutable reference to the state.
#[async_trait]
pub trait Component {
/// A serialized representation of the component's application state,
Expand All @@ -16,7 +23,7 @@ pub trait Component {
/// Performs initialization, given the genesis state.
///
/// This method is called once per chain, and should only perform
/// writes, since the backing tree for the [`State`] will
/// writes, since the backing tree for the [`StateWrite`] will
/// be empty.
///
/// If the app is checkpointed, no genesis app state will be passed in,
Expand Down Expand Up @@ -58,7 +65,12 @@ pub trait Component {
end_block: &abci::request::EndBlock,
);

/// Ends the epoch, applying component-specific state transitions that should occur when an epoch ends.
/// Ends the epoch, applying component-specific state transitions that
/// should occur when an epoch ends.
///
/// Note: epochs are not an ABCI concept. They are merely logical groups of
/// blocks, defined by the application. Applications can choose to treat
/// them as a no-op.
///
/// # Invariants
///
Expand All @@ -67,5 +79,7 @@ pub trait Component {
/// called, `state.get_mut().is_some()`, i.e., the `Arc` is not shared. The
/// implementor MUST ensure that any clones of the `Arc` are dropped before
/// it returns, so that `state.get_mut().is_some()` on completion.
async fn end_epoch<S: StateWrite + 'static>(state: &mut Arc<S>) -> Result<()>;
async fn end_epoch<S: StateWrite + 'static>(_state: &mut Arc<S>) -> Result<()> {
Ok(())
}
}
27 changes: 16 additions & 11 deletions crates/cnidarium-component/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Core trait definitions for components of the Penumbra application.
//! Core trait definitions for components of an ABCI application using [`cnidarium`].
//!
//! This crate defines two traits for use by "component crates":
//!
Expand All @@ -20,17 +20,22 @@
//! a public API, like the rest of the chain state);
//! - a `crate::event` module defining any events emitted by the component;
//!
//! The `penumbra_transaction` crate depends on all of the component crates
//! without the `component` feature, so it can assemble all of the actions for
//! each component into a top-level transaction type. This means all async code
//! should be confined to the `component` module, so that the transaction
//! definitions don't depend on `tokio`, `mio`, etc and can be used without
//! problems in wasm or other non-async contexts.
//! The structure of the feature-gated `component` submodule allows reusing data
//! structures between client and server (fullnode) code.
//!
//! The `penumbra_app` crate depends on all of the component crates with the
//! `component` feature enabled, so it can assemble all of the `ActionHandler`
//! implementations into a top-level `ActionHandler` implementation and call
//! each component's `Component` implementation at the appropriate times.
//! For instance, the `penumbra_transaction` crate depends on all of the
//! component crates without the `component` feature, so it can assemble all of
//! the actions for each component into a top-level transaction type. This
//! means all async code should be confined to the `component` module, so that
//! the transaction definitions don't depend on `tokio`, `mio`, etc and can be
//! used without problems in wasm or other non-async contexts.
//!
//! On the other hand, the `penumbra_app` crate depends on all of the component
//! crates with the `component` feature enabled, so it can assemble all of the
//! `ActionHandler` implementations into a top-level `ActionHandler`
//! implementation and call each component's `Component` implementation at the
//! appropriate times.
#![deny(clippy::unwrap_used)]

mod action_handler;
Expand Down
48 changes: 33 additions & 15 deletions crates/cnidarium/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
//! Storage and management of chain state.
//! Storage and management of chain state, backed by Jellyfish Merkle Trees and RocksDB.
//!
//! This crate provides a versioned, verifiable key-value store that also
//! supports lightweight, copy-on-write snapshots and transactional semantics.
//! The [`Storage`] type is a handle for an instance of a backing store,
//! implemented using RocksDB. The storage records a sequence of versioned
//! [`State`]s. The [`State`] type is a lightweight snapshot of a particular
//! [`Snapshot`]s. The [`Snapshot`] type is a lightweight snapshot of a particular
//! version of the chain state.
//!
//! Each [`State`] instance can also be used as a copy-on-write fork to build up
//! changes before committing them to persistent storage. The
//! [`StateTransaction`] type collects a group of writes, which can then be
//! applied to the (in-memory) [`State`] fork. Finally, the changes accumulated
//! in the [`State`] instance can be committed to the persistent [`Storage`].
//! Each [`Snapshot`] instance can also be used as the basis for a copy-on-write
//! fork to build up changes before committing them to persistent storage. The
//! [`StateDelta`] type collects a group of writes, which can then be applied to
//! the (in-memory) [`StateDelta`] overlay. Finally, the changes accumulated in the
//! [`StateDelta`] instance can be committed to the persistent [`Storage`].
//!
//! Reads are performed with the [`StateRead`] trait, implemented by both
//! [`State`] and [`StateTransaction`], and reflect any currently cached writes.
//! [`Snapshot`] and [`StateDelta`], and reflect any currently cached writes.
//! Writes are performed with the [`StateWrite`] trait, which is only
//! implemented for [`StateTransaction`].
//! implemented for [`StateDelta`].
//!
//! The storage system provides two data stores:
//! The storage system provides three data stores:
//!
//! * A verifiable key-value store, with UTF-8 keys and byte values, backed by
//! the Jellyfish Merkle Tree. The JMT is a sparse merkle tree that records
Expand All @@ -30,11 +30,29 @@
//! values, backed directly by RocksDB. This is intended for use building
//! application-specific indexes of the verifiable consensus state.
//!
//! While the primary key-value store records byte values, it is intended for
//! use with Protobuf-encoded data. To this end, the [`StateRead`] and
//! [`StateWrite`] traits have provided methods that use the
//! [`penumbra_proto::Protobuf`] trait to automatically (de)serialize into proto
//! or domain types, allowing its use as an object store.
//! * A tertiary, in-memory object store. This is intended for use implementing
//! accumulators, like lists of data to be batch-processed at the end of the
//! block. The object store clones on read to prevent violations of
//! transactional semantics, so it should be used with immutable data structures
//! like those in the `im` crate that implement copy-on-write behavior
//! internally.
//!
//! The storage system also supports prefixed "substores", somewhat similar to
//! the Cosmos SDK's multistore design. Each substore has a separate JMT, whose
//! root hash is written into the base store under the prefix. This allows use
//! cases like storing IBC data in a subtree. The substore's non-verifiable
//! store is also stored in a separate RocksDB column family, allowing storage
//! optimizations.
//!
//! Remember that the chain state is a public API. Mapping from raw byte values
//! to typed data should be accomplished by means of extension traits. For
//! instance, the `penumbra_proto` crate provides an extension trait to
//! automatically (de)serialize into proto or domain types, allowing its use as
//! an object store.
//!
//! With the `rpc` feature enabled, this crate also provides a GRPC interface to
//! the key-value store using Tonic.
#![deny(clippy::unwrap_used)]
// Requires nightly.
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
Expand Down

0 comments on commit d77cd10

Please sign in to comment.