Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/database/interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ use state::{Account, AccountInfo, Bytecode};
#[cfg(feature = "asyncdb")]
pub mod async_db;
pub mod empty_db;
pub mod try_commit;

#[cfg(feature = "asyncdb")]
pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
pub use empty_db::{EmptyDB, EmptyDBTyped};
pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};

/// EVM database interface.
#[auto_impl(&mut, Box)]
Expand Down
84 changes: 84 additions & 0 deletions crates/database/interface/src/try_commit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::DatabaseCommit;
use core::{convert::Infallible, error::Error, fmt};
use primitives::{Address, HashMap};
use state::Account;
use std::sync::Arc;

/// EVM database commit interface that can fail.
///
/// This is intended for use with types that may fail to commit changes, e.g.
/// because they are directly interacting with the filesystem, or must arrange
/// access to a shared resource.
pub trait TryDatabaseCommit {
/// Error type for when [`TryDatabaseCommit::try_commit`] fails.
type Error: Error;

/// Attempt to commit changes to the database.
fn try_commit(&mut self, changes: HashMap<Address, Account>) -> Result<(), Self::Error>;
}

impl<Db> TryDatabaseCommit for Db
where
Db: DatabaseCommit,
{
type Error = Infallible;

#[inline]
fn try_commit(&mut self, changes: HashMap<Address, Account>) -> Result<(), Self::Error> {
self.commit(changes);
Ok(())
}
}

/// Error type for implementation of [`TryDatabaseCommit`] on
/// [`Arc`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ArcUpgradeError;

impl fmt::Display for ArcUpgradeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Arc reference is not unique, cannot mutate")
}
}

impl Error for ArcUpgradeError {}

impl<Db> TryDatabaseCommit for Arc<Db>
where
Db: DatabaseCommit + Send + Sync,
{
type Error = ArcUpgradeError;

#[inline]
fn try_commit(&mut self, changes: HashMap<Address, Account>) -> Result<(), Self::Error> {
Arc::get_mut(self)
.map(|db| db.commit(changes))
.ok_or(ArcUpgradeError)
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::DatabaseCommit;
use std::sync::Arc;

struct MockDb;

impl DatabaseCommit for MockDb {
fn commit(&mut self, _changes: HashMap<Address, Account>) {}
}

#[test]
fn arc_try_commit() {
let mut db = Arc::new(MockDb);
let db_2 = Arc::clone(&db);

assert_eq!(
db.try_commit(Default::default()).unwrap_err(),
ArcUpgradeError
);
drop(db_2);
db.try_commit(Default::default()).unwrap();
}
}
Loading