Skip to content

Commit

Permalink
feat: add tests/erc20_independent.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
kien-rise committed Apr 25, 2024
1 parent 7e3d322 commit 8150de5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
dashmap = "5.5.3"
rand = "0.8.5"
revm = "8.0.0"

[lints]
Expand Down
47 changes: 45 additions & 2 deletions src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use std::collections::HashMap;

use revm::primitives::{Account, AccountInfo, Address, Bytecode, B256, U256};
use revm::{
db::DbAccount,
primitives::{Account, AccountInfo, Address, Bytecode, B256, U256},
InMemoryDB,
};

use crate::ReadError;

/// An interface to provide chain state to BlockSTM for transaction execution.
/// TODO: Populate the remaining missing pieces like logs, etc.
/// TODO: Better API for third-pary integration.
#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub struct Storage {
accounts: HashMap<Address, Account>,
contracts: HashMap<B256, Bytecode>,
Expand All @@ -30,6 +34,17 @@ impl Storage {
self.accounts.insert(address, Account::from(info));
}

/// Insert an account into the storage.
pub fn insert_account(&mut self, address: Address, account: Account) {
self.accounts.insert(address, account);
}

/// Insert a contract into the storage.
pub fn insert_contract(&mut self, code: Bytecode) {
let code_hash = code.hash_slow();
self.contracts.insert(code_hash, code);
}

pub(crate) fn basic(&self, address: Address) -> Result<AccountInfo, ReadError> {
match self.accounts.get(&address) {
Some(account) => Ok(account.info.clone()),
Expand Down Expand Up @@ -59,3 +74,31 @@ impl Storage {
}
}
}

fn convert_account_to_db_account(value: Account) -> DbAccount {
DbAccount {
info: value.info,
account_state: revm::db::AccountState::None,
storage: value
.storage
.into_iter()
.map(|(k, v)| (k, v.present_value))
.collect(),
}
}

impl From<Storage> for InMemoryDB {
fn from(value: Storage) -> Self {
InMemoryDB {
accounts: value
.accounts
.into_iter()
.map(|(k, v)| (k, convert_account_to_db_account(v)))
.collect(),
contracts: value.contracts,
logs: Vec::default(),
block_hashes: value.block_hashes,
db: Default::default(),
}
}
}
137 changes: 137 additions & 0 deletions tests/erc20_independent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use block_stm_revm::{BlockSTM, Storage};
use revm::{
primitives::{
bytes, fixed_bytes, keccak256, uint, Account, AccountInfo, AccountStatus, Address,
BlockEnv, Bytecode, Bytes, ResultAndState, StorageSlot, TransactTo, TxEnv, B256,
KECCAK_EMPTY, U256,
},
Evm, InMemoryDB,
};
use std::{collections::HashMap, sync::Arc};

fn random_address() -> Address {
let bytes: [u8; 20] = rand::random();
Address::from_slice(&bytes)
}

fn encode_storage_string(text: &str) -> U256 {
let n = text.bytes().len();
assert!(n < 32);
let x = B256::right_padding_from(text.as_bytes());
let y = B256::with_last_byte((n * 2) as u8);
B256::bit_or(x, y).into()
}

fn get_erc20(slaves: &[Address]) -> (Bytecode, Account) {
let erc20_bytes = bytes!("608060405234801561001057600080fd5b50600436106100a95760003560e01c8063395093511161007157806339509351146101d957806370a082311461020557806395d89b411461022b578063a457c2d714610233578063a9059cbb1461025f578063dd62ed3e1461028b576100a9565b806306fdde03146100ae578063095ea7b31461012b57806318160ddd1461016b57806323b872dd14610185578063313ce567146101bb575b600080fd5b6100b66102b9565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100f05781810151838201526020016100d8565b50505050905090810190601f16801561011d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101576004803603604081101561014157600080fd5b506001600160a01b03813516906020013561034f565b604080519115158252519081900360200190f35b61017361036c565b60408051918252519081900360200190f35b6101576004803603606081101561019b57600080fd5b506001600160a01b03813581169160208101359091169060400135610372565b6101c36103f9565b6040805160ff9092168252519081900360200190f35b610157600480360360408110156101ef57600080fd5b506001600160a01b038135169060200135610402565b6101736004803603602081101561021b57600080fd5b50356001600160a01b0316610450565b6100b661046b565b6101576004803603604081101561024957600080fd5b506001600160a01b0381351690602001356104cc565b6101576004803603604081101561027557600080fd5b506001600160a01b038135169060200135610534565b610173600480360360408110156102a157600080fd5b506001600160a01b0381358116916020013516610548565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b820191906000526020600020905b81548152906001019060200180831161032857829003601f168201915b5050505050905090565b600061036361035c6105d4565b84846105d8565b50600192915050565b60025490565b600061037f8484846106c4565b6103ef8461038b6105d4565b6103ea85604051806060016040528060288152602001610927602891396001600160a01b038a166000908152600160205260408120906103c96105d4565b6001600160a01b03168152602081019190915260400160002054919061081f565b6105d8565b5060019392505050565b60055460ff1690565b600061036361040f6105d4565b846103ea85600160006104206105d4565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610573565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156103455780601f1061031a57610100808354040283529160200191610345565b60006103636104d96105d4565b846103ea8560405180606001604052806025815260200161099860259139600160006105036105d4565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919061081f565b60006103636105416105d4565b84846106c4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000828201838110156105cd576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b3390565b6001600160a01b03831661061d5760405162461bcd60e51b81526004018080602001828103825260248152602001806109746024913960400191505060405180910390fd5b6001600160a01b0382166106625760405162461bcd60e51b81526004018080602001828103825260228152602001806108df6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166107095760405162461bcd60e51b815260040180806020018281038252602581526020018061094f6025913960400191505060405180910390fd5b6001600160a01b03821661074e5760405162461bcd60e51b81526004018080602001828103825260238152602001806108bc6023913960400191505060405180910390fd5b6107598383836108b6565b61079681604051806060016040528060268152602001610901602691396001600160a01b038616600090815260208190526040902054919061081f565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546107c59082610573565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156108ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561087357818101518382015260200161085b565b50505050905090810190601f1680156108a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220231516d22c50e9ac401e774457ff9efe016116125a2b210c3c1ad7a11e39d43064736f6c63430007060033");
let byte_code = Bytecode::new_raw(erc20_bytes);

let total_supply = U256::from(1_234_567_000_000_000_000_000_000u128);
let name = encode_storage_string("Gold Token");
let symbol = encode_storage_string("GLD");
let decimals = U256::from(18);
let mut storage: HashMap<U256, StorageSlot> = HashMap::new();
storage.insert(U256::from(2), StorageSlot::new(total_supply));
storage.insert(U256::from(3), StorageSlot::new(name));
storage.insert(U256::from(4), StorageSlot::new(symbol));
storage.insert(U256::from(5), StorageSlot::new(decimals));

for slave in slaves.iter() {
let storage_key =
keccak256([B256::left_padding_from(slave.as_slice()), B256::ZERO].concat());
storage.insert(storage_key.into(), StorageSlot::new(U256::from(65536)));
}

let account = Account {
info: AccountInfo::new(U256::ZERO, 1u64, byte_code.hash_slow(), byte_code.clone()),
status: AccountStatus::default(),
storage,
};

(byte_code, account)
}

fn init_erc20(storage: &mut Storage, slaves: &[Address]) -> Address {
let (byte_code, db_account) = get_erc20(slaves);
let address = random_address();
storage.insert_account(address, db_account);
storage.insert_contract(byte_code);
address
}

fn init_slaves(storage: &mut Storage, slaves: &[Address]) {
// for coinbase address
storage.insert_account(Address::ZERO, Account::default());

for slave in slaves.iter() {
storage.insert_account(
slave.clone(),
Account::from(AccountInfo::new(
uint!(0x100000000000000000000000000000000_U256),
0u64,
KECCAK_EMPTY,
Bytecode::default(),
)),
);
}
}

fn get_txs(erc20_address: Address, slaves: &[Address]) -> Vec<TxEnv> {
slaves
.iter()
.map(|slave| TxEnv {
caller: slave.clone(),
value: U256::from(0),
chain_id: Default::default(),
transact_to: TransactTo::Call(erc20_address),
gas_limit: 65536u64,
gas_priority_fee: None,
data: Bytes::from(
[
fixed_bytes!("a9059cbb").as_slice(),
B256::right_padding_from(slave.as_slice()).as_slice(),
B256::from(U256::from(1)).as_slice(),
]
.concat(),
),
gas_price: U256::from(0xb2d05e07u64),
blob_hashes: Vec::new(),
max_fee_per_blob_gas: None,
access_list: Vec::new(),
nonce: Some(0u64),
})
.collect()
}

fn run_naively(storage: Arc<InMemoryDB>, txs: Arc<Vec<TxEnv>>) -> Vec<ResultAndState> {
txs.iter()
.map(|tx| {
let result_and_state = Evm::builder()
.with_ref_db(&storage)
.with_tx_env(tx.clone())
.build()
.transact()
.unwrap();
result_and_state
})
.collect()
}

fn run_with_block_stm(storage: Arc<Storage>, txs: Arc<Vec<TxEnv>>) -> Vec<ResultAndState> {
let concurrency = std::thread::available_parallelism().unwrap_or(std::num::NonZeroUsize::MIN);
BlockSTM::run(storage, BlockEnv::default(), txs, concurrency)
}

#[test]
fn test_erc20() {
let slaves: Vec<Address> = (0..20).map(|_| random_address()).collect();
let mut storage = Storage::new();
init_slaves(&mut storage, &slaves);
let erc20_address = init_erc20(&mut storage, &slaves);
let txs = get_txs(erc20_address, &slaves);
let v0 = run_naively(Arc::new(storage.clone().into()), Arc::new(txs.clone()));
let v1 = run_with_block_stm(Arc::new(storage.clone()), Arc::new(txs.clone()));
let r0 = v0.into_iter().map(|x| x.result).collect::<Vec<_>>();
let r1 = v1.into_iter().map(|x| x.result).collect::<Vec<_>>();
assert_eq!(r0, r1);
}

0 comments on commit 8150de5

Please sign in to comment.