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

Consolidate persistent state to BlockchainDataHandler struct #1944

Merged
merged 6 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 15 additions & 85 deletions lib/ain-evm/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,98 +1,28 @@
use crate::traits::{PersistentState, PersistentStateError};
use ethereum::BlockAny;
use primitive_types::H256;
use std::collections::HashMap;
use std::error::Error;
use std::sync::{Arc, RwLock};
use keccak_hash::H256;
use primitive_types::U256;
use std::sync::Arc;

pub static BLOCK_MAP_PATH: &str = "block_map.bin";
pub static BLOCK_DATA_PATH: &str = "block_data.bin";

type BlockHashtoBlock = HashMap<H256, usize>;
type Blocks = Vec<BlockAny>;
use crate::storage::{traits::BlockStorage, Storage};

pub struct BlockHandler {
pub block_map: Arc<RwLock<BlockHashtoBlock>>,
pub blocks: Arc<RwLock<Blocks>>,
}

impl PersistentState for BlockHashtoBlock {}

impl PersistentState for Blocks {}

impl Default for BlockHandler {
fn default() -> Self {
Self::new()
}
storage: Arc<Storage>,
}

impl BlockHandler {
pub fn new() -> Self {
Self {
block_map: Arc::new(RwLock::new(
BlockHashtoBlock::load_from_disk(BLOCK_MAP_PATH).unwrap(),
)),
blocks: Arc::new(RwLock::new(
Blocks::load_from_disk(BLOCK_DATA_PATH).unwrap(),
)),
}
pub fn new(storage: Arc<Storage>) -> Self {
Self { storage }
}

pub fn connect_block(&self, block: BlockAny) {
let mut blocks = self.blocks.write().unwrap();
blocks.push(block.clone());

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

pub fn flush(&self) -> Result<(), PersistentStateError> {
self.block_map
.write()
.unwrap()
.save_to_disk(BLOCK_MAP_PATH)?;
self.blocks.write().unwrap().save_to_disk(BLOCK_DATA_PATH)
pub fn get_latest_block_hash_and_number(&self) -> (H256, U256) {
self.storage
.get_latest_block()
.map(|latest_block| (latest_block.header.hash(), latest_block.header.number + 1))
.unwrap_or((H256::default(), U256::zero()))
}

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)
.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();

Ok(block)
}
}

use std::fmt;

#[derive(Debug)]
pub enum BlockHandlerError {
BlockNotFound,
}

impl fmt::Display for BlockHandlerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BlockHandlerError::BlockNotFound => write!(f, "Block not found"),
}
pub fn connect_block(&self, block: BlockAny) {
self.storage.put_latest_block(&block);
self.storage.put_block(&block)
}
}

impl Error for BlockHandlerError {}
14 changes: 12 additions & 2 deletions lib/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::traits::{PersistentState, PersistentStateError};
use crate::storage::traits::{PersistentState, PersistentStateError};
use crate::tx_queue::TransactionQueueMap;
use crate::{
executor::AinExecutor,
traits::{Executor, ExecutorContext},
transaction::SignedTx,
};
use anyhow::anyhow;
use ethereum::{AccessList, TransactionV2};
use ethereum::{AccessList, Log, TransactionV2};
use ethereum_types::{Bloom, BloomInput};
use evm::backend::MemoryAccount;
use evm::{
backend::{MemoryBackend, MemoryVicinity},
Expand Down Expand Up @@ -138,6 +139,15 @@ impl EVMHandler {
self.tx_queues.add_signed_tx(context, signed_tx);
Ok(())
}

pub fn logs_bloom(logs: Vec<Log>, bloom: &mut Bloom) {
for log in logs {
bloom.accrue(BloomInput::Raw(&log.address[..]));
for topic in log.topics {
bloom.accrue(BloomInput::Raw(&topic[..]));
}
}
}
}

impl EVMHandler {
Expand Down
18 changes: 16 additions & 2 deletions lib/ain-evm/src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use std::collections::BTreeMap;

use crate::{
evm::EVMHandler,
traits::{Executor, ExecutorContext},
transaction::SignedTx,
};
use ethereum::{EIP658ReceiptData, Log, ReceiptV3};
use ethereum_types::{Bloom, U256};
use evm::{
backend::{ApplyBackend, Backend},
executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata},
Config, ExitReason,
};

use ethereum::Log;

#[derive(Debug)]
pub struct AinExecutor<B: Backend> {
backend: B,
Expand Down Expand Up @@ -71,11 +72,23 @@ where
self.backend.apply(values, logs.clone(), true);
}

let receipt = ReceiptV3::EIP1559(EIP658ReceiptData {
logs_bloom: {
let mut bloom: Bloom = Bloom::default();
EVMHandler::logs_bloom(logs.clone(), &mut bloom);
bloom
},
status_code: exit_reason.is_succeed() as u8,
logs: logs.clone(),
used_gas: U256::from(used_gas),
});

TxResponse {
exit_reason,
data,
logs,
used_gas,
receipt,
}
}

Expand All @@ -101,4 +114,5 @@ pub struct TxResponse {
pub data: Vec<u8>,
pub logs: Vec<Log>,
pub used_gas: u64,
pub receipt: ReceiptV3,
}
87 changes: 30 additions & 57 deletions lib/ain-evm/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ use crate::receipt::ReceiptHandler;
use crate::storage::Storage;
use crate::traits::Executor;

use ethereum::{Block, BlockAny, Log, PartialHeader, TransactionV2};
use ethereum_types::{Bloom, BloomInput};
use ethereum::{Block, BlockAny, PartialHeader, ReceiptV3, TransactionV2};
use ethereum_types::{Bloom, H160, U256};
use evm::backend::MemoryBackend;
use primitive_types::{H160, H256, U256};
use std::error::Error;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

pub struct Handlers {
pub evm: EVMHandler,
pub block: BlockHandler,
pub storage: Storage,
pub storage: Arc<Storage>,
pub receipt: ReceiptHandler,
}

Expand All @@ -27,11 +27,12 @@ impl Default for Handlers {

impl Handlers {
pub fn new() -> Self {
let storage = Arc::new(Storage::new());
Self {
evm: EVMHandler::new(),
block: BlockHandler::new(),
storage: Storage::new(),
receipt: ReceiptHandler::new(),
block: BlockHandler::new(Arc::clone(&storage)),
receipt: ReceiptHandler::new(Arc::clone(&storage)),
storage,
}
}

Expand All @@ -42,8 +43,9 @@ impl Handlers {
difficulty: u32,
miner_address: Option<H160>,
) -> Result<(BlockAny, Vec<TransactionV2>), Box<dyn Error>> {
let mut successful_transactions = Vec::with_capacity(self.evm.tx_queues.len(context));
let mut all_transactions = Vec::with_capacity(self.evm.tx_queues.len(context));
let mut failed_transactions = Vec::with_capacity(self.evm.tx_queues.len(context));
let mut receipts_v3: Vec<ReceiptV3> = Vec::with_capacity(self.evm.tx_queues.len(context));
let mut gas_used = 0u64;
let mut logs_bloom: Bloom = Default::default();

Expand All @@ -57,45 +59,31 @@ impl Handlers {
exit_reason,
logs,
used_gas,
receipt,
..
} = executor.exec(&signed_tx);
if exit_reason.is_succeed() {
successful_transactions.push(signed_tx);
all_transactions.push(signed_tx);
} else {
failed_transactions.push(signed_tx)
failed_transactions.push(signed_tx.transaction.clone());
all_transactions.push(signed_tx);
}

gas_used += used_gas;
Self::logs_bloom(logs, &mut logs_bloom);
EVMHandler::logs_bloom(logs, &mut logs_bloom);
receipts_v3.push(receipt);
}

let mut all_transactions = successful_transactions
.clone()
.into_iter()
.map(|tx| tx.transaction)
.collect::<Vec<TransactionV2>>();
all_transactions.extend(
failed_transactions
.clone()
.into_iter()
.map(|tx| tx.transaction)
.collect::<Vec<TransactionV2>>(),
);

self.evm.tx_queues.remove(context);

let (parent_hash, number) = {
self.storage
.get_latest_block()
.map(|latest_block| (latest_block.header.hash(), latest_block.header.number + 1))
.unwrap_or((H256::default(), U256::zero()))
};
let (parent_hash, number) = self.block.get_latest_block_hash_and_number();

let mut block = Block::new(
let block = Block::new(
PartialHeader {
parent_hash,
beneficiary: miner_address.unwrap_or_default(),
state_root: Default::default(),
receipts_root: Default::default(),
receipts_root: ReceiptHandler::get_receipts_root(&receipts_v3),
logs_bloom,
difficulty: U256::from(difficulty),
number,
Expand All @@ -109,43 +97,28 @@ impl Handlers {
mix_hash: Default::default(),
nonce: Default::default(),
},
all_transactions,
all_transactions
.iter()
.map(|signed_tx| signed_tx.transaction.clone())
.collect(),
Vec::new(),
);

let receipts_root = self.receipt.generate_receipts(
successful_transactions,
failed_transactions.clone(),
let receipts = self.receipt.generate_receipts(
&all_transactions,
receipts_v3,
block.header.hash(),
block.header.number,
);
block.header.receipts_root = receipts_root;

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

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

self.storage.put_latest_block(block.clone());
self.storage.put_block(block.clone());
self.block.connect_block(block.clone());
self.receipt.put_receipts(receipts);
}

Ok((
block,
failed_transactions
.into_iter()
.map(|tx| tx.transaction)
.collect(),
))
}

fn logs_bloom(logs: Vec<Log>, bloom: &mut Bloom) {
for log in logs {
bloom.accrue(BloomInput::Raw(&log.address[..]));
for topic in log.topics {
bloom.accrue(BloomInput::Raw(&topic[..]));
}
}
Ok((block, failed_transactions))
}
}
1 change: 0 additions & 1 deletion lib/ain-evm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod block;
mod cache;
mod ecrecover;
pub mod evm;
pub mod executor;
Expand Down
Loading