use crate::db::MemoryDB;
use crate::networks::ACTOR_BUNDLES_METADATA;
use crate::rpc::eth::trace::state_diff::build_state_diff;
use crate::rpc::eth::trace::types::StateDiff;
use crate::rpc::eth::types::EthAddress;
use crate::shim::address::Address as FilecoinAddress;
use crate::shim::econ::TokenAmount;
use crate::shim::machine::BuiltinActor;
use crate::shim::state_tree::{ActorState, StateTree, StateTreeVersion};
use crate::utils::db::CborStoreExt as _;
use ahash::HashSet;
use cid::Cid;
use std::sync::Arc;
pub fn create_test_actor(balance_atto: u64, sequence: u64) -> ActorState {
ActorState::new(
Cid::default(), Cid::default(), TokenAmount::from_atto(balance_atto),
sequence,
None, )
}
pub fn get_evm_actor_code_cid() -> Option<Cid> {
for bundle in ACTOR_BUNDLES_METADATA.values() {
if bundle.actor_major_version().ok() == Some(17)
&& let Ok(cid) = bundle.manifest.get(BuiltinActor::EVM)
{
return Some(cid);
}
}
None
}
pub fn create_evm_actor_with_bytecode(
store: &MemoryDB,
balance_atto: u64,
actor_sequence: u64,
evm_nonce: u64,
bytecode: Option<&[u8]>,
) -> Option<ActorState> {
use fvm_ipld_blockstore::Blockstore as _;
let evm_code_cid = get_evm_actor_code_cid()?;
let bytecode_cid = if let Some(code) = bytecode {
use multihash_codetable::MultihashDigest;
let mh = multihash_codetable::Code::Blake2b256.digest(code);
let cid = Cid::new_v1(fvm_ipld_encoding::IPLD_RAW, mh);
store.put_keyed(&cid, code).ok()?;
cid
} else {
Cid::default()
};
let bytecode_hash = if let Some(code) = bytecode {
use keccak_hash::keccak;
let hash = keccak(code);
fil_actor_evm_state::v17::BytecodeHash::from(hash.0)
} else {
fil_actor_evm_state::v17::BytecodeHash::EMPTY
};
let evm_state = fil_actor_evm_state::v17::State {
bytecode: bytecode_cid,
bytecode_hash,
contract_state: Cid::default(),
transient_data: None,
nonce: evm_nonce,
tombstone: None,
};
let state_cid = store.put_cbor_default(&evm_state).ok()?;
Some(ActorState::new(
evm_code_cid,
state_cid,
TokenAmount::from_atto(balance_atto),
actor_sequence,
None,
))
}
pub fn create_masked_id_eth_address(actor_id: u64) -> EthAddress {
EthAddress::from_actor_id(actor_id)
}
pub struct TestStateTrees {
pub store: Arc<MemoryDB>,
pub pre_state: StateTree<MemoryDB>,
pub post_state: StateTree<MemoryDB>,
}
impl TestStateTrees {
pub fn new() -> anyhow::Result<Self> {
let store = Arc::new(MemoryDB::default());
let pre_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let post_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
Ok(Self {
store,
pre_state,
post_state,
})
}
pub fn with_changed_actor(
actor_id: u64,
pre_actor: ActorState,
post_actor: ActorState,
) -> anyhow::Result<Self> {
let store = Arc::new(MemoryDB::default());
let mut pre_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let mut post_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let addr = FilecoinAddress::new_id(actor_id);
pre_state.set_actor(&addr, pre_actor)?;
post_state.set_actor(&addr, post_actor)?;
Ok(Self {
store,
pre_state,
post_state,
})
}
pub fn with_created_actor(actor_id: u64, post_actor: ActorState) -> anyhow::Result<Self> {
let store = Arc::new(MemoryDB::default());
let pre_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let mut post_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let addr = FilecoinAddress::new_id(actor_id);
post_state.set_actor(&addr, post_actor)?;
Ok(Self {
store,
pre_state,
post_state,
})
}
pub fn with_deleted_actor(actor_id: u64, pre_actor: ActorState) -> anyhow::Result<Self> {
let store = Arc::new(MemoryDB::default());
let mut pre_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let post_state = StateTree::new(store.clone(), StateTreeVersion::V5)?;
let addr = FilecoinAddress::new_id(actor_id);
pre_state.set_actor(&addr, pre_actor)?;
Ok(Self {
store,
pre_state,
post_state,
})
}
pub fn build_diff(&self, touched_addresses: &HashSet<EthAddress>) -> anyhow::Result<StateDiff> {
build_state_diff(
self.store.as_ref(),
&self.pre_state,
&self.post_state,
touched_addresses,
)
}
}