Skip to content

Commit 198b270

Browse files
authored
Merge pull request #16 from movementlabsxyz/0xmovses/db-remodel
ENG-115 Make `executor.rs` compatible with AptosVm
2 parents 0d8b13f + 34887b6 commit 198b270

File tree

8 files changed

+233
-72
lines changed

8 files changed

+233
-72
lines changed

Cargo.toml

+15-7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ borsh = { version = "0.10.3", features = ["rc", "bytes"] }
3939
tracing = "0.1.40"
4040
tokio = { version = "1.35.1", features = ["full"] }
4141
tempfile = "3.5"
42+
fail = "0.5.1"
4243
jsonrpsee = { version = "0.20.1", features = ["jsonrpsee-types"] }
4344
proptest = { version = "1.3.1", default-features = false, features = ["alloc"] }
4445
poem-openapi = { version = "=2.0.11", features = ["swagger-ui", "url"] }
@@ -81,13 +82,20 @@ ethers-middleware = { version = "=2.0.10", default-features = false }
8182

8283
# Aptos dependencies
8384
# We use a forked version so that we can override dependency versions. This is required
84-
# to be avoid depenedency conflicts with other Sovereign Labs crates.
85-
aptos-sdk = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
86-
aptos-consensus-types = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
87-
aptos-crypto = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
88-
aptos-db = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
89-
aptos-api-types = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
90-
aptos-api = { git = "https://github.com/0xmovses/aptos-core", rev = "d3cc82ac6739bd1b9f2f532ddfe79fc261dceb5d" }
85+
# to be avoid depenedency conflicts with other Sovereign Labs crates.
86+
aptos-vm = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
87+
aptos-sdk = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
88+
aptos-consensus-types = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
89+
aptos-crypto = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
90+
aptos-db = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
91+
aptos-api-types = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
92+
aptos-types = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
93+
aptos-api = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
94+
aptos-storage-interface = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
95+
aptos-block-executor = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
96+
aptos-vm-types = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
97+
aptos-vm-logging = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
98+
aptos-language-e2e-tests = { git = "https://github.com/0xmovses/aptos-core", rev = "bfa7d8f9a6467e4b5c84344c2024f60a306536d4" }
9199

92100
# https://github.com/paradigmxyz/reth/tree/c0655fed8915490f82d4acf8900a16a10554cbfb
93101
reth-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "c0655fed8915490f82d4acf8900a16a10554cbfb", default-features = false }

protocol-units/sov-modules/sov-aptos-vm/Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ sov-state = { workspace = true }
1919
sov-chain-state = { workspace = true }
2020

2121
anyhow = { workspace = true }
22+
fail = { workspace = true }
2223
thiserror = { workspace = true }
2324
bytes = { workspace = true }
2425
schemars = { workspace = true, optional = true }
@@ -37,13 +38,19 @@ derive_more = { workspace = true, default-features = true }
3738
lazy_static = "1.4.0"
3839
secp256k1 = { workspace = true }
3940

41+
aptos-vm = { workspace = true }
4042
aptos-sdk = { workspace = true }
4143
aptos-crypto = { workspace = true }
4244
aptos-consensus-types = { workspace = true }
4345
aptos-db = { workspace = true }
4446
aptos-api = { workspace = true }
4547
aptos-api-types = { workspace = true }
46-
48+
aptos-types = { workspace = true }
49+
aptos-storage-interface = { workspace = true }
50+
aptos-block-executor = { workspace = true }
51+
aptos-vm-types = { workspace = true }
52+
aptos-vm-logging = { workspace = true }
53+
aptos-language-e2e-tests = { workspace = true }
4754

4855
alloy-sol-types = { version = "0.6" }
4956
revm = { workspace = true, features = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use anyhow;
2+
use aptos_storage_interface::state_view::{DbStateView, DbStateViewAtVersion};
3+
use aptos_storage_interface::DbReader;
4+
use aptos_types::chain_id::ChainId;
5+
use aptos_types::transaction::Version;
6+
use std::sync::Arc;
7+
8+
/// Context holds Aptos scope context this is a stripped back and adapted version
9+
/// of the `aptos_api::context::Context` struct to make it compatible with Sovereign Labs
10+
/// whilst still being able to interact with the Aptos VM.
11+
#[derive(Clone)]
12+
pub struct Context {
13+
chain_id: ChainId,
14+
pub db: Arc<dyn DbReader>,
15+
// mp_sender: MempoolClientSender,
16+
// pub node_config: Arc<NodeConfig>,
17+
// gas_schedule_cache: Arc<RwLock<GasScheduleCache>>,
18+
// gas_estimation_cache: Arc<RwLock<GasEstimationCache>>,
19+
// gas_limit_cache: Arc<RwLock<GasLimitCache>>,
20+
// view_function_stats: Arc<FunctionStats>,
21+
// simulate_txn_stats: Arc<FunctionStats>,
22+
// pub table_info_reader: Option<Arc<dyn TableInfoReader>>,
23+
}
24+
25+
impl Context {
26+
pub fn new(chain_id: ChainId, db: Arc<dyn DbReader>) -> Self {
27+
Self { chain_id, db }
28+
}
29+
30+
pub fn state_view_at_version(&self, version: Version) -> Result<DbStateView, anyhow::Error> {
31+
Ok(self.db.state_view_at_version(Some(version))?)
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,71 @@
11
use crate::aptos::primitive_types::AptosStorage;
22
use aptos_api_types::{Address, HexEncodedBytes, MoveModule, MoveModuleBytecode, MoveResource};
3+
use aptos_crypto::HashValue;
4+
use aptos_db::AptosDB;
35
use aptos_sdk::rest_client::Account;
4-
use sov_modules_api::{StateMapAccessor, WorkingSet};
5-
use sov_state::codec::BcsCodec;
6-
use std::convert::Infallible;
7-
8-
use super::{AccountInfo, DbAccount};
6+
use aptos_storage_interface::state_view::DbStateViewAtVersion;
7+
use aptos_storage_interface::DbReader;
8+
use aptos_types::state_store::errors::StateviewError;
9+
use aptos_types::state_store::state_key::StateKey;
10+
use aptos_types::state_store::state_storage_usage::StateStorageUsage;
11+
use aptos_types::state_store::{state_value::StateValue as AptosStateValue, TStateView};
12+
use aptos_types::transaction::Version;
13+
use sov_modules_api::{StateMap, StateMapAccessor, StateValue, WorkingSet};
14+
use std::sync::Arc;
915

16+
type Result<T, E = StateviewError> = std::result::Result<T, E>;
1017
/// The Aptos Database structure for storing and working with accounts and their modules.
11-
pub(crate) struct AptosDb<'a, S: sov_modules_api::Spec> {
12-
/// Accounts storage
13-
pub(crate) accounts: sov_modules_api::StateMap<Address, DbAccount, BcsCodec>,
14-
/// Modules storage
15-
pub(crate) modules: sov_modules_api::StateMap<Address, Vec<MoveModule>, BcsCodec>,
16-
/// Resources storage
17-
pub(crate) resources: sov_modules_api::StateMap<Address, Vec<MoveResource>, BcsCodec>,
18+
pub(crate) struct SovAptosDb<'a, S: sov_modules_api::Spec> {
19+
pub(crate) state_kv_db: StateMap<Version, AptosStateValue>,
1820
/// Working set
1921
pub(crate) working_set: &'a mut WorkingSet<S>,
2022
}
2123

22-
impl<'a, S: sov_modules_api::Spec> AptosDb<'a, S> {
23-
pub(crate) fn new(
24-
accounts: sov_modules_api::StateMap<Address, DbAccount, BcsCodec>,
25-
modules: sov_modules_api::StateMap<Address, Vec<MoveModule>, BcsCodec>,
26-
resources: sov_modules_api::StateMap<Address, Vec<MoveResource>, BcsCodec>,
27-
working_set: &'a mut WorkingSet<S>,
28-
) -> Self {
29-
Self { accounts, modules, resources, working_set }
24+
impl<'a, S: sov_modules_api::Spec> SovAptosDb<'a, S> {
25+
pub(crate) fn new(working_set: &'a mut WorkingSet<S>, db: StateValue<AptosDB>) -> Self {
26+
Self { working_set, db }
3027
}
31-
}
3228

33-
impl<'a, S: sov_modules_api::Spec> AptosStorage for AptosDb<'a, S> {
34-
type Error = Infallible;
29+
/// Get state view at `Version`, this is analogous to `blockheight`.
30+
/// `Version` is a type alias for `u64` in the `aptos_types` module.
31+
/// Source code: https://github.com/0xmovses/aptos-core/blob/bd1644729bc2598d9769fbf556797d5a4f51bf35/types/src/transaction/mod.rs#L77
32+
///
33+
/// For reading state from the SovAptosDb. We purposefully do not implement the Aptos native `DbReader` trait
34+
/// because it is `Send` and `Sync`. The sov_modules_api::StateMap is not `Send` and `Sync` so instead we add
35+
/// this custom method.
36+
pub(crate) fn state_view_at_version(
37+
&self,
38+
version: Option<Version>,
39+
) -> Result<DbStateView<'a, S>> {
40+
Ok(DbStateView { db: self.clone(), version, verify_against_state_root_hash: None })
41+
}
42+
}
3543

36-
fn account(&mut self, account: Account) -> Result<AccountInfo, Self::Error> {
37-
let db_account = self
38-
.accounts
39-
.get(&Address::from(account.authentication_key.account_address()), self.working_set)
40-
.expect("Account not found");
44+
/// The DbStateView that is passed to the VM for transaction execution.
45+
/// We don't use the Aptos native `DbStateView` because its `db` field is `Arc<dyn DbReader>`,
46+
/// meaning it's a dynamically dispatched trait object, so unable to derive
47+
/// serialization/deserialization. Instead, in our custom type we use a concrete type `SovAptosDb`.
48+
pub struct DbStateView<'a, S>
49+
where
50+
S: sov_modules_api::Spec,
51+
{
52+
db: &'a SovAptosDb<'a, S>,
53+
version: Option<Version>,
54+
verify_against_state_root_hash: Option<HashValue>,
55+
}
4156

42-
Ok(db_account.info)
43-
}
57+
//`DbStateView` must implement `TStateView` trait for `AptosVM` to execute transactions.
58+
impl<'a, S> TStateView for DbStateView<'a, S>
59+
where
60+
S: sov_modules_api::Spec,
61+
{
62+
type Key = StateKey;
4463

45-
fn resources(&mut self, account: Account) -> Result<Vec<MoveResource>, Self::Error> {
46-
let resources = self
47-
.resources
48-
.get(&Address::from(account.authentication_key.account_address()), self.working_set)
49-
.expect("Modules not found");
50-
Ok(resources)
64+
fn get_state_value(&self, state_key: &StateKey) -> Result<Option<AptosStateValue>> {
65+
self.get(state_key).map_err(Into::into)
5166
}
5267

53-
fn modules(&mut self, account: Account) -> Result<Vec<MoveModule>, Self::Error> {
54-
let modules = self
55-
.modules
56-
.get(&Address::from(account.authentication_key.account_address()), self.working_set)
57-
.expect("Modules not found");
58-
Ok(modules)
68+
fn get_usage(&self) -> Result<StateStorageUsage> {
69+
self.db.get_state_storage_usage(self.version).map_err(Into::into)
5970
}
6071
}
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,121 @@
1-
use std::convert::Infallible;
1+
use sov_modules_api::{StateMap, StateMapAccessor, StateValue, StateValueAccessor, WorkingSet};
2+
use aptos_block_executor::task::{ExecutionStatus, ExecutorTask};
3+
use aptos_db::AptosDB;
4+
use aptos_sdk::move_types::vm_status::StatusCode;
5+
use aptos_types::block_executor::partitioner::TxnIndex;
6+
use aptos_types::state_store::StateView;
7+
use aptos_types::transaction::{Transaction, TransactionOutput, Version, WriteSetPayload};
8+
use aptos_types::vm_status::VMStatus;
9+
use aptos_types::{
10+
chain_id::ChainId, transaction::signature_verified_transaction::SignatureVerifiedTransaction,
11+
};
12+
use aptos_types::block_executor::config::BlockExecutorConfigFromOnchain;
13+
use aptos_vm::block_executor::AptosTransactionOutput;
14+
use aptos_vm::data_cache::AsMoveResolver;
15+
use aptos_vm::{, VMExecutor}
16+
use aptos_vm::AptosVM;
17+
use aptos_vm_logging::{log_schema::AdapterLogSchema, prelude::*};
18+
use aptos_vm_types::output::VMOutput;
19+
use aptos_language_e2e_tests::executor::FakeExecutor;
20+
use aptos_vm_types::resolver::{ExecutorView, ResourceGroupView};
21+
use fail::fail_point;
22+
use crate::aptos::db::{AptosDb, SovAptosDb};
223

3-
use reth_primitives::TransactionSignedEcRecovered;
4-
use revm::primitives::{CfgEnvWithHandlerCfg, EVMError, ExecutionResult};
5-
use revm::{self, Database, DatabaseCommit};
24+
pub(crate) struct AptosExecutor<'a, S> {
25+
vm: AptosVM,
26+
base_view: &'a S,
27+
}
28+
29+
impl<'a, S: 'a + StateView + Sync> ExecutorTask for AptosExecutor<'a, S> {
30+
type Txn = SignatureVerifiedTransaction;
31+
type Output = AptosTransactionOutput;
32+
type Error = VMStatus;
33+
type Argument = &'a S;
34+
35+
fn init(argument: &'a S) -> Self {
36+
// AptosVM has to be initialized using configs from storage
37+
let vm = AptosVM::new(&argument.as_move_resolver(), Some(true));
38+
Self { vm, base_view: argument }
39+
}
640

7-
use super::primitive_types::BlockEnv;
41+
// This function is called by the BlockExecutor for each transaction is intends
42+
// to execute (via the ExecutorTask trait). It can be as a part of sequential
43+
// execution, or speculatively as a part of a parallel execution.
44+
fn execute_transaction(
45+
&self,
46+
executor_with_group_view: &(impl ExecutorView + ResourceGroupView),
47+
txn: &SignatureVerifiedTransaction,
48+
txn_idx: u32,
49+
) -> ExecutionStatus<AptosTransactionOutput, VMStatus> {
50+
fail_point!("aptos_vm::vm_wrapper::execute_transaction", |_| {
51+
ExecutionStatus::DelayedFieldsCodeInvariantError("fail points error".into())
52+
});
853

9-
pub(crate) fn execute_tx<DB: Database<Error = Infallible> + DatabaseCommit>(
10-
_db: DB,
11-
_block_env: &BlockEnv,
12-
_tx: &TransactionSignedEcRecovered,
13-
_config_env: CfgEnvWithHandlerCfg,
14-
) -> Result<ExecutionResult, EVMError<Infallible>> {
15-
todo!()
54+
let log_context = AdapterLogSchema::new(self.base_view.id(), txn_idx as usize);
55+
let resolver = self.vm.as_move_resolver_with_group_view(executor_with_group_view);
56+
57+
match self.vm.execute_single_transaction(txn, &resolver, &log_context) {
58+
Ok((vm_status, vm_output)) => {
59+
if vm_status.status_code() == StatusCode::SPECULATIVE_EXECUTION_ABORT_ERROR {
60+
ExecutionStatus::SpeculativeExecutionAbortError(
61+
vm_status.message().cloned().unwrap_or_default(),
62+
)
63+
} else if vm_status.status_code()
64+
== StatusCode::DELAYED_MATERIALIZATION_CODE_INVARIANT_ERROR
65+
{
66+
ExecutionStatus::DelayedFieldsCodeInvariantError(
67+
vm_status.message().cloned().unwrap_or_default(),
68+
)
69+
} else {
70+
assert!(
71+
Self::is_transaction_dynamic_change_set_capable(txn),
72+
"DirectWriteSet should always create SkipRest transaction, validate_waypoint_change_set provides this guarantee"
73+
);
74+
ExecutionStatus::Success(AptosTransactionOutput::new(vm_output))
75+
}
76+
},
77+
// execute_single_transaction only returns an error when transactions that should never fail
78+
// (BlockMetadataTransaction and GenesisTransaction) return an error themselves.
79+
Err(err) => {
80+
if err.status_code() == StatusCode::SPECULATIVE_EXECUTION_ABORT_ERROR {
81+
ExecutionStatus::SpeculativeExecutionAbortError(
82+
err.message().cloned().unwrap_or_default(),
83+
)
84+
} else if err.status_code()
85+
== StatusCode::DELAYED_MATERIALIZATION_CODE_INVARIANT_ERROR
86+
{
87+
ExecutionStatus::DelayedFieldsCodeInvariantError(
88+
err.message().cloned().unwrap_or_default(),
89+
)
90+
} else {
91+
ExecutionStatus::Abort(err)
92+
}
93+
},
94+
}
95+
}
96+
97+
fn is_transaction_dynamic_change_set_capable(txn: &Self::Txn) -> bool {
98+
if txn.is_valid() {
99+
if let Transaction::GenesisTransaction(WriteSetPayload::Direct(_)) = txn.expect_valid()
100+
{
101+
// WriteSetPayload::Direct cannot be handled in mode where delayed_field_optimization or
102+
// resource_groups_split_in_change_set is enabled.
103+
return false;
104+
}
105+
}
106+
true
107+
}
16108
}
17109

18-
pub(crate) fn inspect<DB: Database<Error = Infallible> + DatabaseCommit>(
19-
_db: DB,
20-
_block_env: &BlockEnv,
21-
_tx: revm::primitives::TxEnv,
22-
_config_env: CfgEnvWithHandlerCfg,
23-
) -> Result<revm::primitives::ResultAndState, EVMError<Infallible>> {
24-
todo!()
110+
pub fn execute_block<S>(
111+
db: SovAptosDb<S>,
112+
version: Version,
113+
transactions: &[SignatureVerifiedTransaction],
114+
onchain_config: BlockExecutorConfigFromOnchain,
115+
)
116+
where S: sov_modules_api::Spec
117+
{
118+
let state= db.state_view_at_version(Some(version)).expect("Failed to create state view");
119+
120+
let foo= AptosVM::execute_block(transactions, &state, onchain_config);
25121
}

protocol-units/sov-modules/sov-aptos-vm/src/aptos/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use sov_modules_api::StateMap;
88
use sov_state::Prefix;
99

1010
//pub(crate) mod call;
11+
mod context;
1112
pub(crate) mod db;
1213
mod db_commit;
1314
pub(crate) mod db_init;

protocol-units/sov-modules/sov-aptos-vm/src/aptos/primitive_types.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
use aptos_api_types::{AccountData, MoveModule, MoveModuleBytecode, MoveResource};
22
use std::ops::Range;
33

4+
use crate::aptos::db::SovAptosDb;
45
use crate::aptos::AccountInfo;
56
use aptos_consensus_types::{block::Block, block_data::BlockData};
67
use aptos_crypto::{bls12381::Signature, hash::HashValue};
8+
use aptos_db::ledger_db::LedgerDb;
79
use aptos_sdk::rest_client::Account;
810
use aptos_sdk::types::account_address::AccountAddress;
11+
use aptos_storage_interface::state_view::DbStateView;
12+
use aptos_types::on_chain_config::Version;
913
use auto_impl::auto_impl;
1014
use reth_primitives::{Header, SealedHeader, TransactionSigned, TransactionSignedEcRecovered};
1115
use reth_revm::precompile::HashMap;
1216
use revm::primitives::{Address, EVMError, B256};
1317

18+
pub type SovLedgerDb = LedgerDb;
19+
1420
/// Aptos database interface
1521
/// This trait is loosely modelled on `revm::Database` as this trait is used
1622
/// in the sov-aptos module.

0 commit comments

Comments
 (0)