Skip to content

Commit 59afd46

Browse files
committed
chore(storage): backend
1 parent bd0334f commit 59afd46

14 files changed

Lines changed: 192 additions & 227 deletions

File tree

crates/node/consensus/src/components/mempool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ mod tests {
7171
let tx2 = vec![4, 5, 6];
7272

7373
assert!(mempool.insert(tx1.clone()));
74-
assert!(mempool.insert(tx2.clone()));
75-
assert!(!mempool.insert(tx1.clone())); // Duplicate
74+
assert!(mempool.insert(tx2));
75+
assert!(!mempool.insert(tx1)); // Duplicate
7676

7777
assert_eq!(mempool.len(), 2);
7878

crates/node/consensus/src/components/snapshot.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,10 @@ mod tests {
185185
Ok(B256::ZERO)
186186
}
187187

188-
async fn compute_root(&self, _changes: &ChangeSet) -> Result<B256, kora_traits::StateDbError> {
188+
async fn compute_root(
189+
&self,
190+
_changes: &ChangeSet,
191+
) -> Result<B256, kora_traits::StateDbError> {
189192
Ok(B256::ZERO)
190193
}
191194

crates/node/consensus/src/ledger.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ mod tests {
271271
Ok(B256::repeat_byte(0xCC))
272272
}
273273

274-
async fn compute_root(&self, _changes: &ChangeSet) -> Result<B256, kora_traits::StateDbError> {
274+
async fn compute_root(
275+
&self,
276+
_changes: &ChangeSet,
277+
) -> Result<B256, kora_traits::StateDbError> {
275278
Ok(B256::ZERO)
276279
}
277280

crates/node/consensus/src/proposal.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,10 @@ mod tests {
288288
Ok(B256::repeat_byte(0x42))
289289
}
290290

291-
async fn compute_root(&self, _changes: &ChangeSet) -> Result<B256, kora_traits::StateDbError> {
291+
async fn compute_root(
292+
&self,
293+
_changes: &ChangeSet,
294+
) -> Result<B256, kora_traits::StateDbError> {
292295
Ok(B256::repeat_byte(0x42))
293296
}
294297

crates/storage/backend/README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
# kora-backend
1+
# `kora-backend`
22

3-
Commonware-storage based backend for Kora QMDB.
3+
<a href="https://github.com/refcell/kora/actions/workflows/ci.yml"><img src="https://github.com/refcell/kora/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
4+
<a href="https://github.com/refcell/kora/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-d1d1f6.svg" alt="License"></a>
45

5-
This crate provides storage implementations using commonware-storage primitives for the three QMDB partitions:
6-
- **AccountStore**: Stores account state (nonce, balance, code hash, generation)
7-
- **StorageStore**: Stores contract storage slots
8-
- **CodeStore**: Stores contract bytecode
6+
Concrete storage backend for Kora QMDB.
7+
8+
This crate implements the `QmdbGettable` and `QmdbBatchable` traits from [`kora-qmdb`](../qmdb) with in-memory stores:
9+
10+
- **AccountStore** - Account state (nonce, balance, code hash, generation)
11+
- **StorageStore** - Contract storage slots
12+
- **CodeStore** - Contract bytecode
913

1014
## Usage
1115

@@ -23,3 +27,7 @@ let backend = CommonwareBackend::open(config).await?;
2327
// Get state root
2428
let root = backend.get_state_root().await?;
2529
```
30+
31+
## License
32+
33+
[MIT License](https://github.com/refcell/kora/blob/main/LICENSE)

crates/storage/backend/src/accounts.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Account store backed by commonware-storage.
22
3-
use alloy_primitives::{keccak256, Address, B256};
3+
use alloy_primitives::{Address, B256, keccak256};
44
use kora_qmdb::{AccountEncoding, QmdbBatchable, QmdbGettable};
55
use std::collections::HashMap;
66
use tokio::sync::RwLock;
@@ -23,10 +23,7 @@ pub struct AccountStore {
2323
impl AccountStore {
2424
/// Create a new account store.
2525
pub fn new() -> Self {
26-
Self {
27-
data: RwLock::new(HashMap::new()),
28-
root_cache: RwLock::new(B256::ZERO),
29-
}
26+
Self { data: RwLock::new(HashMap::new()), root_cache: RwLock::new(B256::ZERO) }
3027
}
3128

3229
/// Get the root hash of the account store.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
//! Commonware-based QMDB backend implementation.
2+
3+
use alloy_primitives::B256;
4+
use async_trait::async_trait;
5+
use kora_handlers::{HandleError, RootProvider};
6+
use kora_qmdb::StateRoot;
7+
8+
use crate::{AccountStore, BackendError, CodeStore, QmdbBackendConfig, StorageStore};
9+
10+
/// Commonware-based QMDB backend.
11+
///
12+
/// Provides storage for accounts, storage slots, and code using
13+
/// commonware-storage primitives.
14+
#[derive(Debug)]
15+
pub struct CommonwareBackend {
16+
accounts: AccountStore,
17+
storage: StorageStore,
18+
code: CodeStore,
19+
}
20+
21+
impl CommonwareBackend {
22+
/// Create a new backend with default in-memory stores.
23+
pub fn new() -> Self {
24+
Self { accounts: AccountStore::new(), storage: StorageStore::new(), code: CodeStore::new() }
25+
}
26+
27+
/// Open a backend with the given configuration.
28+
///
29+
/// Note: Currently this creates in-memory stores regardless of config.
30+
/// Full persistent storage will be added when commonware-storage QMDB
31+
/// is available.
32+
pub async fn open(_config: QmdbBackendConfig) -> Result<Self, BackendError> {
33+
// For now, we just create in-memory stores
34+
// In the future, this will use the config to open persistent stores
35+
Ok(Self::new())
36+
}
37+
38+
/// Get a reference to the accounts store.
39+
pub const fn accounts(&self) -> &AccountStore {
40+
&self.accounts
41+
}
42+
43+
/// Get a mutable reference to the accounts store.
44+
pub const fn accounts_mut(&mut self) -> &mut AccountStore {
45+
&mut self.accounts
46+
}
47+
48+
/// Get a reference to the storage store.
49+
pub const fn storage(&self) -> &StorageStore {
50+
&self.storage
51+
}
52+
53+
/// Get a mutable reference to the storage store.
54+
pub const fn storage_mut(&mut self) -> &mut StorageStore {
55+
&mut self.storage
56+
}
57+
58+
/// Get a reference to the code store.
59+
pub const fn code(&self) -> &CodeStore {
60+
&self.code
61+
}
62+
63+
/// Get a mutable reference to the code store.
64+
pub const fn code_mut(&mut self) -> &mut CodeStore {
65+
&mut self.code
66+
}
67+
68+
/// Get the current state root.
69+
pub async fn get_state_root(&self) -> Result<B256, BackendError> {
70+
let accounts_root = self.accounts.root().await?;
71+
let storage_root = self.storage.root().await?;
72+
let code_root = self.code.root().await?;
73+
Ok(StateRoot::compute(accounts_root, storage_root, code_root))
74+
}
75+
76+
/// Compute the state root.
77+
///
78+
/// This is the same as `get_state_root` for now since we compute
79+
/// roots incrementally.
80+
pub async fn compute_state_root(&mut self) -> Result<B256, BackendError> {
81+
self.get_state_root().await
82+
}
83+
84+
/// Commit pending changes and return the new state root.
85+
///
86+
/// For now, this just computes the root since we apply changes
87+
/// immediately in write_batch.
88+
pub async fn commit(&mut self) -> Result<B256, BackendError> {
89+
self.get_state_root().await
90+
}
91+
}
92+
93+
impl Default for CommonwareBackend {
94+
fn default() -> Self {
95+
Self::new()
96+
}
97+
}
98+
99+
#[async_trait]
100+
impl RootProvider for CommonwareBackend {
101+
async fn state_root(&self) -> Result<B256, HandleError> {
102+
self.get_state_root().await.map_err(|e| HandleError::RootComputation(e.to_string()))
103+
}
104+
105+
async fn compute_root(&mut self) -> Result<B256, HandleError> {
106+
self.compute_state_root().await.map_err(|e| HandleError::RootComputation(e.to_string()))
107+
}
108+
109+
async fn commit_and_get_root(&mut self) -> Result<B256, HandleError> {
110+
self.commit().await.map_err(|e| HandleError::RootComputation(e.to_string()))
111+
}
112+
}
113+
114+
#[cfg(test)]
115+
mod tests {
116+
use super::*;
117+
use std::path::PathBuf;
118+
119+
#[tokio::test]
120+
async fn backend_new() {
121+
let backend = CommonwareBackend::new();
122+
let root = backend.get_state_root().await.unwrap();
123+
// Initial root should be deterministic (based on empty stores)
124+
assert_ne!(root, B256::ZERO); // MMR has non-zero initial root
125+
}
126+
127+
#[tokio::test]
128+
async fn backend_default() {
129+
let backend = CommonwareBackend::default();
130+
assert!(backend.accounts().root().await.is_ok());
131+
}
132+
133+
#[tokio::test]
134+
async fn backend_open() {
135+
let config = QmdbBackendConfig::new(PathBuf::from("/tmp/test"), 1000);
136+
let backend = CommonwareBackend::open(config).await.unwrap();
137+
assert!(backend.get_state_root().await.is_ok());
138+
}
139+
}

crates/storage/backend/src/code.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Code store backed by commonware-storage.
22
3-
use alloy_primitives::{keccak256, B256};
3+
use alloy_primitives::{B256, keccak256};
44
use kora_qmdb::{QmdbBatchable, QmdbGettable};
55
use std::collections::HashMap;
66
use tokio::sync::RwLock;
@@ -23,10 +23,7 @@ pub struct CodeStore {
2323
impl CodeStore {
2424
/// Create a new code store.
2525
pub fn new() -> Self {
26-
Self {
27-
data: RwLock::new(HashMap::new()),
28-
root_cache: RwLock::new(B256::ZERO),
29-
}
26+
Self { data: RwLock::new(HashMap::new()), root_cache: RwLock::new(B256::ZERO) }
3027
}
3128

3229
/// Get the root hash of the code store.

0 commit comments

Comments
 (0)