forked from Sovereign-Labs/sovereign-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement EvmDb for WorkingSet (Sovereign-Labs#424)
- Loading branch information
Showing
9 changed files
with
231 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
module-system/module-implementations/sov-evm/src/evm/conversions.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use bytes::Bytes; | ||
|
||
use super::AccountInfo; | ||
use revm::primitives::{AccountInfo as ReVmAccountInfo, U256}; | ||
use revm::primitives::{Bytecode, B256}; | ||
|
||
impl From<AccountInfo> for ReVmAccountInfo { | ||
fn from(info: AccountInfo) -> Self { | ||
Self { | ||
nonce: info.nonce, | ||
balance: U256::from_le_bytes(info.balance), | ||
code: Some(Bytecode::new_raw(Bytes::from(info.code))), | ||
code_hash: B256::from(info.code_hash), | ||
} | ||
} | ||
} | ||
|
||
impl From<ReVmAccountInfo> for AccountInfo { | ||
fn from(info: ReVmAccountInfo) -> Self { | ||
Self { | ||
balance: info.balance.to_le_bytes(), | ||
code_hash: info.code_hash.to_fixed_bytes(), | ||
code: info.code.unwrap_or_default().bytes().to_vec(), | ||
nonce: info.nonce, | ||
} | ||
} | ||
} |
58 changes: 37 additions & 21 deletions
58
module-system/module-implementations/sov-evm/src/evm/db.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,53 @@ | ||
use std::convert::Infallible; | ||
|
||
use super::{Address, DbAccount}; | ||
use revm::{ | ||
db::{CacheDB, EmptyDB}, | ||
primitives::{Account, AccountInfo, Bytecode, HashMap, B160, B256, U256}, | ||
Database, DatabaseCommit, | ||
primitives::{AccountInfo as ReVmAccountInfo, Bytecode, B160, B256, U256}, | ||
Database, | ||
}; | ||
use sov_state::WorkingSet; | ||
use std::convert::Infallible; | ||
|
||
pub(crate) struct EvmDb<'a> { | ||
pub(crate) db: &'a mut CacheDB<EmptyDB>, | ||
pub(crate) struct EvmDb<'a, C: sov_modules_api::Context> { | ||
pub(crate) accounts: sov_state::StateMap<Address, DbAccount>, | ||
pub(crate) working_set: &'a mut WorkingSet<C::Storage>, | ||
} | ||
|
||
impl<'a> Database for EvmDb<'a> { | ||
impl<'a, C: sov_modules_api::Context> EvmDb<'a, C> { | ||
pub(crate) fn new( | ||
accounts: sov_state::StateMap<Address, DbAccount>, | ||
working_set: &'a mut WorkingSet<C::Storage>, | ||
) -> Self { | ||
Self { | ||
accounts, | ||
working_set, | ||
} | ||
} | ||
} | ||
|
||
impl<'a, C: sov_modules_api::Context> Database for EvmDb<'a, C> { | ||
type Error = Infallible; | ||
|
||
fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error> { | ||
self.db.basic(address) | ||
fn basic(&mut self, address: B160) -> Result<Option<ReVmAccountInfo>, Self::Error> { | ||
let db_account = self.accounts.get(&address.0, self.working_set); | ||
Ok(db_account.map(|acc| acc.info.into())) | ||
} | ||
|
||
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> { | ||
self.db.code_by_hash(code_hash) | ||
fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> { | ||
panic!("Should not be called. Contract code is already loaded"); | ||
} | ||
|
||
fn storage(&mut self, address: B160, index: U256) -> Result<U256, Self::Error> { | ||
self.db.storage(address, index) | ||
} | ||
|
||
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> { | ||
self.db.block_hash(number) | ||
let storage_value = if let Some(acc) = self.accounts.get(&address.0, self.working_set) { | ||
let key = index.to_le_bytes(); | ||
let storage_value = acc.storage.get(&key, self.working_set).unwrap_or_default(); | ||
U256::from_le_bytes(storage_value) | ||
} else { | ||
U256::default() | ||
}; | ||
|
||
Ok(storage_value) | ||
} | ||
} | ||
|
||
impl<'a> DatabaseCommit for EvmDb<'a> { | ||
fn commit(&mut self, changes: HashMap<B160, Account>) { | ||
self.db.commit(changes) | ||
fn block_hash(&mut self, _number: U256) -> Result<B256, Self::Error> { | ||
todo!("block_hash not yet implemented") | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
module-system/module-implementations/sov-evm/src/evm/db_commit.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use super::{db::EvmDb, DbAccount}; | ||
use revm::{ | ||
primitives::{Account, HashMap, B160}, | ||
DatabaseCommit, | ||
}; | ||
|
||
impl<'a, C: sov_modules_api::Context> DatabaseCommit for EvmDb<'a, C> { | ||
fn commit(&mut self, changes: HashMap<B160, Account>) { | ||
for (address, account) in changes { | ||
let address = address.0; | ||
|
||
// TODO figure out what to do when account is destroyed. | ||
// https://github.com/Sovereign-Labs/sovereign-sdk/issues/425 | ||
if account.is_destroyed { | ||
todo!("Account destruction not supported") | ||
} | ||
|
||
let accounts_prefix = self.accounts.prefix(); | ||
|
||
let mut db_account = self | ||
.accounts | ||
.get(&address, self.working_set) | ||
.unwrap_or_else(|| DbAccount::new(accounts_prefix, address)); | ||
|
||
db_account.info = account.info.into(); | ||
|
||
for (key, value) in account.storage.into_iter() { | ||
let key = key.to_le_bytes(); | ||
let value = value.present_value().to_le_bytes(); | ||
db_account.storage.set(&key, &value, self.working_set); | ||
} | ||
|
||
self.accounts.set(&address, &db_account, self.working_set) | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
module-system/module-implementations/sov-evm/src/evm/db_init.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use super::{db::EvmDb, AccountInfo, Address, DbAccount}; | ||
#[cfg(test)] | ||
use revm::{ | ||
db::{CacheDB, EmptyDB}, | ||
primitives::B160, | ||
}; | ||
|
||
/// Initializes database with a predefined account. | ||
pub(crate) trait InitEvmDb { | ||
fn insert_account_info(&mut self, address: Address, acc: AccountInfo); | ||
} | ||
|
||
impl<'a, C: sov_modules_api::Context> InitEvmDb for EvmDb<'a, C> { | ||
fn insert_account_info(&mut self, sender: Address, info: AccountInfo) { | ||
let parent_prefix = self.accounts.prefix(); | ||
let db_account = DbAccount::new_with_info(parent_prefix, sender, info); | ||
|
||
self.accounts.set(&sender, &db_account, self.working_set); | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
impl InitEvmDb for CacheDB<EmptyDB> { | ||
fn insert_account_info(&mut self, sender: Address, acc: AccountInfo) { | ||
self.insert_account_info(B160::from_slice(&sender), acc.into()); | ||
} | ||
} |
9 changes: 4 additions & 5 deletions
9
module-system/module-implementations/sov-evm/src/evm/executor.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 51 additions & 1 deletion
52
module-system/module-implementations/sov-evm/src/evm/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,54 @@ | ||
mod db; | ||
use sov_state::Prefix; | ||
|
||
mod conversions; | ||
pub(crate) mod db; | ||
mod db_commit; | ||
mod db_init; | ||
mod executor; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
pub(crate) type Address = [u8; 20]; | ||
pub(crate) type SovU256 = [u8; 32]; | ||
|
||
// Stores information about an EVM account | ||
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone, Default)] | ||
pub(crate) struct AccountInfo { | ||
pub(crate) balance: SovU256, | ||
pub(crate) code_hash: SovU256, | ||
// TODO: `code` can be a huge chunk of data. We can use `StateValue` and lazy load it only when needed. | ||
// https://github.com/Sovereign-Labs/sovereign-sdk/issues/425 | ||
pub(crate) code: Vec<u8>, | ||
pub(crate) nonce: u64, | ||
} | ||
|
||
/// Stores information about an EVM account and a corresponding account state. | ||
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone)] | ||
pub(crate) struct DbAccount { | ||
pub(crate) info: AccountInfo, | ||
pub(crate) storage: sov_state::StateMap<SovU256, SovU256>, | ||
} | ||
|
||
impl DbAccount { | ||
fn new(parent_prefix: &Prefix, address: Address) -> Self { | ||
let prefix = Self::create_storage_prefix(parent_prefix, address); | ||
Self { | ||
info: Default::default(), | ||
storage: sov_state::StateMap::new(prefix), | ||
} | ||
} | ||
|
||
fn new_with_info(parent_prefix: &Prefix, address: Address, info: AccountInfo) -> Self { | ||
let prefix = Self::create_storage_prefix(parent_prefix, address); | ||
Self { | ||
info, | ||
storage: sov_state::StateMap::new(prefix), | ||
} | ||
} | ||
|
||
fn create_storage_prefix(parent_prefix: &Prefix, address: Address) -> Prefix { | ||
let mut prefix = parent_prefix.as_aligned_vec().clone().into_inner(); | ||
prefix.extend_from_slice(&address); | ||
Prefix::new(prefix) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters