Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

evm: Connect and store blocks #1882

Merged
merged 14 commits into from
Apr 12, 2023
2 changes: 1 addition & 1 deletion src/rust/crates/ain-evm-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ fn evm_queue_tx(context: u64, raw_tx: &str) -> Result<bool, Box<dyn Error>> {

use rlp::Encodable;
fn evm_finalise(context: u64, update_state: bool) -> Result<Vec<u8>, Box<dyn Error>> {
let (block, _failed_tx) = RUNTIME.handlers.evm.finalize_block(context, update_state)?;
let (block, _failed_tx) = RUNTIME.handlers.finalize_block(context, update_state)?;
Ok(block.header.rlp_bytes().into())
}
20 changes: 15 additions & 5 deletions src/rust/crates/ain-evm/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::sync::{Arc, RwLock};
pub static BLOCK_MAP_PATH: &str = "block_map.bin";
pub static BLOCK_DATA_PATH: &str = "block_data.bin";

type BlockHashtoBlock = HashMap<H256, U256>;
type BlockHashtoBlock = HashMap<H256, usize>;
type Blocks = Vec<BlockAny>;

pub struct BlockHandler {
Expand All @@ -33,7 +33,7 @@ impl PersistentState for BlockHashtoBlock {
let mut file = File::open(path)?;
let mut data = Vec::new();
file.read_to_end(&mut data)?;
let new_state: HashMap<H256, U256> = bincode::deserialize(&data)?;
let new_state: HashMap<H256, usize> = bincode::deserialize(&data)?;
Ok(new_state)
} else {
Ok(Self::new())
Expand Down Expand Up @@ -79,7 +79,7 @@ impl BlockHandler {
blocks.push(block.clone());

let mut blockhash = self.block_map.write().unwrap();
blockhash.insert(block.header.hash(), block.header.number);
blockhash.insert(block.header.hash(), blocks.len() - 1);
}

pub fn flush(&self) -> Result<(), PersistentStateError> {
Expand All @@ -90,15 +90,25 @@ impl BlockHandler {
self.blocks.write().unwrap().save_to_disk(BLOCK_DATA_PATH)
}

pub fn get_block_hash(&self, hash: H256) -> Result<BlockAny, BlockHandlerError> {
pub fn get_block_by_hash(&self, hash: H256) -> Result<BlockAny, BlockHandlerError> {
let block_map = self.block_map.read().unwrap();
let block_number = *block_map
.get(&hash)
.ok_or(BlockHandlerError::BlockNotFound)?;

let blocks = self.blocks.read().unwrap();
let block = blocks
.get(block_number.as_usize())
.get(block_number)
.ok_or(BlockHandlerError::BlockNotFound)?
.clone();

Ok(block)
}

pub fn get_block_by_number(&self, count: usize) -> Result<BlockAny, BlockHandlerError> {
let blocks = self.blocks.read().unwrap();
let block = blocks
.get(count)
.ok_or(BlockHandlerError::BlockNotFound)?
.clone();

Expand Down
50 changes: 0 additions & 50 deletions src/rust/crates/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,56 +140,6 @@ impl EVMHandler {
self.tx_queues.add_signed_tx(context, signed_tx);
Ok(())
}

pub fn finalize_block(
&self,
context: u64,
update_state: bool,
) -> Result<(Block<TransactionV2>, Vec<TransactionV2>), Box<dyn Error>> {
let mut tx_hashes = Vec::with_capacity(self.tx_queues.len(context));
let mut failed_tx_hashes = Vec::with_capacity(self.tx_queues.len(context));
let vicinity = get_vicinity(None, None);
let state = self.tx_queues.state(context).expect("Wrong context");
let backend = MemoryBackend::new(&vicinity, state);
let mut executor = AinExecutor::new(backend);

for signed_tx in self.tx_queues.drain_all(context) {
let tx_response = executor.exec(&signed_tx);
if tx_response.exit_reason.is_succeed() {
tx_hashes.push(signed_tx.transaction);
} else {
failed_tx_hashes.push(signed_tx.transaction)
}
}

self.tx_queues.remove(context);

if update_state {
let mut state = self.state.write().unwrap();
*state = executor.backend().state().clone();
}

let block = Block::new(
PartialHeader {
parent_hash: Default::default(),
beneficiary: Default::default(),
state_root: Default::default(),
receipts_root: Default::default(),
logs_bloom: Default::default(),
difficulty: Default::default(),
number: Default::default(),
gas_limit: Default::default(),
gas_used: Default::default(),
timestamp: Default::default(),
extra_data: Default::default(),
mix_hash: Default::default(),
nonce: Default::default(),
},
tx_hashes,
Vec::new(),
);
Ok((block, failed_tx_hashes))
}
}

impl EVMHandler {
Expand Down
86 changes: 86 additions & 0 deletions src/rust/crates/ain-evm/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
use crate::block::BlockHandler;
use crate::evm::EVMHandler;
use crate::executor::AinExecutor;
use crate::traits::Executor;
use ethereum::{Block, PartialHeader, TransactionV2};
use evm::backend::{MemoryBackend, MemoryVicinity};
use primitive_types::{H160, H256, U256};
use std::error::Error;
use std::time::{SystemTime, UNIX_EPOCH};

pub struct Handlers {
pub evm: EVMHandler,
Expand All @@ -13,4 +20,83 @@ impl Handlers {
block: BlockHandler::new(),
}
}

pub fn finalize_block(
&self,
context: u64,
update_state: bool,
) -> Result<(Block<TransactionV2>, Vec<TransactionV2>), Box<dyn Error>> {
let mut tx_hashes = Vec::with_capacity(self.evm.tx_queues.len(context));
let mut failed_tx_hashes = Vec::with_capacity(self.evm.tx_queues.len(context));
let vicinity = get_vicinity(None, None);
let state = self.evm.tx_queues.state(context).expect("Wrong context");
let backend = MemoryBackend::new(&vicinity, state);
let mut executor = AinExecutor::new(backend);

for signed_tx in self.evm.tx_queues.drain_all(context) {
let tx_response = executor.exec(&signed_tx);
if tx_response.exit_reason.is_succeed() {
tx_hashes.push(signed_tx.transaction);
} else {
failed_tx_hashes.push(signed_tx.transaction)
}
}

self.evm.tx_queues.remove(context);

if update_state {
let mut state = self.evm.state.write().unwrap();
*state = executor.backend().state().clone();
}

let (parent_hash, number) = {
let blocks = self.block.blocks.read().unwrap();
blocks
.first()
.and_then(|first_block| Some((first_block.header.hash(), blocks.len() + 1)))
.unwrap_or((H256::default(), 0))
};

let block = Block::new(
PartialHeader {
parent_hash,
beneficiary: Default::default(),
state_root: Default::default(),
receipts_root: Default::default(),
logs_bloom: Default::default(),
difficulty: Default::default(),
number: U256::from(number),
gas_limit: Default::default(),
gas_used: Default::default(),
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64,
extra_data: Default::default(),
mix_hash: Default::default(),
nonce: Default::default(),
},
tx_hashes,
Vec::new(),
);

self.block.connect_block(block.clone());

Ok((block, failed_tx_hashes))
}
}

fn get_vicinity(origin: Option<H160>, gas_price: Option<U256>) -> MemoryVicinity {
MemoryVicinity {
gas_price: gas_price.unwrap_or(U256::MAX),
origin: origin.unwrap_or_default(),
block_hashes: Vec::new(),
block_number: Default::default(),
block_coinbase: Default::default(),
block_timestamp: Default::default(),
block_difficulty: Default::default(),
block_gas_limit: U256::MAX,
chain_id: U256::one(),
block_base_fee_per_gas: U256::MAX,
}
}
8 changes: 4 additions & 4 deletions src/rust/crates/ain-evm/tests/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn test_finalize_block_and_do_not_update_state() {
handler.evm.tx_queues.add_signed_tx(context, tx1);

let old_state = handler.evm.state.read().unwrap();
let _ = handler.evm.finalize_block(context, false).unwrap();
let _ = handler.finalize_block(context, false).unwrap();

let new_state = handler.evm.state.read().unwrap();
assert_eq!(*new_state, *old_state);
Expand Down Expand Up @@ -58,7 +58,7 @@ fn test_finalize_block_and_update_state() {
assert_eq!(handler.evm.tx_queues.len(context), 3);
assert_eq!(handler.evm.tx_queues.len(handler.evm.get_context()), 0);

let (block, failed_txs) = handler.evm.finalize_block(context, true).unwrap();
let (block, failed_txs) = handler.finalize_block(context, true).unwrap();
assert_eq!(
block.transactions,
vec![tx1, tx2]
Expand Down Expand Up @@ -131,7 +131,7 @@ fn test_deploy_and_call_smart_contract() {
.tx_queues
.add_signed_tx(context, create_smart_contract_tx);

handler.evm.finalize_block(context, true).unwrap();
handler.finalize_block(context, true).unwrap();

// Fund caller address
handler.evm.add_balance(
Expand All @@ -150,7 +150,7 @@ fn test_deploy_and_call_smart_contract() {
.tx_queues
.add_signed_tx(context, call_smart_contract_tx);

handler.evm.finalize_block(context, true).unwrap();
handler.finalize_block(context, true).unwrap();

let smart_contract_storage = handler.evm.get_storage(smart_contract_address);
assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions src/rust/crates/ain-grpc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ fn change_types(file: syn::File) -> (HashMap<String, ItemStruct>, TokenStream, T
modified.extend(quote!(#s));
map.insert(s.ident.to_string(), s.clone());

s.attrs = Attr::parse("#[derive(Debug, Default, Serialize , Deserialize)]");
s.attrs = Attr::parse("#[derive(Debug, Default, Serialize , Deserialize, PartialEq)]");
let fields = match &mut s.fields {
Fields::Named(ref mut f) => f,
_ => unreachable!(),
Expand Down Expand Up @@ -642,7 +642,7 @@ fn apply_substitutions(
.url
.as_ref()
.map(String::from)
.unwrap_or_else(|| method.name.to_lower_camel_case());
.unwrap_or_else(|| method.name.to_lowercase());
if method.client {
funcs.extend(quote! {
#[allow(non_snake_case)]
Expand Down
Loading