-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcode.rs
More file actions
121 lines (104 loc) · 3.81 KB
/
code.rs
File metadata and controls
121 lines (104 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Code store bindings for commonware-storage.
use alloy_primitives::B256;
use commonware_cryptography::sha256::Digest as QmdbDigest;
use commonware_storage::{kv::Batchable as _, qmdb::any::VariableConfig, translator::EightCap};
use kora_qmdb::{QmdbBatchable, QmdbGettable};
use crate::{
BackendError,
types::{CodeDb, CodeDbDirty, CodeKey, Context, StoreSlot},
};
/// Code partition backed by commonware-storage.
///
/// Stores contract bytecode keyed by the keccak256 hash of the code (code hash).
/// Values are variable-length byte vectors containing the raw EVM bytecode.
///
/// Implements [`QmdbGettable`] for reads and [`QmdbBatchable`] for batch writes.
/// All writes are atomic and update the authenticated Merkle root.
pub struct CodeStore {
inner: StoreSlot<CodeDb>,
}
pub(crate) struct CodeStoreDirty {
inner: CodeDbDirty,
}
impl CodeStore {
/// Initialize the code store.
pub async fn init(
context: Context,
config: VariableConfig<EightCap, (commonware_codec::RangeCfg<usize>, ())>,
) -> Result<Self, BackendError> {
let inner = CodeDb::init(context, config)
.await
.map_err(|e| BackendError::Storage(e.to_string()))?;
Ok(Self { inner: StoreSlot::new(inner) })
}
/// Return the current authenticated root for the code partition.
pub fn root(&self) -> Result<QmdbDigest, BackendError> {
Ok(self.inner.get()?.root())
}
pub(crate) fn into_dirty(self) -> Result<CodeStoreDirty, BackendError> {
let inner = self.inner.into_inner()?;
Ok(CodeStoreDirty { inner: inner.into_mutable() })
}
}
impl CodeStoreDirty {
pub(crate) fn root(self) -> QmdbDigest {
self.inner.into_merkleized().root()
}
}
impl std::fmt::Debug for CodeStore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CodeStore").finish_non_exhaustive()
}
}
/// Error type for code store operations.
pub type CodeStoreError = BackendError;
const fn code_key(hash: B256) -> CodeKey {
CodeKey::new(hash.0)
}
impl QmdbGettable for CodeStore {
type Key = B256;
type Value = Vec<u8>;
type Error = CodeStoreError;
async fn get(&self, key: &Self::Key) -> Result<Option<Self::Value>, Self::Error> {
self.inner
.get()?
.get(&code_key(*key))
.await
.map_err(|e| BackendError::Storage(e.to_string()))
}
}
impl QmdbBatchable for CodeStore {
async fn write_batch<I>(&mut self, ops: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = (Self::Key, Option<Self::Value>)> + Send,
I::IntoIter: Send,
{
let inner = self.inner.take()?;
let mut dirty = inner.into_mutable();
let mapped = ops.into_iter().map(|(hash, value)| (code_key(hash), value));
dirty.write_batch(mapped).await.map_err(|e| BackendError::Storage(e.to_string()))?;
let merkleized = dirty.into_merkleized();
let (inner, _) =
merkleized.commit(None).await.map_err(|e| BackendError::Storage(e.to_string()))?;
self.inner.restore(inner);
Ok(())
}
}
impl QmdbGettable for CodeStoreDirty {
type Key = B256;
type Value = Vec<u8>;
type Error = CodeStoreError;
async fn get(&self, key: &Self::Key) -> Result<Option<Self::Value>, Self::Error> {
self.inner.get(&code_key(*key)).await.map_err(|e| BackendError::Storage(e.to_string()))
}
}
impl QmdbBatchable for CodeStoreDirty {
async fn write_batch<I>(&mut self, ops: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = (Self::Key, Option<Self::Value>)> + Send,
I::IntoIter: Send,
{
let mapped = ops.into_iter().map(|(hash, value)| (code_key(hash), value));
self.inner.write_batch(mapped).await.map_err(|e| BackendError::Storage(e.to_string()))
}
}