From d6ce41272b94fe828e57df662234fcc03d360b19 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 4 Jun 2024 20:02:26 +0800 Subject: [PATCH] 1, use 0 as dag fork number in test case 2, use selected parent in tips as the new block header's parent if tips are descendants of the header --- chain/api/src/chain.rs | 5 +- chain/service/src/chain_service.rs | 2 +- chain/src/chain.rs | 60 +++++++++++++++---- miner/src/create_block_template/mod.rs | 10 +++- sync/Cargo.toml | 2 +- .../test_write_dag_block_chain.rs | 5 +- sync/src/tasks/block_sync_task.rs | 3 + 7 files changed, 69 insertions(+), 18 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index 2ff42f8078..1e6b2ad8e9 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -102,7 +102,10 @@ pub trait ChainReader { access_path: Option, ) -> Result>; - fn current_tips_hash(&self) -> Result>; + fn current_tips_hash( + &self, + header: &BlockHeader, + ) -> Result)>>; fn has_dag_block(&self, header_id: HashValue) -> Result; fn check_dag_type(&self, header: &BlockHeader) -> Result; } diff --git a/chain/service/src/chain_service.rs b/chain/service/src/chain_service.rs index e0d1fb6944..3b67f25f8f 100644 --- a/chain/service/src/chain_service.rs +++ b/chain/service/src/chain_service.rs @@ -466,7 +466,7 @@ impl ReadableChainService for ChainReaderServiceInner { head.number(), ); } - let (dag_genesis, state) = self.main.get_dag_state()?; + let (dag_genesis, state) = self.main.get_dag_state_by_block(&head)?; Ok(DagStateView { dag_genesis, tips: state.tips, diff --git a/chain/src/chain.rs b/chain/src/chain.rs index bd08370b2d..73e29b8142 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -45,7 +45,9 @@ use starcoin_vm_runtime::force_upgrade_management::get_force_upgrade_block_numbe use starcoin_vm_types::access_path::AccessPath; use starcoin_vm_types::account_config::genesis_address; use starcoin_vm_types::genesis_config::{ChainId, ConsensusStrategy}; +use starcoin_vm_types::on_chain_config::FlexiDagConfig; use starcoin_vm_types::on_chain_resource::Epoch; +use starcoin_vm_types::state_view::StateReaderExt; use std::cmp::min; use std::collections::HashSet; use std::iter::Extend; @@ -839,7 +841,11 @@ impl BlockChain { } else if tips.is_some() { tips } else { - Some(self.current_tips_hash()?) + Some( + self.current_tips_hash(&previous_header)? + .map(|r| r.1) + .expect("Creating a Dag block but tips don't exist"), + ) }; let strategy = epoch.strategy(); let difficulty = strategy.calculate_next_difficulty(self)?; @@ -999,7 +1005,7 @@ impl BlockChain { let results = header.parents_hash().ok_or_else(|| anyhow!("dag block has no parents."))?.into_iter().map(|parent_hash| { let header = self.storage.get_block_header_by_hash(parent_hash)?.ok_or_else(|| anyhow!("failed to find the block header in the block storage when checking the dag block exists, block hash: {:?}, number: {:?}", header.id(), header.number()))?; - let dag_genesis_hash = self.genesis_hash; + let dag_genesis_hash = self.get_block_dag_genesis(&header)?; let dag_genesis = self.storage.get_block_header_by_hash(dag_genesis_hash)?.ok_or_else(|| anyhow!("failed to find the block header in the block storage when checking the dag block exists, block hash: {:?}, number: {:?}", header.id(), header.number()))?; Ok(dag_genesis.parent_hash()) }).collect::>>()?; @@ -1689,8 +1695,28 @@ impl BlockChain { Ok(()) } + pub fn get_block_dag_genesis(&self, header: &BlockHeader) -> Result { + let dag_fork_height = self + .dag_fork_height()? + .ok_or_else(|| anyhow!("unset dag fork height"))?; + let block_info = self + .storage + .get_block_info(header.id())? + .ok_or_else(|| anyhow!("Cannot find block info by hash {:?}", header.id()))?; + let block_accumulator = MerkleAccumulator::new_with_info( + block_info.get_block_accumulator_info().clone(), + self.storage + .get_accumulator_store(AccumulatorStoreType::Block), + ); + let dag_genesis = block_accumulator + .get_leaf(dag_fork_height)? + .ok_or_else(|| anyhow!("failed to get the dag genesis"))?; + + Ok(dag_genesis) + } + pub fn get_block_dag_origin(&self) -> Result { - let dag_genesis = self.genesis_hash; + let dag_genesis = self.get_block_dag_genesis(&self.current_header())?; let block_header = self .storage .get_block_header_by_hash(dag_genesis)? @@ -1701,8 +1727,8 @@ impl BlockChain { )) } - pub fn get_dag_state(&self) -> Result<(HashValue, DagState)> { - let dag_genesis = self.genesis_hash; + pub fn get_dag_state_by_block(&self, header: &BlockHeader) -> Result<(HashValue, DagState)> { + let dag_genesis = self.get_block_dag_genesis(header)?; Ok((dag_genesis, self.dag.get_dag_state(dag_genesis)?)) } @@ -2002,6 +2028,7 @@ impl ChainReader for BlockChain { self.vm_metrics.clone(), )? }; + self.init_dag_with_genesis(header)?; Ok(executed) } else { self.execute_dag_block(verified_block) @@ -2118,9 +2145,12 @@ impl ChainReader for BlockChain { })) } - fn current_tips_hash(&self) -> Result> { - let (_dag_genesis, dag_state) = self.get_dag_state()?; - Ok(dag_state.tips) + fn current_tips_hash( + &self, + header: &BlockHeader, + ) -> Result)>> { + let (dag_genesis, dag_state) = self.get_dag_state_by_block(header)?; + Ok(Some((dag_genesis, dag_state.tips))) } fn has_dag_block(&self, header_id: HashValue) -> Result { @@ -2277,12 +2307,14 @@ impl BlockChain { fn connect_dag(&mut self, executed_block: ExecutedBlock) -> Result { let dag = self.dag.clone(); let (new_tip_block, _) = (executed_block.block(), executed_block.block_info()); - let mut tips = self.current_tips_hash()?; + let (dag_genesis, mut tips) = self + .current_tips_hash(new_tip_block.header())? + .expect("tips should exists in dag"); let parents = executed_block .block .header .parents_hash() - .expect("Dag parents must exist"); + .expect("Dag parents need exist"); if !tips.contains(&new_tip_block.id()) { for hash in parents { tips.retain(|x| *x != hash); @@ -2333,8 +2365,7 @@ impl BlockChain { if self.epoch.end_block_number() == block.header().number() { self.epoch = get_epoch_from_statedb(&self.statedb)?; } - self.dag - .save_dag_state(self.genesis_hash, DagState { tips })?; + self.dag.save_dag_state(dag_genesis, DagState { tips })?; Ok(executed_block) } @@ -2367,7 +2398,10 @@ impl BlockChain { #[cfg(not(feature = "sync-dag-test"))] pub fn dag_fork_height(&self) -> Result> { - Ok(Some(0)) + Ok(self + .statedb + .get_on_chain_config::()? + .map(|c| c.effective_height)) } } diff --git a/miner/src/create_block_template/mod.rs b/miner/src/create_block_template/mod.rs index 2084bd2e1a..2072f411a7 100644 --- a/miner/src/create_block_template/mod.rs +++ b/miner/src/create_block_template/mod.rs @@ -359,7 +359,15 @@ where } let difficulty = strategy.calculate_next_difficulty(&self.chain)?; let tips_hash = if current_number > self.chain.dag_fork_height()?.unwrap_or(u64::MAX) { - Some(self.chain.current_tips_hash()?) + let (_dag_genesis, tips_hash) = self + .chain + .current_tips_hash(&previous_header)? + .ok_or_else(|| { + anyhow!( + "the number of the block is larger than the dag fork number but no dag state!" + ) + })?; + Some(tips_hash) } else { None }; diff --git a/sync/Cargo.toml b/sync/Cargo.toml index becfa8a120..eaa78f145f 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -52,7 +52,7 @@ hex = { workspace = true } starcoin-miner = { workspace = true } starcoin-account-api = { workspace = true } starcoin-block-relayer = { workspace = true } -starcoin-chain-mock = { workspace = true, features = ["sync-dag-test"] } +starcoin-chain-mock = { workspace = true } starcoin-consensus = { workspace = true } starcoin-node = { workspace = true } starcoin-state-service = { workspace = true } diff --git a/sync/src/block_connector/test_write_dag_block_chain.rs b/sync/src/block_connector/test_write_dag_block_chain.rs index ebf1645dcc..fa7c6f2b6e 100644 --- a/sync/src/block_connector/test_write_dag_block_chain.rs +++ b/sync/src/block_connector/test_write_dag_block_chain.rs @@ -81,7 +81,10 @@ pub fn new_dag_block( } let block_chain = writeable_block_chain_service.get_main(); - let tips = block_chain.current_tips_hash().expect("failed to get tips"); + let (_dag_genesis, tips) = block_chain + .current_tips_hash(&block_chain.current_header()) + .expect("failed to get tips") + .expect("failed to get the tip and dag genesis"); let (block_template, _) = block_chain .create_block_template( miner_address, diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index ad84998f60..d55baf1e8c 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -734,6 +734,9 @@ where let (block_info, action) = match block_info { Some(block_info) => { + //If block_info exists, it means that this block was already executed and try to connect in the previous sync, but the sync task was interrupted. + //So, we need make sure the dag genesis is initialized properly, then update chain and continue + self.chain.init_dag_with_genesis(block.header().clone())?; self.chain.connect(ExecutedBlock { block: block.clone(), block_info: block_info.clone(),