From 6be4fd0df4ace3c5322121aa6779cb8e78ee23e4 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Sat, 28 Dec 2024 16:29:33 +0800 Subject: [PATCH] add squash writeset when executing genesis --- chain/src/chain.rs | 23 +++++++---- executor/src/block_executor.rs | 73 ++++++++++++++++++++++++++++++---- executor/src/lib.rs | 2 +- genesis/src/lib.rs | 29 +++----------- 4 files changed, 87 insertions(+), 40 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 017774d6b5..93c84431cb 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -697,10 +697,10 @@ impl BlockChain { txn_accumulator, block_accumulator, &genesis_epoch, - None, + None, /*parent status*/ genesis_block, &chain_id, - None, + None, /*VM metrics*/ )?; dag = Self::init_dag(dag, genesis_header)?; Self::new(time_service, executed_block.block.id(), storage, None, dag) @@ -1269,12 +1269,19 @@ impl BlockChain { }; watch(CHAIN_WATCH_NAME, "n21"); - let executed_data = starcoin_executor::block_execute( - &statedb, - transactions.clone(), - epoch.block_gas_limit(), - vm_metrics, - )?; + let executed_data = if header.is_genesis() { + starcoin_executor::execute_genesis_transaction( + &statedb, + transactions.first().unwrap().clone(), + )? + } else { + starcoin_executor::block_execute( + &statedb, + transactions.clone(), + epoch.block_gas_limit(), + vm_metrics, + )? + }; watch(CHAIN_WATCH_NAME, "n22"); let state_root = executed_data.state_root; let vec_transaction_info = &executed_data.txn_infos; diff --git a/executor/src/block_executor.rs b/executor/src/block_executor.rs index b6da0a1321..e49545000e 100644 --- a/executor/src/block_executor.rs +++ b/executor/src/block_executor.rs @@ -5,14 +5,18 @@ use crate::execute_block_transactions; use serde::{Deserialize, Serialize}; use starcoin_crypto::HashValue; use starcoin_state_api::{ChainStateReader, ChainStateWriter}; -use starcoin_types::error::BlockExecutorError; -use starcoin_types::error::ExecutorResult; -use starcoin_types::transaction::TransactionStatus; -use starcoin_types::transaction::{Transaction, TransactionInfo}; +use starcoin_types::{ + error::{BlockExecutorError, ExecutorResult}, + transaction::{Transaction, TransactionInfo, TransactionStatus}, + vm_error::KeptVMStatus, +}; use starcoin_vm_runtime::metrics::VMMetrics; -use starcoin_vm_types::contract_event::ContractEvent; -use starcoin_vm_types::state_store::table::{TableHandle, TableInfo}; -use starcoin_vm_types::write_set::WriteSet; +use starcoin_vm_types::{ + contract_event::ContractEvent, + state_store::table::{TableHandle, TableInfo}, + write_set::WriteSet, + StateView, +}; use std::collections::BTreeMap; #[cfg(feature = "force-deploy")] @@ -64,6 +68,57 @@ impl Default for BlockExecutedData { } } +pub fn execute_genesis_transaction( + chain_state: &S, + genesis_txn: Transaction, +) -> ExecutorResult { + let txn_hash = genesis_txn.id(); + let txn_outputs = execute_block_transactions(chain_state, vec![genesis_txn], u64::MAX, None) + .map_err(BlockExecutorError::BlockTransactionExecuteErr)?; + assert_eq!( + txn_outputs.len(), + 1, + "genesis txn output count must be 1, but got {}", + txn_outputs.len() + ); + let mut executed_data = BlockExecutedData::default(); + let (write_set, events, gas_used, status, _) = + txn_outputs.first().unwrap().clone().into_inner(); + let extra_write_set = + extract_extra_writeset(chain_state).expect("extract extra writeset failed"); + let write_set = write_set + .into_mut() + .squash(extra_write_set.into_mut()) + .expect("failed to squash write set") + .freeze() + .expect("failed to freeze write set"); + match status { + TransactionStatus::Keep(status) => { + assert_eq!(status, KeptVMStatus::Executed); + chain_state + .apply_write_set(write_set.clone()) + .map_err(BlockExecutorError::BlockChainStateErr)?; + + let txn_state_root = chain_state + .commit() + .map_err(BlockExecutorError::BlockChainStateErr)?; + executed_data.state_root = txn_state_root; + executed_data.txn_infos.push(TransactionInfo::new( + txn_hash, + txn_state_root, + events.as_slice(), + gas_used, + status, + )); + executed_data.txn_events.push(events); + executed_data.write_sets.push(write_set); + } + _ => unreachable!("genesis txn output must be keep"), + } + + Ok(executed_data) +} + pub fn block_execute( chain_state: &S, txns: Vec, @@ -170,6 +225,10 @@ fn create_force_upgrade_extra_txn( ) } +fn extract_extra_writeset(_chain_state: &S) -> anyhow::Result { + Ok(WriteSet::default()) +} + // todo: check the execute_extra_txn in OpenedBlock, and merge with it #[cfg(feature = "force-deploy")] fn execute_extra_txn( diff --git a/executor/src/lib.rs b/executor/src/lib.rs index da0f2a4cf2..606ad5af9e 100644 --- a/executor/src/lib.rs +++ b/executor/src/lib.rs @@ -5,7 +5,7 @@ #[macro_use] extern crate log; -pub use block_executor::{block_execute, BlockExecutedData}; +pub use block_executor::{block_execute, execute_genesis_transaction, BlockExecutedData}; pub use executor::*; // pub use starcoin_transaction_builder::{ // build_accept_token_txn, build_batch_transfer_txn, build_transfer_from_association, diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 3cb054d6da..0c683f8e0f 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -3,7 +3,7 @@ mod errors; -use anyhow::{bail, ensure, format_err, Result}; +use anyhow::{bail, format_err, Result}; pub use errors::GenesisError; use include_dir::include_dir; use include_dir::Dir; @@ -32,7 +32,6 @@ use starcoin_vm_types::{ account_config::CORE_CODE_ADDRESS, state_store::StateView, transaction::{RawUserTransaction, SignedUserTransaction, TransactionPayload}, - vm_status::KeptVMStatus, }; use std::{ fmt::Display, @@ -186,31 +185,13 @@ impl Genesis { txn: SignedUserTransaction, ) -> Result { let txn = Transaction::UserTransaction(txn); - let txn_hash = txn.id(); - let output = starcoin_executor::execute_transactions(chain_state, vec![txn], None)? + let output = starcoin_executor::execute_genesis_transaction(chain_state, txn)? + .txn_infos .pop() .expect("Execute output must exist."); - let (write_set, events, gas_used, status, _) = output.into_inner(); - assert_eq!(gas_used, 0, "Genesis txn output's gas_used must be zero"); - let keep_status = status - .status() - .map_err(|e| format_err!("Genesis txn is discard by: {:?}", e))?; - ensure!( - keep_status == KeptVMStatus::Executed, - "Genesis txn execute fail for: {:?}", - keep_status - ); - chain_state.apply_write_set(write_set)?; - let state_root = chain_state.commit()?; - chain_state.flush()?; - Ok(TransactionInfo::new( - txn_hash, - state_root, - events.as_slice(), - gas_used, - keep_status, - )) + + Ok(output) } pub fn block(&self) -> &Block {