use crate::errors::RuntimeError;
use crate::internal_prelude::*;
use radix_engine_interface::types::*;
use radix_substate_store_interface::db_key_mapper::SubstateKeyContent;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CallbackError<E, C> {
Error(E),
CallbackError(C),
}
impl<E> CallbackError<E, RuntimeError> {
pub fn to_runtime_error<F: FnOnce(E) -> RuntimeError>(self, f: F) -> RuntimeError {
match self {
CallbackError::Error(e) => f(e),
CallbackError::CallbackError(c) => c,
}
}
}
impl<E, C> CallbackError<E, C> {
pub fn map<N, F: FnOnce(E) -> N>(self, f: F) -> CallbackError<N, C> {
match self {
CallbackError::Error(e) => CallbackError::Error(f(e)),
CallbackError::CallbackError(c) => CallbackError::CallbackError(c),
}
}
}
pub type NodeSubstates = BTreeMap<PartitionNumber, BTreeMap<SubstateKey, IndexedScryptoValue>>;
pub(crate) trait NodeSubstatesExt {
fn into_node_state_updates(self) -> NodeStateUpdates;
}
impl NodeSubstatesExt for NodeSubstates {
fn into_node_state_updates(self) -> NodeStateUpdates {
let mut updates = NodeStateUpdates::empty();
for (partition_num, substates) in self {
for (substate_key, indexed_scrypto_value) in substates {
updates.of_partition(partition_num).mut_update_substate(
substate_key,
DatabaseUpdate::Set(indexed_scrypto_value.unpack().0),
);
}
}
updates
}
}
pub enum TrackedSubstateInfo {
New,
Updated,
Unmodified,
}
pub trait CommitableSubstateStore {
fn mark_as_transient(
&mut self,
node_id: NodeId,
partition_num: PartitionNumber,
substate_key: SubstateKey,
);
fn create_node<E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: NodeId,
node_substates: NodeSubstates,
on_io_access: &mut F,
) -> Result<(), E>;
fn get_tracked_substate_info(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
substate_key: &SubstateKey,
) -> TrackedSubstateInfo;
fn read_substate(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
substate_key: &SubstateKey,
) -> Option<&IndexedScryptoValue> {
self.get_substate(node_id, partition_num, substate_key, &mut |_| -> Result<
(),
(),
> {
Ok(())
})
.unwrap()
}
fn get_substate<E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
substate_key: &SubstateKey,
on_io_access: &mut F,
) -> Result<Option<&IndexedScryptoValue>, E>;
fn set_substate<E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: NodeId,
partition_num: PartitionNumber,
substate_key: SubstateKey,
substate_value: IndexedScryptoValue,
on_io_access: &mut F,
) -> Result<(), E>;
fn force_write(
&mut self,
node_id: &NodeId,
partition_num: &PartitionNumber,
substate_key: &SubstateKey,
);
fn remove_substate<E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
substate_key: &SubstateKey,
on_io_access: &mut F,
) -> Result<Option<IndexedScryptoValue>, E>;
fn scan_keys<K: SubstateKeyContent, E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
count: u32,
on_io_access: &mut F,
) -> Result<Vec<SubstateKey>, E>;
fn drain_substates<K: SubstateKeyContent, E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
count: u32,
on_io_access: &mut F,
) -> Result<Vec<(SubstateKey, IndexedScryptoValue)>, E>;
fn scan_sorted_substates<E, F: FnMut(IOAccess) -> Result<(), E>>(
&mut self,
node_id: &NodeId,
partition_num: PartitionNumber,
count: u32,
on_io_access: &mut F,
) -> Result<Vec<(SortedKey, IndexedScryptoValue)>, E>;
fn delete_partition(&mut self, node_id: &NodeId, partition_num: PartitionNumber);
fn get_commit_info(&mut self) -> StoreCommitInfo;
}
#[derive(Debug, Clone, Copy)]
pub struct CanonicalPartition {
pub node_id: NodeId,
pub partition_number: PartitionNumber,
}
#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
pub struct CanonicalSubstateKey {
pub node_id: NodeId,
pub partition_number: PartitionNumber,
pub substate_key: SubstateKey, }
impl CanonicalSubstateKey {
pub fn of(partition: CanonicalPartition, substate_key: SubstateKey) -> Self {
Self {
node_id: partition.node_id,
partition_number: partition.partition_number,
substate_key,
}
}
}
impl CanonicalSubstateKey {
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.node_id.as_bytes().len()
+ 1
+ match &self.substate_key {
SubstateKey::Field(_) => 1,
SubstateKey::Map(k) => k.len(),
SubstateKey::Sorted(k) => 2 + k.1.len(),
}
}
}
#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
pub enum IOAccess {
ReadFromDb(CanonicalSubstateKey, usize),
ReadFromDbNotFound(CanonicalSubstateKey),
TrackSubstateUpdated {
canonical_substate_key: CanonicalSubstateKey,
old_size: Option<usize>,
new_size: Option<usize>,
},
HeapSubstateUpdated {
canonical_substate_key: CanonicalSubstateKey,
old_size: Option<usize>,
new_size: Option<usize>,
},
}
impl IOAccess {
pub fn node_id(&self) -> NodeId {
match self {
IOAccess::ReadFromDb(key, _)
| IOAccess::ReadFromDbNotFound(key)
| IOAccess::TrackSubstateUpdated {
canonical_substate_key: key,
..
}
| IOAccess::HeapSubstateUpdated {
canonical_substate_key: key,
..
} => key.node_id,
}
}
}
pub type StoreCommitInfo = Vec<StoreCommit>;
#[derive(Debug, Clone)]
pub enum StoreCommit {
Insert {
canonical_substate_key: CanonicalSubstateKey,
size: usize,
},
Update {
canonical_substate_key: CanonicalSubstateKey,
size: usize,
old_size: usize,
},
Delete {
canonical_substate_key: CanonicalSubstateKey,
old_size: usize,
},
}
impl StoreCommit {
pub fn node_id(&self) -> NodeId {
match self {
StoreCommit::Insert {
canonical_substate_key,
..
}
| StoreCommit::Update {
canonical_substate_key,
..
}
| StoreCommit::Delete {
canonical_substate_key,
..
} => canonical_substate_key.node_id,
}
}
pub fn len_increase(&self) -> usize {
match self {
StoreCommit::Insert {
canonical_substate_key,
size,
..
} => canonical_substate_key.len() + *size,
StoreCommit::Update { size, old_size, .. } => (*size).saturating_sub(*old_size),
StoreCommit::Delete { .. } => 0, }
}
}