use crate::{
evm::{block_hash::EthereumBlockBuilder, fees::InfoT, Block, TransactionSigned},
test_utils::{builder::Contract, deposit_limit, ALICE},
tests::{assert_ok, builder, Contracts, ExtBuilder, RuntimeOrigin, System, Test, Timestamp},
BalanceWithDust, Code, Config, EthBlock, EthBlockBuilderFirstValues, EthBlockBuilderIR,
EthereumBlock, Pallet, ReceiptGasInfo, ReceiptInfoData,
};
use alloy_consensus::RlpEncodableReceipt;
use alloy_core::primitives::{FixedBytes, Log as AlloyLog};
use frame_support::traits::{
fungible::{Balanced, Mutate},
Hooks,
};
use pallet_revive_fixtures::compile_module;
use sp_state_machine::BasicExternalities;
#[test]
fn on_initialize_clears_storage() {
ExtBuilder::default().existential_deposit(50).build().execute_with(|| {
let receipt_data =
vec![ReceiptGasInfo { gas_used: 1.into(), effective_gas_price: 1.into() }];
ReceiptInfoData::<Test>::put(receipt_data.clone());
assert_eq!(ReceiptInfoData::<Test>::get(), receipt_data);
let block = EthBlock { number: 1.into(), ..Default::default() };
EthereumBlock::<Test>::put(block.clone());
assert_eq!(EthereumBlock::<Test>::get(), block);
Contracts::on_initialize(0);
assert_eq!(ReceiptInfoData::<Test>::get(), vec![]);
assert_eq!(EthereumBlock::<Test>::get(), Default::default());
});
}
#[test]
fn genesis_block_number_and_timestamp_fetched_from_storage() {
let mut ext = BasicExternalities::new_empty();
ext.execute_with(|| {
System::set_block_number(10);
Timestamp::set_timestamp(10000000);
});
let storage = ext.into_storages();
ExtBuilder::default()
.with_genesis_state_overrides(storage)
.build()
.execute_with(|| {
let block = EthereumBlock::<Test>::get();
assert_eq!(block.timestamp, 10000.into());
assert_eq!(block.number, 10.into());
});
}
#[test]
fn transactions_are_captured() {
let (binary, _) = compile_module("dummy").unwrap();
let (gas_binary, _code_hash) = compile_module("run_out_of_gas").unwrap();
ExtBuilder::default().existential_deposit(200).build().execute_with(|| {
Contracts::on_initialize(0);
let _ = <Test as Config>::Currency::set_balance(&ALICE, 100_000_000_000);
let Contract { addr, .. } =
builder::bare_instantiate(Code::Upload(binary.clone())).build_and_unwrap_contract();
let Contract { addr: addr2, .. } =
builder::bare_instantiate(Code::Upload(gas_binary.clone())).build_and_unwrap_contract();
let balance =
Pallet::<Test>::convert_native_to_evm(BalanceWithDust::new_unchecked::<Test>(100, 10));
<Test as Config>::FeeInfo::deposit_txfee(<Test as Config>::Currency::issue(5_000_000_000));
assert_ok!(builder::eth_call(addr).transaction_encoded(vec![1]).value(balance).build());
assert_ok!(builder::eth_instantiate_with_code(binary)
.value(balance)
.transaction_encoded(vec![2])
.build());
assert_ok!(builder::eth_call(addr2).transaction_encoded(vec![3]).build());
assert_ok!(builder::call(addr).value(1).build());
assert_ok!(builder::instantiate_with_code(gas_binary).salt(Some([1u8; 32])).build());
let block_builder = EthBlockBuilderIR::<Test>::get();
assert_eq!(block_builder.gas_info.len(), 3, "3 transactions were captured");
let expected_payloads = vec![vec![1u8], vec![2u8], vec![3u8]];
let expected_tx_root = Block::compute_trie_root(&expected_payloads);
let mut builder = EthereumBlockBuilder::<Test>::from_ir(block_builder);
let first_values = EthBlockBuilderFirstValues::<Test>::get().unwrap();
builder.transaction_root_builder.set_first_value(first_values.0);
let tx_root = builder.transaction_root_builder.finish();
assert_eq!(tx_root, expected_tx_root.0.into());
Contracts::on_finalize(0);
assert_eq!(crate::EthereumBlock::<Test>::get().transactions.len(), 3);
let block_builder = EthBlockBuilderIR::<Test>::get();
assert_eq!(block_builder.gas_info.len(), 0);
});
}
#[test]
fn events_are_captured() {
let (binary, code_hash) = compile_module("event_and_return_on_deploy").unwrap();
ExtBuilder::default().existential_deposit(200).build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 100_000_000_000_000);
assert_ok!(Contracts::upload_code(
RuntimeOrigin::signed(ALICE),
binary.clone(),
deposit_limit::<Test>(),
));
Contracts::on_initialize(1);
builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_contract();
let balance =
Pallet::<Test>::convert_native_to_evm(BalanceWithDust::new_unchecked::<Test>(100, 10));
<Test as Config>::FeeInfo::deposit_txfee(<Test as Config>::Currency::issue(
500_000_000_000,
));
assert_ok!(builder::eth_instantiate_with_code(binary).value(balance).build());
let events = frame_system::Pallet::<Test>::events();
let contract = events
.into_iter()
.filter_map(|event_record| match event_record.event {
crate::tests::RuntimeEvent::Contracts(crate::Event::Instantiated {
contract,
..
}) => Some(contract),
_ => None,
})
.last()
.expect("Contract address must be found from events");
let expected_payloads = vec![
TransactionSigned::Transaction4844Signed(Default::default()).signed_payload(),
];
let expected_tx_root = Block::compute_trie_root(&expected_payloads);
let block_builder = EthBlockBuilderIR::<Test>::get();
let gas_used = block_builder.gas_info[0].gas_used;
let logs = vec![AlloyLog::new_unchecked(
contract.0.into(),
vec![FixedBytes::from([42u8; 32])],
vec![1, 2, 3, 4].into(),
)];
let receipt = alloy_consensus::Receipt {
status: true.into(),
cumulative_gas_used: gas_used.as_u64(),
logs,
};
let receipt_bloom = receipt.bloom_slow();
let mut encoded_receipt = vec![3];
receipt.rlp_encode_with_bloom(&receipt_bloom, &mut encoded_receipt);
let expected_receipt_root = Block::compute_trie_root(&[encoded_receipt.clone()]);
let block_builder = EthBlockBuilderIR::<Test>::get();
assert_eq!(block_builder.gas_info.len(), 1);
let mut builder = EthereumBlockBuilder::<Test>::from_ir(block_builder);
builder.transaction_root_builder.set_first_value(expected_payloads[0].clone());
let tx_root = builder.transaction_root_builder.finish();
assert_eq!(tx_root, expected_tx_root.0.into());
builder.receipts_root_builder.set_first_value(encoded_receipt.clone());
let receipt_root = builder.receipts_root_builder.finish();
assert_eq!(receipt_root, expected_receipt_root.0.into());
Contracts::on_finalize(0);
let block_builder = EthBlockBuilderIR::<Test>::get();
assert_eq!(block_builder.gas_info.len(), 0);
});
}