From ee7104fbb7ab2ef0522ed37d4c548e7aa95720e8 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 28 Aug 2024 18:28:24 +0800 Subject: [PATCH 01/60] add parallel code --- .../src/consensusdb/consensus_reachability.rs | 2 +- sync/Cargo.toml | 1 + sync/src/lib.rs | 1 + sync/src/parallel/executor.rs | 179 ++++++++++++++++++ sync/src/parallel/mod.rs | 2 + sync/src/parallel/sender.rs | 156 +++++++++++++++ sync/src/store/sync_dag_store.rs | 17 +- sync/src/store/tests.rs | 71 ++++++- sync/src/tasks/block_sync_task.rs | 55 +++--- 9 files changed, 455 insertions(+), 29 deletions(-) create mode 100644 sync/src/parallel/executor.rs create mode 100644 sync/src/parallel/mod.rs create mode 100644 sync/src/parallel/sender.rs diff --git a/flexidag/src/consensusdb/consensus_reachability.rs b/flexidag/src/consensusdb/consensus_reachability.rs index 282a000abf..55adbfb338 100644 --- a/flexidag/src/consensusdb/consensus_reachability.rs +++ b/flexidag/src/consensusdb/consensus_reachability.rs @@ -50,7 +50,7 @@ pub trait ReachabilityStore: ReachabilityStoreReader { } pub const REINDEX_ROOT_KEY: &str = "reachability-reindex-root"; -pub(crate) const REACHABILITY_DATA_CF: &str = "reachability-data"; +pub const REACHABILITY_DATA_CF: &str = "reachability-data"; // TODO: explore perf to see if using fixed-length constants for store prefixes is preferable define_schema!( diff --git a/sync/Cargo.toml b/sync/Cargo.toml index c91d2c7084..8842133038 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -48,6 +48,7 @@ timeout-join-handler = { workspace = true } starcoin-dag = { workspace = true } serde = { workspace = true } byteorder = { workspace = true } +tokio = { features = ["full"], workspace = true } [dev-dependencies] hex = { workspace = true } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index ebf07c00d2..bb5860ab2c 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -11,3 +11,4 @@ pub mod tasks; pub mod txn_sync; pub mod verified_rpc_client; +pub mod parallel; \ No newline at end of file diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs new file mode 100644 index 0000000000..f0e9f33cf5 --- /dev/null +++ b/sync/src/parallel/executor.rs @@ -0,0 +1,179 @@ +use std::sync::Arc; + +use starcoin_chain::{verifier::DagVerifier, BlockChain, ChainReader}; +use starcoin_config::TimeService; +use starcoin_crypto::HashValue; +use starcoin_dag::blockdag::BlockDAG; +use starcoin_executor::VMMetrics; +use starcoin_logger::prelude::{error, info}; +use starcoin_storage::Store; +use starcoin_types::block::{Block, BlockHeader}; +use tokio::{ + sync::mpsc::{self, Receiver, Sender}, + time::{timeout, Duration}, +}; + +#[derive(Debug)] +pub enum ExecuteState { + Ready(HashValue), + Executing(HashValue), + Executed(BlockHeader), + Error(BlockHeader), + Closed, +} + +pub struct DagBlockExecutor { + sender: Sender, + receiver: Receiver, + chain: BlockChain, +} + +impl DagBlockExecutor { + pub fn new( + sender_to_main: Sender, + buffer_size: usize, + time_service: Arc, + head_block_hash: HashValue, + storage: Arc, + vm_metrics: Option, + dag: BlockDAG, + ) -> anyhow::Result<(Sender, Self)> { + let (sender_for_main, receiver) = mpsc::channel::(buffer_size); + let chain = BlockChain::new(time_service, head_block_hash, storage, vm_metrics, dag)?; + let executor = Self { + sender: sender_to_main, + receiver, + chain, + }; + anyhow::Ok((sender_for_main, executor)) + } + + pub fn waiting_for_parents( + chain: &BlockChain, + parents_hash: Vec, + ) -> anyhow::Result { + for parent_id in parents_hash { + if !chain.dag().has_dag_block(parent_id)? { + return Ok(false); + } + } + Ok(true) + } + + pub fn start_to_execute(mut self) -> anyhow::Result<()> { + tokio::spawn(async move { + loop { + match timeout(Duration::from_secs(10), self.receiver.recv()).await { + Ok(Some(block)) => { + let header = block.header().clone(); + + match self + .sender + .send(ExecuteState::Executing(header.id())) + .await + { + Ok(_) => (), + Err(e) => { + error!( + "failed to send executing state: {:?}, for reason: {:?}", + header, e + ); + return; + } + } + + loop { + match Self::waiting_for_parents( + &self.chain, + block.header().parents_hash(), + ) { + Ok(true) => break, + Ok(false) => tokio::task::yield_now().await, + Err(e) => { + error!( + "failed to check parents: {:?}, for reason: {:?}", + header, e + ); + match self + .sender + .send(ExecuteState::Error(header.clone())) + .await + { + Ok(_) => (), + Err(e) => { + error!("failed to send error state: {:?}, for reason: {:?}", header, e); + return; + } + } + return; + } + } + } + + if self.chain.status().head().id() != block.header().parent_hash() { + self.chain = match self.chain.fork(block.header().parent_hash()) { + Ok(chain) => chain, + Err(e) => { + error!("failed to fork in parallel for: {:?}", e); + return; + } + } + } + + match self.chain.apply_with_verifier::(block) { + Ok(executed_block) => { + let header = executed_block.header(); + info!( + "succeed to execute block: number: {:?}, id: {:?}", + header.number(), + header.id() + ); + match self + .sender + .send(ExecuteState::Executed(header.clone())) + .await + { + Ok(_) => (), + Err(e) => { + error!( + "failed to send waiting state: {:?}, for reason: {:?}", + header, e + ); + return; + } + } + } + Err(e) => { + error!( + "failed to execute block: {:?}, for reason: {:?}", + header, e + ); + match self.sender.send(ExecuteState::Error(header.clone())).await { + Ok(_) => (), + Err(e) => { + error!( + "failed to send error state: {:?}, for reason: {:?}", + header, e + ); + return; + } + } + return; + } + } + } + Ok(None) => { + info!("sync worker channel closed"); + return; + } + Err(e) => { + info!("timeout occurs: {:?}", e); + return; + } + } + } + }); + + anyhow::Ok(()) + } +} diff --git a/sync/src/parallel/mod.rs b/sync/src/parallel/mod.rs new file mode 100644 index 0000000000..98cc4ed310 --- /dev/null +++ b/sync/src/parallel/mod.rs @@ -0,0 +1,2 @@ +mod executor; +pub mod sender; diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs new file mode 100644 index 0000000000..3c9cdda27e --- /dev/null +++ b/sync/src/parallel/sender.rs @@ -0,0 +1,156 @@ +use std::{ops::Deref, sync::Arc, vec}; + +use starcoin_config::TimeService; +use starcoin_crypto::HashValue; +use starcoin_dag::{blockdag::BlockDAG, consensusdb::schema::ValueCodec, reachability::inquirer}; +use starcoin_executor::VMMetrics; +use starcoin_logger::prelude::error; +use starcoin_network::worker; +use starcoin_storage::Store; +use starcoin_types::block::{Block, BlockHeader}; +use tokio::sync::mpsc::{self, Receiver, Sender}; + +use crate::store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::{self, SyncDagStore}}; + +use super::executor::{DagBlockExecutor, ExecuteState}; + +struct DagBlockWorker { + pub sender_to_executor: Sender, + pub receiver_from_executor: Receiver, + pub state: ExecuteState, +} + +pub struct DagBlockSender { + sync_dag_store: SyncDagStore, + executors: Vec, + queue_size: usize, + time_service: Arc, + storage: Arc, + vm_metrics: Option, + dag: BlockDAG, +} + +impl DagBlockSender { + pub fn new( + sync_dag_store: SyncDagStore, + queue_size: usize, + time_service: Arc, + storage: Arc, + vm_metrics: Option, + dag: BlockDAG, + ) -> Self { + Self { + sync_dag_store, + executors: vec![], + queue_size, + time_service, + storage, + vm_metrics, + dag, + } + } + + async fn dispatch_to_worker(&mut self, block: &Block) -> anyhow::Result { + for executor in &mut self.executors { + match &executor.state { + ExecuteState::Executed(executing_header_block) => { + if inquirer::is_dag_ancestor_of( + self.sync_dag_store.reachability_store.read().deref(), + executing_header_block.id(), + block.id(), + )? { + executor.state = ExecuteState::Executing(block.id()); + executor.sender_to_executor.send(block.clone()).await?; + return anyhow::Ok(true); + } + } + ExecuteState::Executing(header_id) => { + if inquirer::is_dag_ancestor_of( + self.sync_dag_store.reachability_store.read().deref(), + *header_id, + block.id(), + )? { + executor.sender_to_executor.send(block.clone()).await?; + return anyhow::Ok(true); + } + } + ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + continue; + } + } + } + + anyhow::Ok(false) + } + + pub async fn process_absent_blocks(&mut self) -> anyhow::Result<()> { + let sync_dag_store = self.sync_dag_store.clone(); + let iter = sync_dag_store.iter_at_first()?; + for result_value in iter { + let (_, value) = result_value?; + let block = DagSyncBlock::decode_value(&value)?.block.ok_or_else(|| { + anyhow::format_err!("failed to decode for the block in parallel!") + })?; + + // Finding the executing state is the priority + if self.dispatch_to_worker(&block).await? { + continue; + } + + // no suitable worker found, create a new worker + let chain_header = self + .storage + .get_block_header_by_hash(block.header().parent_hash())? + .ok_or_else(|| { + anyhow::format_err!( + "in parallel sync, failed to get the block header by hash: {:?}", + block.header().parent_hash() + ) + })?; + let (sender_for_main, receiver) = mpsc::channel::(self.queue_size); + let (sender_to_worker, executor) = DagBlockExecutor::new( + sender_for_main, + self.queue_size, + self.time_service.clone(), + chain_header.id(), + self.storage.clone(), + self.vm_metrics.clone(), + self.dag.clone(), + )?; + + self.executors.push(DagBlockWorker { + sender_to_executor: sender_to_worker.clone(), + receiver_from_executor: receiver, + state: ExecuteState::Ready(block.id()), + }); + + executor.start_to_execute()?; + sender_to_worker.send(block).await?; + + self.flush_executor_state().await?; + } + Ok(()) + } + + async fn flush_executor_state(&mut self) -> anyhow::Result<()> { + for worker in &mut self.executors { + match worker.receiver_from_executor.recv().await { + Some(state) => { + worker.state = state; + } + None => { + worker.state = ExecuteState::Closed; + }, + } + } + + self.executors.retain(|worker| { + if let ExecuteState::Closed = worker.state { + false + } else { + true + } + }); + anyhow::Ok(()) + } +} diff --git a/sync/src/store/sync_dag_store.rs b/sync/src/store/sync_dag_store.rs index af4b7c8f26..ce08de6f51 100644 --- a/sync/src/store/sync_dag_store.rs +++ b/sync/src/store/sync_dag_store.rs @@ -1,9 +1,10 @@ -use std::{path::Path, sync::Arc}; +use std::{ops::DerefMut, path::Path, sync::Arc}; use anyhow::format_err; +use parking_lot::RwLock; use starcoin_config::{temp_dir, RocksdbConfig, StorageConfig}; use starcoin_crypto::HashValue; -use starcoin_dag::consensusdb::prelude::StoreError; +use starcoin_dag::{consensusdb::{prelude::StoreError, schemadb::{DbReachabilityStore, MemoryReachabilityStore, REACHABILITY_DATA_CF}}, reachability::inquirer}; use starcoin_logger::prelude::error; use starcoin_storage::db_storage::{DBStorage, SchemaIterator}; use starcoin_types::block::{Block, BlockNumber}; @@ -16,6 +17,7 @@ use super::sync_absent_ancestor::{ #[derive(Clone)] pub struct SyncDagStore { pub absent_dag_store: SyncAbsentBlockStore, + pub reachability_store: Arc> } #[derive(Clone)] @@ -64,7 +66,7 @@ impl SyncDagStore { let db = Arc::new( DBStorage::open_with_cfs( db_path, - vec![SYNC_ABSENT_BLOCK_CF], + vec![SYNC_ABSENT_BLOCK_CF, REACHABILITY_DATA_CF], false, config.rocksdb_config, None, @@ -73,7 +75,8 @@ impl SyncDagStore { ); Ok(Self { - absent_dag_store: SyncAbsentBlockStore::new(db, config.cache_size), + absent_dag_store: SyncAbsentBlockStore::new(db.clone(), config.cache_size), + reachability_store: Arc::new(RwLock::new(MemoryReachabilityStore::new())), }) } @@ -111,6 +114,12 @@ impl SyncDagStore { block: Some(block.clone()), }]) .map_err(|e| format_err!("Failed to save absent block: {:?}", e))?; + + { + let mut writer = self.reachability_store.write(); + inquirer::add_block(writer.deref_mut(), block.id(), block.header().parent_hash(), &mut [block.header().parents_hash()].into_iter().flatten())?; + drop(writer); + } Ok(()) } _ => Err(format_err!( diff --git a/sync/src/store/tests.rs b/sync/src/store/tests.rs index 4fb598dec3..ee8cc8c8f1 100644 --- a/sync/src/store/tests.rs +++ b/sync/src/store/tests.rs @@ -1,6 +1,20 @@ +use std::{ + ops::{Deref, DerefMut}, + sync::Arc, + u64, +}; + use anyhow::Ok; +use parking_lot::RwLock; use starcoin_crypto::HashValue; -use starcoin_dag::consensusdb::schema::{KeyCodec, ValueCodec}; +use starcoin_dag::{ + consensusdb::{ + schema::{KeyCodec, ValueCodec}, + schemadb::MemoryReachabilityStore, + }, + reachability::inquirer, + types::interval::Interval, +}; use starcoin_types::{ account_address::AccountAddress, block::{Block, BlockBody, BlockHeader, BlockHeaderBuilder, BlockHeaderExtra, BlockNumber}, @@ -66,6 +80,61 @@ fn build_version_0_block(number: BlockNumber) -> Block { Block::new(header, body) } +#[test] +fn test_add_reachability_data() -> anyhow::Result<()> { + let mut sync_dag_store = SyncDagStore::create_for_testing()?; + let reachability_store = sync_dag_store.reachability_store.clone(); + + let mut writer = reachability_store.write(); + + let x = HashValue::random(); + let a = HashValue::random(); + let b = HashValue::random(); + let c = HashValue::random(); + let d = HashValue::random(); + let e = HashValue::random(); + + inquirer::init_with_params(writer.deref_mut(), x, Interval::maximal())?; + + inquirer::add_block(writer.deref_mut(), a, x, &mut [x].into_iter())?; + inquirer::add_block(writer.deref_mut(), b, a, &mut [a].into_iter())?; + inquirer::add_block(writer.deref_mut(), c, a, &mut [a].into_iter())?; + inquirer::add_block(writer.deref_mut(), d, a, &mut [a].into_iter())?; + inquirer::add_block(writer.deref_mut(), e, b, &mut [c, d].into_iter())?; + + drop(writer); + + let reader = reachability_store.read(); + + assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, b)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, c)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, d)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, e)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), b, e)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), c, e)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), d, e)?); + + drop(reader); + + sync_dag_store.reachability_store = Arc::new(RwLock::new(MemoryReachabilityStore::new())); + let mut writer = sync_dag_store.reachability_store.write(); + + inquirer::init_with_params(writer.deref_mut(), 1.into(), Interval::maximal())?; + inquirer::add_block(writer.deref_mut(), e, 1.into(), &mut [1.into()].into_iter())?; + inquirer::add_block(writer.deref_mut(), a, e, &mut [e].into_iter())?; + + drop(writer); + + let reader = sync_dag_store.reachability_store.read(); + + assert!(inquirer::is_dag_ancestor_of(reader.deref(), e, a)?); + assert!(inquirer::is_dag_ancestor_of(reader.deref(), b, e).is_err()); + + drop(reader); + + anyhow::Ok(()) +} + #[test] fn test_sync_dag_absent_store() -> anyhow::Result<()> { let sync_dag_store = SyncDagStore::create_for_testing()?; diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index d53254427f..fdf5385d92 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -1,6 +1,7 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 +use crate::parallel::sender::DagBlockSender; use crate::store::sync_absent_ancestor::DagSyncBlock; use crate::store::sync_dag_store::SyncDagStore; use crate::tasks::continue_execute_absent_block::ContinueExecuteAbsentBlock; @@ -444,29 +445,37 @@ where self.find_absent_ancestor(vec![block_header.clone()]) .await?; - let sync_dag_store = self.sync_dag_store.clone(); - let mut absent_block_iter = sync_dag_store - .iter_at_first() - .context("Failed to create iterator for sync_dag_store")?; - loop { - debug!("start to read local absent block and try to execute the dag if its parents are ready."); - let mut local_absent_block = vec![]; - match self.read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) - { - anyhow::Result::Ok(_) => { - if local_absent_block.is_empty() { - info!("absent block is empty, continue to sync"); - break; - } - self.execute_absent_block(&mut local_absent_block) - .context("Failed to execute absent block")?; - } - Err(e) => { - error!("failed to read local absent block, error: {:?}", e); - return Err(e); - } - } - } + let mut parallel_execute = DagBlockSender::new( + self.sync_dag_store.clone(), + usize::try_from(u64::MAX)?, + self.chain.time_service(), + self.local_store.clone(), + None, self.chain.dag()); + parallel_execute.process_absent_blocks().await?; + + // let sync_dag_store = self.sync_dag_store.clone(); + // let mut absent_block_iter = sync_dag_store + // .iter_at_first() + // .context("Failed to create iterator for sync_dag_store")?; + // loop { + // debug!("start to read local absent block and try to execute the dag if its parents are ready."); + // let mut local_absent_block = vec![]; + // match self.read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) + // { + // anyhow::Result::Ok(_) => { + // if local_absent_block.is_empty() { + // info!("absent block is empty, continue to sync"); + // break; + // } + // self.execute_absent_block(&mut local_absent_block) + // .context("Failed to execute absent block")?; + // } + // Err(e) => { + // error!("failed to read local absent block, error: {:?}", e); + // return Err(e); + // } + // } + // } Ok(()) }; From 85b9b45dd47407490898121b26e305b470be070e Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 28 Aug 2024 19:45:21 +0800 Subject: [PATCH 02/60] use try recv to avoid blocking --- sync/src/parallel/sender.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index 3c9cdda27e..c7efc5ea5e 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -107,9 +107,9 @@ impl DagBlockSender { block.header().parent_hash() ) })?; - let (sender_for_main, receiver) = mpsc::channel::(self.queue_size); + let (sender_to_main, receiver_from_executor) = mpsc::channel::(self.queue_size); let (sender_to_worker, executor) = DagBlockExecutor::new( - sender_for_main, + sender_to_main, self.queue_size, self.time_service.clone(), chain_header.id(), @@ -120,7 +120,7 @@ impl DagBlockSender { self.executors.push(DagBlockWorker { sender_to_executor: sender_to_worker.clone(), - receiver_from_executor: receiver, + receiver_from_executor, state: ExecuteState::Ready(block.id()), }); @@ -134,13 +134,14 @@ impl DagBlockSender { async fn flush_executor_state(&mut self) -> anyhow::Result<()> { for worker in &mut self.executors { - match worker.receiver_from_executor.recv().await { - Some(state) => { - worker.state = state; + match worker.receiver_from_executor.try_recv() { + Ok(state) => worker.state = state, + Err(e) => { + match e { + mpsc::error::TryRecvError::Empty => continue, + mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + } } - None => { - worker.state = ExecuteState::Closed; - }, } } From 2d672b4ed2940189b37f6c3b0f588e2cc314fde2 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 00:33:27 +0800 Subject: [PATCH 03/60] parallel execution --- flexidag/src/blockdag.rs | 4 ++ flexidag/src/reachability/inquirer.rs | 2 +- sync/src/parallel/executor.rs | 2 +- sync/src/parallel/sender.rs | 49 +++++++++++++++++++----- sync/src/store/sync_dag_store.rs | 9 +---- sync/src/store/tests.rs | 24 ++---------- sync/src/sync.rs | 43 ++++++++++----------- sync/src/tasks/block_sync_task.rs | 2 +- sync/src/tasks/inner_sync_task.rs | 54 +++++++++++++-------------- sync/src/tasks/mock.rs | 3 +- 10 files changed, 99 insertions(+), 93 deletions(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 4ce5177410..6f3fc81254 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -416,4 +416,8 @@ impl BlockDAG { anyhow::Ok(()) } + + pub fn reachability_store(&self) -> Arc> { + self.storage.reachability_store.clone() + } } diff --git a/flexidag/src/reachability/inquirer.rs b/flexidag/src/reachability/inquirer.rs index 3d3e5dec5f..fa6f8cbd68 100644 --- a/flexidag/src/reachability/inquirer.rs +++ b/flexidag/src/reachability/inquirer.rs @@ -18,7 +18,7 @@ pub fn init_for_test( init_with_params(store, origin, capacity) } -pub(super) fn init_with_params( +pub fn init_with_params( store: &mut (impl ReachabilityStore + ?Sized), origin: Hash, capacity: Interval, diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index f0e9f33cf5..65bae1c37e 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -63,7 +63,7 @@ impl DagBlockExecutor { pub fn start_to_execute(mut self) -> anyhow::Result<()> { tokio::spawn(async move { loop { - match timeout(Duration::from_secs(10), self.receiver.recv()).await { + match timeout(Duration::from_secs(1), self.receiver.recv()).await { Ok(Some(block)) => { let header = block.header().clone(); diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index c7efc5ea5e..dbe599a6b9 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -54,22 +54,15 @@ impl DagBlockSender { for executor in &mut self.executors { match &executor.state { ExecuteState::Executed(executing_header_block) => { - if inquirer::is_dag_ancestor_of( - self.sync_dag_store.reachability_store.read().deref(), - executing_header_block.id(), - block.id(), - )? { + if executing_header_block.id() == block.header().parent_hash() { executor.state = ExecuteState::Executing(block.id()); executor.sender_to_executor.send(block.clone()).await?; return anyhow::Ok(true); } } ExecuteState::Executing(header_id) => { - if inquirer::is_dag_ancestor_of( - self.sync_dag_store.reachability_store.read().deref(), - *header_id, - block.id(), - )? { + if *header_id == block.header().id() { + executor.state = ExecuteState::Executing(block.id()); executor.sender_to_executor.send(block.clone()).await?; return anyhow::Ok(true); } @@ -94,6 +87,7 @@ impl DagBlockSender { // Finding the executing state is the priority if self.dispatch_to_worker(&block).await? { + self.flush_executor_state().await?; continue; } @@ -129,6 +123,10 @@ impl DagBlockSender { self.flush_executor_state().await?; } + + self.sync_dag_store.delete_all_dag_sync_block()?; + + self.wait_for_finish().await?; Ok(()) } @@ -154,4 +152,35 @@ impl DagBlockSender { }); anyhow::Ok(()) } + + async fn wait_for_finish(&mut self) -> anyhow::Result<()> { + loop { + for worker in &mut self.executors { + match worker.receiver_from_executor.try_recv() { + Ok(state) => worker.state = state, + Err(e) => { + match e { + mpsc::error::TryRecvError::Empty => continue, + mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + } + } + } + } + + self.executors.retain(|worker| { + if let ExecuteState::Closed = worker.state { + false + } else { + true + } + }); + + if self.executors.is_empty() { + break; + } + tokio::task::yield_now().await; + } + + anyhow::Ok(()) + } } diff --git a/sync/src/store/sync_dag_store.rs b/sync/src/store/sync_dag_store.rs index ce08de6f51..7d90b8d894 100644 --- a/sync/src/store/sync_dag_store.rs +++ b/sync/src/store/sync_dag_store.rs @@ -4,7 +4,7 @@ use anyhow::format_err; use parking_lot::RwLock; use starcoin_config::{temp_dir, RocksdbConfig, StorageConfig}; use starcoin_crypto::HashValue; -use starcoin_dag::{consensusdb::{prelude::StoreError, schemadb::{DbReachabilityStore, MemoryReachabilityStore, REACHABILITY_DATA_CF}}, reachability::inquirer}; +use starcoin_dag::{consensusdb::{prelude::StoreError, schemadb::{DbReachabilityStore, MemoryReachabilityStore, ReachabilityStore, REACHABILITY_DATA_CF}}, reachability::inquirer}; use starcoin_logger::prelude::error; use starcoin_storage::db_storage::{DBStorage, SchemaIterator}; use starcoin_types::block::{Block, BlockNumber}; @@ -17,7 +17,6 @@ use super::sync_absent_ancestor::{ #[derive(Clone)] pub struct SyncDagStore { pub absent_dag_store: SyncAbsentBlockStore, - pub reachability_store: Arc> } #[derive(Clone)] @@ -76,7 +75,6 @@ impl SyncDagStore { Ok(Self { absent_dag_store: SyncAbsentBlockStore::new(db.clone(), config.cache_size), - reachability_store: Arc::new(RwLock::new(MemoryReachabilityStore::new())), }) } @@ -115,11 +113,6 @@ impl SyncDagStore { }]) .map_err(|e| format_err!("Failed to save absent block: {:?}", e))?; - { - let mut writer = self.reachability_store.write(); - inquirer::add_block(writer.deref_mut(), block.id(), block.header().parent_hash(), &mut [block.header().parents_hash()].into_iter().flatten())?; - drop(writer); - } Ok(()) } _ => Err(format_err!( diff --git a/sync/src/store/tests.rs b/sync/src/store/tests.rs index ee8cc8c8f1..618116d81e 100644 --- a/sync/src/store/tests.rs +++ b/sync/src/store/tests.rs @@ -8,12 +8,10 @@ use anyhow::Ok; use parking_lot::RwLock; use starcoin_crypto::HashValue; use starcoin_dag::{ - consensusdb::{ + blockdag::BlockDAG, consensusdb::{ schema::{KeyCodec, ValueCodec}, schemadb::MemoryReachabilityStore, - }, - reachability::inquirer, - types::interval::Interval, + }, reachability::inquirer, types::interval::Interval }; use starcoin_types::{ account_address::AccountAddress, @@ -116,27 +114,12 @@ fn test_add_reachability_data() -> anyhow::Result<()> { drop(reader); - sync_dag_store.reachability_store = Arc::new(RwLock::new(MemoryReachabilityStore::new())); - let mut writer = sync_dag_store.reachability_store.write(); - - inquirer::init_with_params(writer.deref_mut(), 1.into(), Interval::maximal())?; - inquirer::add_block(writer.deref_mut(), e, 1.into(), &mut [1.into()].into_iter())?; - inquirer::add_block(writer.deref_mut(), a, e, &mut [e].into_iter())?; - - drop(writer); - - let reader = sync_dag_store.reachability_store.read(); - - assert!(inquirer::is_dag_ancestor_of(reader.deref(), e, a)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), b, e).is_err()); - - drop(reader); - anyhow::Ok(()) } #[test] fn test_sync_dag_absent_store() -> anyhow::Result<()> { + let dag = BlockDAG::create_for_testing()?; let sync_dag_store = SyncDagStore::create_for_testing()?; // write and read @@ -208,6 +191,7 @@ fn test_sync_dag_absent_store() -> anyhow::Result<()> { #[test] fn test_write_read_in_order() -> anyhow::Result<()> { + let dag = BlockDAG::create_for_testing()?; let sync_dag_store = SyncDagStore::create_for_testing()?; // write and read diff --git a/sync/src/sync.rs b/sync/src/sync.rs index 4371b7f5b0..535d7be53a 100644 --- a/sync/src/sync.rs +++ b/sync/src/sync.rs @@ -62,7 +62,6 @@ pub struct SyncService { stage: SyncStage, config: Arc, storage: Arc, - sync_dag_store: SyncDagStore, metrics: Option, peer_score_metrics: Option, vm_metrics: Option, @@ -84,13 +83,6 @@ impl SyncService { let head_block_info = storage .get_block_info(head_block_hash)? .ok_or_else(|| format_err!("can't get block info by hash {}", head_block_hash))?; - let sync_dag_store = SyncDagStore::create_from_path( - config.storage.sync_dir(), - SyncDagStoreConfig::create_with_params( - config.storage.cache_size(), - RocksdbConfig::default(), - ), - )?; //TODO bail PrometheusError after use custom metrics registry. let metrics = config .metrics @@ -105,7 +97,6 @@ impl SyncService { stage: SyncStage::NotStart, config, storage, - sync_dag_store, metrics, peer_score_metrics, vm_metrics, @@ -235,7 +226,13 @@ impl SyncService { let sync_metrics = self.metrics.clone(); let vm_metrics = self.vm_metrics.clone(); let dag = ctx.get_shared::()?; - let sync_dag_store = self.sync_dag_store.clone(); + let sync_dag_store = SyncDagStore::create_from_path( + config.storage.sync_dir(), + SyncDagStoreConfig::create_with_params( + config.storage.cache_size(), + RocksdbConfig::default(), + ), + )?; let fut = async move { let startup_info = storage .get_startup_info()? @@ -621,19 +618,19 @@ impl EventHandler for SyncService { } } -#[derive(Debug, Clone)] -pub struct SaveSyncBlock { - pub block: Block, -} - -impl EventHandler for SyncService { - fn handle_event(&mut self, msg: SaveSyncBlock, _ctx: &mut ServiceContext) { - let block = msg.block; - if let Err(e) = self.sync_dag_store.save_block(block) { - error!("[sync] Save absent block error: {:?}", e); - } - } -} +// #[derive(Debug, Clone)] +// pub struct SaveSyncBlock { +// pub block: Block, +// } + +// impl EventHandler for SyncService { +// fn handle_event(&mut self, msg: SaveSyncBlock, _ctx: &mut ServiceContext) { +// let block = msg.block; +// if let Err(e) = self.sync_dag_store.save_block(block) { +// error!("[sync] Save absent block error: {:?}", e); +// } +// } +// } impl ServiceHandler for SyncService { fn handle(&mut self, _msg: SyncStatusRequest, _ctx: &mut ServiceContext) -> SyncStatus { diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index fdf5385d92..2cd6521ab3 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -447,7 +447,7 @@ where let mut parallel_execute = DagBlockSender::new( self.sync_dag_store.clone(), - usize::try_from(u64::MAX)?, + 100, self.chain.time_service(), self.local_store.clone(), None, self.chain.dag()); diff --git a/sync/src/tasks/inner_sync_task.rs b/sync/src/tasks/inner_sync_task.rs index d5ab214000..ba25d78b24 100644 --- a/sync/src/tasks/inner_sync_task.rs +++ b/sync/src/tasks/inner_sync_task.rs @@ -158,33 +158,33 @@ where self.sync_dag_store.clone(), ); - let mut absent_block_iter = self.sync_dag_store.iter_at_first()?; - loop { - let mut local_absent_block = vec![]; - match block_collector - .read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) - { - anyhow::Result::Ok(_) => { - if local_absent_block.is_empty() { - info!("absent block is empty, continue to sync"); - break; - } - match block_collector.execute_absent_block(&mut local_absent_block) { - anyhow::Result::Ok(_) => (), - Err(e) => { - error!("failed to execute absent block, error: {:?}, break from the continuing block execution", e); - break; - } - } - } - Err(e) => { - error!("failed to read local absent block, error: {:?}, break from the continuing block execution", e); - break; - } - } - } - // clear the dag sync if fork happened - self.sync_dag_store.delete_all_dag_sync_block()?; + // let mut absent_block_iter = self.sync_dag_store.iter_at_first()?; + // loop { + // let mut local_absent_block = vec![]; + // match block_collector + // .read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) + // { + // anyhow::Result::Ok(_) => { + // if local_absent_block.is_empty() { + // info!("absent block is empty, continue to sync"); + // break; + // } + // match block_collector.execute_absent_block(&mut local_absent_block) { + // anyhow::Result::Ok(_) => (), + // Err(e) => { + // error!("failed to execute absent block, error: {:?}, break from the continuing block execution", e); + // break; + // } + // } + // } + // Err(e) => { + // error!("failed to read local absent block, error: {:?}, break from the continuing block execution", e); + // break; + // } + // } + // } + // // clear the dag sync if fork happened + // self.sync_dag_store.delete_all_dag_sync_block()?; Ok(TaskGenerator::new( block_sync_task, diff --git a/sync/src/tasks/mock.rs b/sync/src/tasks/mock.rs index 96b9822d1b..15a59bb79c 100644 --- a/sync/src/tasks/mock.rs +++ b/sync/src/tasks/mock.rs @@ -155,8 +155,7 @@ impl SyncNodeMocker { None, ); let peer_selector = PeerSelector::new(vec![peer_info], PeerStrategy::default(), None); - let sync_dag_store = SyncDagStore::create_for_testing() - .context("Failed to create SyncDagStore for testing")?; + let sync_dag_store = SyncDagStore::create_for_testing().context("Failed to create SyncDagStore for testing")?; Ok(Self::new_inner( peer_id, chain, From e575d6d16571174ecfa603f13730bd219b423562 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 02:36:20 +0800 Subject: [PATCH 04/60] create chain when the parents are ready in parallel execution --- sync/src/parallel/executor.rs | 58 +++++++++++++++++++++++------------ sync/src/parallel/sender.rs | 53 ++++++++++++-------------------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index 65bae1c37e..618669846d 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -9,8 +9,7 @@ use starcoin_logger::prelude::{error, info}; use starcoin_storage::Store; use starcoin_types::block::{Block, BlockHeader}; use tokio::{ - sync::mpsc::{self, Receiver, Sender}, - time::{timeout, Duration}, + sync::mpsc::{self, Receiver, Sender}, task::JoinHandle, time::{timeout, Duration} }; #[derive(Debug)] @@ -25,7 +24,10 @@ pub enum ExecuteState { pub struct DagBlockExecutor { sender: Sender, receiver: Receiver, - chain: BlockChain, + time_service: Arc, + storage: Arc, + vm_metrics: Option, + dag: BlockDAG } impl DagBlockExecutor { @@ -39,29 +41,32 @@ impl DagBlockExecutor { dag: BlockDAG, ) -> anyhow::Result<(Sender, Self)> { let (sender_for_main, receiver) = mpsc::channel::(buffer_size); - let chain = BlockChain::new(time_service, head_block_hash, storage, vm_metrics, dag)?; let executor = Self { sender: sender_to_main, receiver, - chain, + time_service, + storage, + vm_metrics, + dag, }; anyhow::Ok((sender_for_main, executor)) } pub fn waiting_for_parents( - chain: &BlockChain, + chain: &BlockDAG, parents_hash: Vec, ) -> anyhow::Result { for parent_id in parents_hash { - if !chain.dag().has_dag_block(parent_id)? { + if !chain.has_dag_block(parent_id)? { return Ok(false); } } Ok(true) } - pub fn start_to_execute(mut self) -> anyhow::Result<()> { - tokio::spawn(async move { + pub fn start_to_execute(mut self) -> anyhow::Result> { + let handle = tokio::spawn(async move { + let mut chain = None; loop { match timeout(Duration::from_secs(1), self.receiver.recv()).await { Ok(Some(block)) => { @@ -84,7 +89,7 @@ impl DagBlockExecutor { loop { match Self::waiting_for_parents( - &self.chain, + &self.dag, block.header().parents_hash(), ) { Ok(true) => break, @@ -110,17 +115,33 @@ impl DagBlockExecutor { } } - if self.chain.status().head().id() != block.header().parent_hash() { - self.chain = match self.chain.fork(block.header().parent_hash()) { - Ok(chain) => chain, - Err(e) => { - error!("failed to fork in parallel for: {:?}", e); - return; + match chain { + None => { + chain = match BlockChain::new(self.time_service.clone(), block.header().parent_hash(), self.storage.clone(), self.vm_metrics.clone(), self.dag.clone()) { + Ok(new_chain) => Some(new_chain), + Err(e) => { + error!("failed to create chain for block: {:?} for {:?}", block.header().id(), e); + return; + } + } + } + Some(old_chain) => { + if old_chain.status().head().id() != block.header().parent_hash(){ + chain = match old_chain.fork(block.header().parent_hash()) { + Ok(new_chain) => Some(new_chain), + Err(e) => { + error!("failed to fork in parallel for: {:?}", e); + return; + } + } + } else { + chain = Some(old_chain); } } } - match self.chain.apply_with_verifier::(block) { + info!("sync parallel worker {:p} will execute block: {:?}", &self, block.header().id()); + match chain.as_mut().expect("it cannot be none!").apply_with_verifier::(block) { Ok(executed_block) => { let header = executed_block.header(); info!( @@ -167,13 +188,12 @@ impl DagBlockExecutor { return; } Err(e) => { - info!("timeout occurs: {:?}", e); return; } } } }); - anyhow::Ok(()) + anyhow::Ok(handle) } } diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index dbe599a6b9..5c40710b88 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -4,11 +4,11 @@ use starcoin_config::TimeService; use starcoin_crypto::HashValue; use starcoin_dag::{blockdag::BlockDAG, consensusdb::schema::ValueCodec, reachability::inquirer}; use starcoin_executor::VMMetrics; -use starcoin_logger::prelude::error; +use starcoin_logger::prelude::{error, info}; use starcoin_network::worker; use starcoin_storage::Store; use starcoin_types::block::{Block, BlockHeader}; -use tokio::sync::mpsc::{self, Receiver, Sender}; +use tokio::{sync::mpsc::{self, Receiver, Sender}, task::JoinHandle}; use crate::store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::{self, SyncDagStore}}; @@ -18,6 +18,7 @@ struct DagBlockWorker { pub sender_to_executor: Sender, pub receiver_from_executor: Receiver, pub state: ExecuteState, + pub handle: JoinHandle<()>, } pub struct DagBlockSender { @@ -92,21 +93,12 @@ impl DagBlockSender { } // no suitable worker found, create a new worker - let chain_header = self - .storage - .get_block_header_by_hash(block.header().parent_hash())? - .ok_or_else(|| { - anyhow::format_err!( - "in parallel sync, failed to get the block header by hash: {:?}", - block.header().parent_hash() - ) - })?; let (sender_to_main, receiver_from_executor) = mpsc::channel::(self.queue_size); let (sender_to_worker, executor) = DagBlockExecutor::new( sender_to_main, self.queue_size, self.time_service.clone(), - chain_header.id(), + block.header().parent_hash(), self.storage.clone(), self.vm_metrics.clone(), self.dag.clone(), @@ -116,17 +108,18 @@ impl DagBlockSender { sender_to_executor: sender_to_worker.clone(), receiver_from_executor, state: ExecuteState::Ready(block.id()), + handle: executor.start_to_execute()?, }); - executor.start_to_execute()?; sender_to_worker.send(block).await?; self.flush_executor_state().await?; } + self.wait_for_finish().await?; + self.sync_dag_store.delete_all_dag_sync_block()?; - self.wait_for_finish().await?; Ok(()) } @@ -134,12 +127,11 @@ impl DagBlockSender { for worker in &mut self.executors { match worker.receiver_from_executor.try_recv() { Ok(state) => worker.state = state, - Err(e) => { - match e { - mpsc::error::TryRecvError::Empty => continue, - mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, - } - } + Err(_) => (), + } + + if worker.handle.is_finished() { + worker.state = ExecuteState::Closed; } } @@ -150,20 +142,15 @@ impl DagBlockSender { true } }); + info!("sync workers count: {:?}", self.executors.len()); anyhow::Ok(()) } async fn wait_for_finish(&mut self) -> anyhow::Result<()> { loop { for worker in &mut self.executors { - match worker.receiver_from_executor.try_recv() { - Ok(state) => worker.state = state, - Err(e) => { - match e { - mpsc::error::TryRecvError::Empty => continue, - mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, - } - } + if worker.handle.is_finished() { + worker.state = ExecuteState::Closed; } } @@ -173,14 +160,12 @@ impl DagBlockSender { } else { true } - }); - + }); if self.executors.is_empty() { - break; - } + info!("executor is empty, end the parallel execution"); + return anyhow::Ok(()); + } tokio::task::yield_now().await; } - - anyhow::Ok(()) } } From 959995e5e2d9af2700c38f07dc02cbf4c5aeed73 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 03:13:28 +0800 Subject: [PATCH 05/60] set executing state in sender --- sync/src/parallel/executor.rs | 15 --------------- sync/src/parallel/sender.rs | 3 +-- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index 618669846d..e5910d5f46 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -72,21 +72,6 @@ impl DagBlockExecutor { Ok(Some(block)) => { let header = block.header().clone(); - match self - .sender - .send(ExecuteState::Executing(header.id())) - .await - { - Ok(_) => (), - Err(e) => { - error!( - "failed to send executing state: {:?}, for reason: {:?}", - header, e - ); - return; - } - } - loop { match Self::waiting_for_parents( &self.dag, diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index 5c40710b88..f0432a74c9 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -62,7 +62,7 @@ impl DagBlockSender { } } ExecuteState::Executing(header_id) => { - if *header_id == block.header().id() { + if *header_id == block.header().parent_hash() { executor.state = ExecuteState::Executing(block.id()); executor.sender_to_executor.send(block.clone()).await?; return anyhow::Ok(true); @@ -88,7 +88,6 @@ impl DagBlockSender { // Finding the executing state is the priority if self.dispatch_to_worker(&block).await? { - self.flush_executor_state().await?; continue; } From 8e1744a0f743e7274060da4155adb1e3b87de759 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 04:06:46 +0800 Subject: [PATCH 06/60] check the parents when dispatching --- sync/src/parallel/sender.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index f0432a74c9..1466aaf90f 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -54,21 +54,21 @@ impl DagBlockSender { async fn dispatch_to_worker(&mut self, block: &Block) -> anyhow::Result { for executor in &mut self.executors { match &executor.state { - ExecuteState::Executed(executing_header_block) => { - if executing_header_block.id() == block.header().parent_hash() { - executor.state = ExecuteState::Executing(block.id()); - executor.sender_to_executor.send(block.clone()).await?; - return anyhow::Ok(true); - } - } + // ExecuteState::Executed(executing_header_block) => { + // if executing_header_block.id() == block.header().parent_hash() { + // executor.state = ExecuteState::Executing(block.id()); + // executor.sender_to_executor.send(block.clone()).await?; + // return anyhow::Ok(true); + // } + // } ExecuteState::Executing(header_id) => { - if *header_id == block.header().parent_hash() { + if *header_id == block.header().parent_hash() || block.header.parents_hash().contains(header_id) { executor.state = ExecuteState::Executing(block.id()); executor.sender_to_executor.send(block.clone()).await?; return anyhow::Ok(true); } } - ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + ExecuteState::Executed(_) | ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { continue; } } @@ -106,7 +106,7 @@ impl DagBlockSender { self.executors.push(DagBlockWorker { sender_to_executor: sender_to_worker.clone(), receiver_from_executor, - state: ExecuteState::Ready(block.id()), + state: ExecuteState::Executing(block.id()), handle: executor.start_to_execute()?, }); @@ -124,10 +124,10 @@ impl DagBlockSender { async fn flush_executor_state(&mut self) -> anyhow::Result<()> { for worker in &mut self.executors { - match worker.receiver_from_executor.try_recv() { - Ok(state) => worker.state = state, - Err(_) => (), - } + // match worker.receiver_from_executor.try_recv() { + // Ok(state) => worker.state = state, + // Err(_) => (), + // } if worker.handle.is_finished() { worker.state = ExecuteState::Closed; From 03f8b8d331261d73796f0637ec167591faa91b27 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 13:56:02 +0800 Subject: [PATCH 07/60] add 10000 buffer for parallel execution --- sync/src/parallel/executor.rs | 11 +++-- sync/src/parallel/sender.rs | 69 ++++++++++++++++++------------- sync/src/tasks/block_sync_task.rs | 37 +++++++++++------ 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index e5910d5f46..ed95f004e1 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -68,10 +68,11 @@ impl DagBlockExecutor { let handle = tokio::spawn(async move { let mut chain = None; loop { - match timeout(Duration::from_secs(1), self.receiver.recv()).await { - Ok(Some(block)) => { + match self.receiver.recv().await { + Some(block) => { let header = block.header().clone(); + info!("worker will process header {:?}", header); loop { match Self::waiting_for_parents( &self.dag, @@ -168,11 +169,9 @@ impl DagBlockExecutor { } } } - Ok(None) => { + None => { info!("sync worker channel closed"); - return; - } - Err(e) => { + drop(self.sender); return; } } diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index 1466aaf90f..e1211c5561 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -74,10 +74,24 @@ impl DagBlockSender { } } + for executor in &mut self.executors { + match &executor.state { + ExecuteState::Executed(_) => { + executor.state = ExecuteState::Executing(block.id()); + executor.sender_to_executor.send(block.clone()).await?; + return anyhow::Ok(true); + } + + ExecuteState::Executing(_) | ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + continue; + } + } + } + anyhow::Ok(false) } - pub async fn process_absent_blocks(&mut self) -> anyhow::Result<()> { + pub async fn process_absent_blocks(mut self) -> anyhow::Result<()> { let sync_dag_store = self.sync_dag_store.clone(); let iter = sync_dag_store.iter_at_first()?; for result_value in iter { @@ -115,22 +129,30 @@ impl DagBlockSender { self.flush_executor_state().await?; } - self.wait_for_finish().await?; - self.sync_dag_store.delete_all_dag_sync_block()?; + self.wait_for_finish().await?; + Ok(()) } async fn flush_executor_state(&mut self) -> anyhow::Result<()> { for worker in &mut self.executors { - // match worker.receiver_from_executor.try_recv() { - // Ok(state) => worker.state = state, - // Err(_) => (), - // } - - if worker.handle.is_finished() { - worker.state = ExecuteState::Closed; + match worker.receiver_from_executor.try_recv() { + Ok(state) => { + match state { + ExecuteState::Executed(header_id) => { + worker.state = ExecuteState::Executed(header_id); + } + _ => () + } + } + Err(e) => { + match e { + mpsc::error::TryRecvError::Empty => (), + mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + } + } } } @@ -145,26 +167,15 @@ impl DagBlockSender { anyhow::Ok(()) } - async fn wait_for_finish(&mut self) -> anyhow::Result<()> { - loop { - for worker in &mut self.executors { - if worker.handle.is_finished() { - worker.state = ExecuteState::Closed; - } + async fn wait_for_finish(self) -> anyhow::Result<()> { + for mut worker in self.executors { + drop(worker.sender_to_executor); + while let Some(_) = worker.receiver_from_executor.recv().await { + () } - - self.executors.retain(|worker| { - if let ExecuteState::Closed = worker.state { - false - } else { - true - } - }); - if self.executors.is_empty() { - info!("executor is empty, end the parallel execution"); - return anyhow::Ok(()); - } - tokio::task::yield_now().await; + worker.handle.await?; } + + anyhow::Ok(()) } } diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index 2cd6521ab3..5214048b4a 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -32,6 +32,11 @@ use stream_task::{CollectorState, TaskError, TaskResultCollector, TaskState}; use super::continue_execute_absent_block::ContinueChainOperator; use super::{BlockConnectAction, BlockConnectedFinishEvent}; +enum ParallelSign { + NeedMoreBlocks, + Executed, +} + #[derive(Clone, Debug)] pub struct SyncBlockData { pub(crate) block: Block, @@ -426,14 +431,15 @@ where } } - pub fn ensure_dag_parent_blocks_exist(&mut self, block_header: BlockHeader) -> Result<()> { + fn ensure_dag_parent_blocks_exist(&mut self, block: Block) -> Result { + let block_header = &block.header().clone(); if self.chain.has_dag_block(block_header.id())? { info!( "the dag block exists, skipping, its id: {:?}, its number {:?}", block_header.id(), block_header.number() ); - return Ok(()); + return Ok(ParallelSign::NeedMoreBlocks); } info!( "the block is a dag block, its id: {:?}, number: {:?}, its parents: {:?}", @@ -445,13 +451,19 @@ where self.find_absent_ancestor(vec![block_header.clone()]) .await?; - let mut parallel_execute = DagBlockSender::new( - self.sync_dag_store.clone(), - 100, - self.chain.time_service(), - self.local_store.clone(), - None, self.chain.dag()); - parallel_execute.process_absent_blocks().await?; + if block_header.number() % 10000 == 0 || block_header.number() >= self.target.target_id.number() { + let parallel_execute = DagBlockSender::new( + self.sync_dag_store.clone(), + 100000, + self.chain.time_service(), + self.local_store.clone(), + None, self.chain.dag()); + parallel_execute.process_absent_blocks().await?; + anyhow::Ok(ParallelSign::Executed) + } else { + self.sync_dag_store.save_block(block)?; + anyhow::Ok(ParallelSign::NeedMoreBlocks) + } // let sync_dag_store = self.sync_dag_store.clone(); // let mut absent_block_iter = sync_dag_store @@ -476,8 +488,6 @@ where // } // } // } - - Ok(()) }; async_std::task::block_on(fut) } @@ -606,7 +616,10 @@ where // if it is a dag block, we must ensure that its dag parent blocks exist. // if it is not, we must pull the dag parent blocks from the peer. info!("now sync dag block -- ensure_dag_parent_blocks_exist"); - self.ensure_dag_parent_blocks_exist(block.header().clone())?; + match self.ensure_dag_parent_blocks_exist(block.clone())? { + ParallelSign::NeedMoreBlocks => return Ok(CollectorState::Need), + ParallelSign::Executed => (), + } let state = self.check_enough(); if let anyhow::Result::Ok(CollectorState::Enough) = &state { if self.chain.has_dag_block(block.header().id())? { From b9e34d00c788046b1c3e5a461e1feb6e2795eb32 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 14:23:32 +0800 Subject: [PATCH 08/60] save the block in local store to buffer the block --- sync/src/tasks/block_sync_task.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index 5214048b4a..1bafe6d97d 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -461,6 +461,10 @@ where parallel_execute.process_absent_blocks().await?; anyhow::Ok(ParallelSign::Executed) } else { + self.local_store.save_dag_sync_block(starcoin_storage::block::DagSyncBlock { + block: block.clone(), + children: vec![], + })?; self.sync_dag_store.save_block(block)?; anyhow::Ok(ParallelSign::NeedMoreBlocks) } From 689a478db73a3a6be6d53294de8d33a319b748b2 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 15:32:06 +0800 Subject: [PATCH 09/60] add log for saving time --- sync/src/tasks/block_sync_task.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index 1bafe6d97d..0c42de0997 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -461,11 +461,13 @@ where parallel_execute.process_absent_blocks().await?; anyhow::Ok(ParallelSign::Executed) } else { + info!("now save the dag block in order"); self.local_store.save_dag_sync_block(starcoin_storage::block::DagSyncBlock { block: block.clone(), children: vec![], })?; self.sync_dag_store.save_block(block)?; + info!("finish saving"); anyhow::Ok(ParallelSign::NeedMoreBlocks) } From b086d1373d5bf5ebc1ab30dd9ac996d59355737d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 29 Aug 2024 16:51:54 +0800 Subject: [PATCH 10/60] check local store for the absent block --- sync/src/tasks/block_sync_task.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index 0c42de0997..b4647e59fd 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -399,10 +399,13 @@ where return Ok(()); } for parent in parents { - if !self.chain.has_dag_block(parent)? { + if self.local_store.get_dag_sync_block(parent)?.is_none() { if absent_blocks.contains(&parent) { continue; } + if self.chain.has_dag_block(parent)? { + continue; + } absent_blocks.push(parent) } } From 1fa8f942ea3df701e324b8093283c886544955b6 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Mon, 2 Sep 2024 11:34:21 +0800 Subject: [PATCH 11/60] add test case --- flexidag/tests/tests.rs | 107 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 6483bfe933..8491f5ac1a 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -947,5 +947,112 @@ fn test_prune() -> anyhow::Result<()> { assert_eq!(tips.len(), 1); assert_eq!(*tips.last().unwrap(), block_main_5.id()); + anyhow::Result::Ok(()) +} + +#[test] +fn test_verification_blue_block() -> anyhow::Result<()> { + // initialzie the dag firstly + let k = 5; + + let mut dag = BlockDAG::create_for_testing_with_parameters(k).unwrap(); + + let origin = BlockHeaderBuilder::random().with_number(0).build(); + let genesis = BlockHeader::dag_genesis_random_with_parent(origin)?; + + dag.init_with_genesis(genesis.clone()).unwrap(); + + let block1 = add_and_print( + 1, + genesis.id(), + vec![genesis.id()], + genesis.parent_hash(), + &mut dag, + )?; + + let block_main_2 = add_and_print( + 2, + block1.id(), + vec![block1.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_main_3 = add_and_print( + 3, + block_main_2.id(), + vec![block_main_2.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_main_3_1 = add_and_print( + 3, + block_main_2.id(), + vec![block_main_2.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_main_4 = add_and_print( + 4, + block_main_3.id(), + vec![block_main_3.id(), block_main_3_1.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_main_5 = add_and_print( + 5, + block_main_4.id(), + vec![block_main_4.id()], + genesis.parent_hash(), + &mut dag, + )?; + + let block_red_2 = add_and_print( + 2, + block1.id(), + vec![block1.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_red_2_1 = add_and_print( + 2, + block1.id(), + vec![block1.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_red_3 = add_and_print( + 3, + block_red_2.id(), + vec![block_red_2.id(), block_red_2_1.id()], + genesis.parent_hash(), + &mut dag, + )?; + // let block_red_4 = add_and_print( + // 4, + // block_red_3.id(), + // vec![block_red_3.id()], + // genesis.parent_hash(), + // &mut dag, + // )?; + + // let's obser the blue scores which show how blue the tips are + let observer1 = dag.ghostdata(&[block_red_3.id()])?; + println!("observer 1 data: {:?}, ", observer1); + + let observer2 = dag.ghostdata(&[block_red_3.id(), block_main_5.id()])?; + println!("observer 2 dag data: {:?}, ", observer2); + + let observer3 = dag.ghostdata(&[block_main_5.id()])?; + println!("observer 3 dag data: {:?}, ", observer3); + + // assert!(observer1.blue_score < observer2.blue_score); + // assert!(observer1.selected_parent != observer2.selected_parent); + + // assert_eq!(observer3.blue_score, observer2.blue_score); + // assert_eq!(observer3.selected_parent, observer2.selected_parent); + + + + anyhow::Result::Ok(()) } From 4f26278927585d4fe13f2a70a2ec441d0ebe775d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Mon, 2 Sep 2024 11:59:21 +0800 Subject: [PATCH 12/60] add some fix --- sync/src/parallel/executor.rs | 10 +++++----- sync/src/parallel/sender.rs | 14 +++----------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index ed95f004e1..ed4c9480d7 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use starcoin_chain::{verifier::DagVerifier, BlockChain, ChainReader}; +use starcoin_chain_api::ExecutedBlock; use starcoin_config::TimeService; use starcoin_crypto::HashValue; use starcoin_dag::blockdag::BlockDAG; @@ -16,7 +17,7 @@ use tokio::{ pub enum ExecuteState { Ready(HashValue), Executing(HashValue), - Executed(BlockHeader), + Executed(ExecutedBlock), Error(BlockHeader), Closed, } @@ -129,15 +130,14 @@ impl DagBlockExecutor { info!("sync parallel worker {:p} will execute block: {:?}", &self, block.header().id()); match chain.as_mut().expect("it cannot be none!").apply_with_verifier::(block) { Ok(executed_block) => { - let header = executed_block.header(); info!( "succeed to execute block: number: {:?}, id: {:?}", - header.number(), - header.id() + executed_block.header().number(), + executed_block.header().id() ); match self .sender - .send(ExecuteState::Executed(header.clone())) + .send(ExecuteState::Executed(executed_block)) .await { Ok(_) => (), diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index e1211c5561..a98715e421 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -54,13 +54,6 @@ impl DagBlockSender { async fn dispatch_to_worker(&mut self, block: &Block) -> anyhow::Result { for executor in &mut self.executors { match &executor.state { - // ExecuteState::Executed(executing_header_block) => { - // if executing_header_block.id() == block.header().parent_hash() { - // executor.state = ExecuteState::Executing(block.id()); - // executor.sender_to_executor.send(block.clone()).await?; - // return anyhow::Ok(true); - // } - // } ExecuteState::Executing(header_id) => { if *header_id == block.header().parent_hash() || block.header.parents_hash().contains(header_id) { executor.state = ExecuteState::Executing(block.id()); @@ -129,8 +122,6 @@ impl DagBlockSender { self.flush_executor_state().await?; } - self.sync_dag_store.delete_all_dag_sync_block()?; - self.wait_for_finish().await?; Ok(()) @@ -141,8 +132,9 @@ impl DagBlockSender { match worker.receiver_from_executor.try_recv() { Ok(state) => { match state { - ExecuteState::Executed(header_id) => { - worker.state = ExecuteState::Executed(header_id); + ExecuteState::Executed(executed_block) => { + self.sync_dag_store.delete_dag_sync_block(executed_block.block().header().number(), executed_block.header().id())?; + worker.state = ExecuteState::Executed(executed_block); } _ => () } From cb4abfed35fe0f31a557a909e417be439a9dbbc7 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Mon, 2 Sep 2024 15:44:30 +0800 Subject: [PATCH 13/60] add some test --- flexidag/src/blockdag.rs | 127 +++++++++++++++++++++++++++++- flexidag/src/ghostdag/protocol.rs | 22 ++++++ flexidag/src/types/ghostdata.rs | 2 +- flexidag/tests/tests.rs | 65 +++++++++++---- 4 files changed, 200 insertions(+), 16 deletions(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 6f3fc81254..cd6716b82d 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -12,8 +12,9 @@ use crate::consensusdb::{ }; use crate::ghostdag::protocol::GhostdagManager; use crate::prune::pruning_point_manager::PruningPointManagerT; +use crate::types::ghostdata::CompactGhostdagData; use crate::{process_key_already_error, reachability}; -use anyhow::{bail, format_err, Ok}; +use anyhow::{bail, ensure, format_err, Ok}; use starcoin_accumulator::node::AccumulatorStoreType; use starcoin_accumulator::{Accumulator, MerkleAccumulator}; use starcoin_config::temp_dir; @@ -25,6 +26,8 @@ use starcoin_types::{ blockhash::{BlockHashes, KType}, consensus_header::ConsensusHeader, }; +use std::char::EscapeUnicode; +use std::collections::HashSet; use std::ops::DerefMut; use std::sync::Arc; @@ -142,6 +145,128 @@ impl BlockDAG { Ok(()) } + pub fn commit_trusted_block(&mut self, header: BlockHeader, origin: HashValue, trusted_ghostdata: Arc) -> anyhow::Result<()> { + info!( + "start to commit header: {:?}, number: {:?}", + header.id(), + header.number() + ); + // Generate ghostdag data + let parents = header.parents(); + + debug!( + "start to get the ghost data from block: {:?}, number: {:?}", + header.id(), + header.number() + ); + let ghostdata = match self.ghostdata_by_hash(header.id())? { + None => { + // It must be the dag genesis if header is a format for a single chain + if header.is_genesis() { + Arc::new(self.ghostdag_manager.genesis_ghostdag_data(&header)) + } else { + self.storage.ghost_dag_store.insert(header.id(), trusted_ghostdata.clone())?; + trusted_ghostdata + } + } + Some(ghostdata) => { + ensure!(ghostdata.blue_score == trusted_ghostdata.blue_score, "blue score is not same"); + ensure!(ghostdata.blue_work == trusted_ghostdata.blue_work, "blue work is not same"); + ensure!(ghostdata.mergeset_blues.len() == trusted_ghostdata.mergeset_blues.len(), "blue len is not same"); + ensure!(ghostdata.mergeset_blues.iter().cloned().collect::>() == trusted_ghostdata.mergeset_blues.iter().cloned().collect::>(), "blue values are not same"); + trusted_ghostdata + } + }; + // Store ghostdata + process_key_already_error( + self.storage + .ghost_dag_store + .insert(header.id(), ghostdata.clone()), + )?; + + // Update reachability store + debug!( + "start to update reachability data for block: {:?}, number: {:?}", + header.id(), + header.number() + ); + let reachability_store = self.storage.reachability_store.clone(); + + let mut merge_set = ghostdata + .unordered_mergeset_without_selected_parent() + .filter(|hash| self.storage.reachability_store.read().has(*hash).unwrap()) + .collect::>() + .into_iter(); + let add_block_result = { + let mut reachability_writer = reachability_store.write(); + inquirer::add_block( + reachability_writer.deref_mut(), + header.id(), + ghostdata.selected_parent, + &mut merge_set, + ) + }; + match add_block_result { + Result::Ok(_) => (), + Err(reachability::ReachabilityError::DataInconsistency) => { + let _future_covering_set = reachability_store + .read() + .get_future_covering_set(header.id())?; + info!( + "the key {:?} was already processed, original error message: {:?}", + header.id(), + reachability::ReachabilityError::DataInconsistency + ); + } + Err(reachability::ReachabilityError::StoreError(StoreError::KeyNotFound(msg))) => { + if msg == *REINDEX_ROOT_KEY.to_string() { + info!( + "the key {:?} was already processed, original error message: {:?}", + header.id(), + reachability::ReachabilityError::StoreError(StoreError::KeyNotFound( + REINDEX_ROOT_KEY.to_string() + )) + ); + info!("now set the reindex key to origin: {:?}", origin); + // self.storage.reachability_store.set_reindex_root(origin)?; + self.set_reindex_root(origin)?; + bail!( + "failed to add a block when committing, e: {:?}", + reachability::ReachabilityError::StoreError(StoreError::KeyNotFound(msg)) + ); + } else { + bail!( + "failed to add a block when committing, e: {:?}", + reachability::ReachabilityError::StoreError(StoreError::KeyNotFound(msg)) + ); + } + } + Err(reachability::ReachabilityError::StoreError(StoreError::InvalidInterval(_, _))) => { + self.set_reindex_root(origin)?; + bail!("failed to add a block when committing for invalid interval",); + } + Err(e) => { + bail!("failed to add a block when committing, e: {:?}", e); + } + } + + process_key_already_error( + self.storage + .relations_store + .write() + .insert(header.id(), BlockHashes::new(parents)), + )?; + // Store header store + process_key_already_error(self.storage.header_store.insert( + header.id(), + Arc::new(header), + 1, + ))?; + Ok(()) + } + + + pub fn commit(&mut self, header: BlockHeader, origin: HashValue) -> anyhow::Result<()> { info!( "start to commit header: {:?}, number: {:?}", diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 18cce2ea81..3a2d92d7b5 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -8,6 +8,7 @@ use starcoin_crypto::HashValue as Hash; use starcoin_logger::prelude::*; use starcoin_types::block::BlockHeader; use starcoin_types::blockhash::{BlockHashMap, BlockHashes, BlueWorkType, HashKTypeMap, KType}; +use std::collections::HashSet; use std::sync::Arc; #[derive(Clone)] @@ -170,6 +171,27 @@ impl< Ok(new_block_data) } + pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { + let mut new_block_data = GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); + for blue_candidate in ghostdata.mergeset_blues.iter().skip(1).cloned() { + let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; + if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { + new_block_data.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); + } else { + new_block_data.add_red(blue_candidate); + } + } + println!("jacktest: new_block_data: {:?}", new_block_data); + println!("jacktest: ghostdata: {:?}", ghostdata); + if ghostdata.mergeset_blues.len() != new_block_data.mergeset_blues.len() { + return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, {}", ghostdata.mergeset_blues.len(), new_block_data.mergeset_blues.len())); + } + if ghostdata.mergeset_blues.iter().cloned().collect::>() != new_block_data.mergeset_blues.iter().cloned().collect::>() { + return Err(anyhow::anyhow!("The blue set is not equal")); + } + Ok(()) + } + fn check_blue_candidate_with_chain_block( &self, new_block_data: &GhostdagData, diff --git a/flexidag/src/types/ghostdata.rs b/flexidag/src/types/ghostdata.rs index 83a51280bb..80ba6c6523 100644 --- a/flexidag/src/types/ghostdata.rs +++ b/flexidag/src/types/ghostdata.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use starcoin_crypto::HashValue as Hash; use starcoin_types::blockhash::{BlockHashMap, BlockHashes, BlueWorkType, HashKTypeMap, KType}; -#[derive(Clone, Serialize, Deserialize, Default, Debug, JsonSchema)] +#[derive(Clone, Serialize, Deserialize, Default, Debug, JsonSchema, PartialEq, Eq)] pub struct GhostdagData { pub blue_score: u64, #[schemars(with = "String")] diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 8491f5ac1a..e468dcebc2 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -4,19 +4,16 @@ use anyhow::{bail, format_err, Ok, Result}; use starcoin_crypto::HashValue as Hash; use starcoin_dag::{ - blockdag::{BlockDAG, MineNewDagBlockInfo}, - consensusdb::{ + blockdag::{BlockDAG, MineNewDagBlockInfo}, consensusdb::{ consenses_state::{DagState, DagStateReader, DagStateStore}, schemadb::{ DbReachabilityStore, ReachabilityStore, ReachabilityStoreReader, RelationsStore, RelationsStoreReader, }, - }, - reachability::{inquirer, ReachabilityError}, - types::interval::Interval, + }, ghostdag, reachability::{inquirer, ReachabilityError}, types::{ghostdata::GhostdagData, interval::Interval} }; use starcoin_logger::prelude::debug; -use starcoin_types::block::{BlockHeader, BlockHeaderBuilder, BlockNumber}; +use starcoin_types::{block::{BlockHeader, BlockHeaderBuilder, BlockNumber}, blockhash::{BlockHashMap, HashKTypeMap, KType}}; use std::{ ops::{Deref, DerefMut}, @@ -702,6 +699,37 @@ fn test_reachability_algorithm() -> anyhow::Result<()> { Ok(()) } +fn add_and_print_with_ghostdata( + number: BlockNumber, + parent: Hash, + parents: Vec, + origin: Hash, + dag: &mut BlockDAG, + ghostdata: GhostdagData, +) -> anyhow::Result { + let header_builder = BlockHeaderBuilder::random(); + let header = header_builder + .with_parent_hash(parent) + .with_parents_hash(parents) + .with_number(number) + .build(); + let start = Instant::now(); + dag.commit_trusted_block(header.to_owned(), origin, Arc::new(ghostdata))?; + let duration = start.elapsed(); + println!( + "commit header: {:?}, number: {:?}, duration: {:?}", + header.id(), + header.number(), + duration + ); + let _ghostdata = dag.ghostdata(&[header.id()])?; + // println!( + // "add a header: {:?}, blue set: {:?}, red set: {:?}, blue anticone size: {:?}", + // header, ghostdata.mergeset_blues, ghostdata.mergeset_reds, ghostdata.blues_anticone_sizes + // ); + Ok(header) +} + fn add_and_print( number: BlockNumber, parent: Hash, @@ -1027,13 +1055,7 @@ fn test_verification_blue_block() -> anyhow::Result<()> { genesis.parent_hash(), &mut dag, )?; - // let block_red_4 = add_and_print( - // 4, - // block_red_3.id(), - // vec![block_red_3.id()], - // genesis.parent_hash(), - // &mut dag, - // )?; + // let's obser the blue scores which show how blue the tips are let observer1 = dag.ghostdata(&[block_red_3.id()])?; @@ -1051,8 +1073,23 @@ fn test_verification_blue_block() -> anyhow::Result<()> { // assert_eq!(observer3.blue_score, observer2.blue_score); // assert_eq!(observer3.selected_parent, observer2.selected_parent); - + let normal_block = add_and_print(6, block_main_5.id(), vec![block_main_5.id(), block_red_3.id()], genesis.parent_hash(), &mut dag)?; + assert_eq!(observer2, dag.ghostdata_by_hash(normal_block.id())?.expect("the data cannot be none").as_ref().clone()); + + let makeup_ghostdata = GhostdagData::new(observer2.blue_score, observer2.blue_work, observer2.selected_parent, observer2.mergeset_blues.clone(), Arc::new(vec![]), HashKTypeMap::new(BlockHashMap::::new())); + dag.ghost_dag_manager().check_ghostdata_blue_block(&makeup_ghostdata)?; + let makeup_block = add_and_print_with_ghostdata(6, block_main_5.id(), vec![block_main_5.id(), block_red_3.id()], genesis.parent_hash(), &mut dag, makeup_ghostdata.clone())?; + + let block_from_normal = add_and_print(7, normal_block.id(), vec![normal_block.id()], genesis.parent_hash(), &mut dag)?; + let block_from_makeup = add_and_print(7, makeup_block.id(), vec![makeup_block.id()], genesis.parent_hash(), &mut dag)?; + + let ghostdag_data_from_normal = dag.ghostdata_by_hash(block_from_normal.id())?.expect("the data cannot be none").as_ref().clone(); + let ghostdag_data_from_makeup = dag.ghostdata_by_hash(block_from_makeup.id())?.expect("the data cannot be none").as_ref().clone(); + + println!("normal: {:?}", ghostdag_data_from_normal); + println!("makeup: {:?}", ghostdag_data_from_makeup); + dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_makeup)?; anyhow::Result::Ok(()) } From bcac3fad1efacc9e699525b89efdbdbdc3d4f4eb Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Mon, 2 Sep 2024 16:26:08 +0800 Subject: [PATCH 14/60] add false testing case --- flexidag/tests/tests.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index e468dcebc2..9fc89dc5bf 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -16,10 +16,7 @@ use starcoin_logger::prelude::debug; use starcoin_types::{block::{BlockHeader, BlockHeaderBuilder, BlockNumber}, blockhash::{BlockHashMap, HashKTypeMap, KType}}; use std::{ - ops::{Deref, DerefMut}, - sync::Arc, - time::Instant, - vec, + io::Read, ops::{Deref, DerefMut}, sync::Arc, time::Instant, vec }; #[test] @@ -1064,6 +1061,21 @@ fn test_verification_blue_block() -> anyhow::Result<()> { let observer2 = dag.ghostdata(&[block_red_3.id(), block_main_5.id()])?; println!("observer 2 dag data: {:?}, ", observer2); + let mut false_observer2 = observer2.clone(); + let red_block_id = false_observer2.mergeset_reds.first().expect("the k is wrong, modify it to create a red block!").clone(); + if red_block_id == block_red_2.id() { + false_observer2.mergeset_blues = Arc::new(vec![red_block_id].into_iter().chain(false_observer2.mergeset_blues.iter().cloned().filter(|id| { + *id != block_red_2_1.id() + })).collect()); + false_observer2.mergeset_reds = Arc::new(vec![block_red_2_1.id()]); + } else { + false_observer2.mergeset_blues = Arc::new(vec![red_block_id].into_iter().chain(false_observer2.mergeset_blues.iter().cloned().filter(|id| { + *id != block_red_2.id() + })).collect()); + false_observer2.mergeset_reds = Arc::new(vec![block_red_2.id()]); + } + assert!(dag.ghost_dag_manager().check_ghostdata_blue_block(&false_observer2).is_err()); + let observer3 = dag.ghostdata(&[block_main_5.id()])?; println!("observer 3 dag data: {:?}, ", observer3); From ccfe95d56898f22996e388081f90d8efdc6ff7c2 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Mon, 2 Sep 2024 16:52:38 +0800 Subject: [PATCH 15/60] add more testing code --- flexidag/tests/tests.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 9fc89dc5bf..2acf9f457c 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -7,8 +7,7 @@ use starcoin_dag::{ blockdag::{BlockDAG, MineNewDagBlockInfo}, consensusdb::{ consenses_state::{DagState, DagStateReader, DagStateStore}, schemadb::{ - DbReachabilityStore, ReachabilityStore, ReachabilityStoreReader, RelationsStore, - RelationsStoreReader, + DbReachabilityStore, GhostdagStoreReader, ReachabilityStore, ReachabilityStoreReader, RelationsStore, RelationsStoreReader }, }, ghostdag, reachability::{inquirer, ReachabilityError}, types::{ghostdata::GhostdagData, interval::Interval} }; @@ -1060,6 +1059,7 @@ fn test_verification_blue_block() -> anyhow::Result<()> { let observer2 = dag.ghostdata(&[block_red_3.id(), block_main_5.id()])?; println!("observer 2 dag data: {:?}, ", observer2); + assert!(dag.ghost_dag_manager().check_ghostdata_blue_block(&observer2).is_ok()); let mut false_observer2 = observer2.clone(); let red_block_id = false_observer2.mergeset_reds.first().expect("the k is wrong, modify it to create a red block!").clone(); @@ -1074,7 +1074,10 @@ fn test_verification_blue_block() -> anyhow::Result<()> { })).collect()); false_observer2.mergeset_reds = Arc::new(vec![block_red_2.id()]); } - assert!(dag.ghost_dag_manager().check_ghostdata_blue_block(&false_observer2).is_err()); + + let check_error = dag.ghost_dag_manager().check_ghostdata_blue_block(&false_observer2); + println!("check error: {:?} after the blue block turns red and the red turns blue maliciously", check_error); + assert!(check_error.is_err()); let observer3 = dag.ghostdata(&[block_main_5.id()])?; println!("observer 3 dag data: {:?}, ", observer3); @@ -1103,5 +1106,11 @@ fn test_verification_blue_block() -> anyhow::Result<()> { dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_makeup)?; + + let together_mine = dag.ghostdata(&[block_from_normal.id(), block_from_makeup.id()])?; + let mine_together = add_and_print(8, together_mine.selected_parent, vec![block_from_normal.id(), block_from_makeup.id()], genesis.parent_hash(), &mut dag)?; + let together_ghost_data = dag.storage.ghost_dag_store.get_data(mine_together.id())?; + dag.ghost_dag_manager().check_ghostdata_blue_block(&together_ghost_data)?; + anyhow::Result::Ok(()) } From 4e50d66ab62b56fbde45397a499a0ca387a89d78 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 3 Sep 2024 10:12:27 +0800 Subject: [PATCH 16/60] add check data --- flexidag/src/ghostdag/protocol.rs | 49 ++++++++++++++++++++++++------- flexidag/src/types/ghostdata.rs | 2 +- flexidag/tests/tests.rs | 3 +- sync/src/store/tests.rs | 39 ------------------------ 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 3a2d92d7b5..9993fa8ac2 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -2,7 +2,7 @@ use super::util::Refs; use crate::consensusdb::schemadb::{GhostdagStoreReader, HeaderStoreReader, RelationsStoreReader}; use crate::reachability::reachability_service::ReachabilityService; use crate::types::{ghostdata::GhostdagData, ordering::*}; -use anyhow::{Context, Result}; +use anyhow::{ensure, Context, Result}; use parking_lot::RwLock; use starcoin_crypto::HashValue as Hash; use starcoin_logger::prelude::*; @@ -172,23 +172,52 @@ impl< } pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { - let mut new_block_data = GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); + let mut check_ghostdata = GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); for blue_candidate in ghostdata.mergeset_blues.iter().skip(1).cloned() { - let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; + let coloring = self.check_blue_candidate(&check_ghostdata, blue_candidate)?; if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { - new_block_data.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); + check_ghostdata.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); } else { - new_block_data.add_red(blue_candidate); + check_ghostdata.add_red(blue_candidate); } } - println!("jacktest: new_block_data: {:?}", new_block_data); - println!("jacktest: ghostdata: {:?}", ghostdata); - if ghostdata.mergeset_blues.len() != new_block_data.mergeset_blues.len() { - return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, {}", ghostdata.mergeset_blues.len(), new_block_data.mergeset_blues.len())); + if ghostdata.mergeset_blues.len() != check_ghostdata.mergeset_blues.len() { + return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, checking data: {}", ghostdata.mergeset_blues.len(), check_ghostdata.mergeset_blues.len())); } - if ghostdata.mergeset_blues.iter().cloned().collect::>() != new_block_data.mergeset_blues.iter().cloned().collect::>() { + if ghostdata.mergeset_blues.iter().cloned().collect::>() != check_ghostdata.mergeset_blues.iter().cloned().collect::>() { return Err(anyhow::anyhow!("The blue set is not equal")); } + + let blue_score = self + .ghostdag_store + .get_blue_score(ghostdata.selected_parent)? + .checked_add(check_ghostdata.mergeset_blues.len() as u64) + .expect("blue score size should less than u64"); + + let added_blue_work: BlueWorkType = check_ghostdata + .mergeset_blues + .iter() + .cloned() + .map(|hash| { + self.headers_store + .get_difficulty(hash) + .unwrap_or_else(|err| { + error!("Failed to get difficulty of block: {}, {}", hash, err); + 0.into() + }) + }) + .sum(); + + let blue_work = self + .ghostdag_store + .get_blue_work(ghostdata.selected_parent)? + .checked_add(added_blue_work) + .expect("blue work should less than u256"); + + check_ghostdata.finalize_score_and_work(blue_score, blue_work); + + ensure!(check_ghostdata.to_compact() == ghostdata.to_compact(), "check_ghostdata: {:?} is not the same as ghostdata: {:?}", check_ghostdata.to_compact(), ghostdata.to_compact()); + Ok(()) } diff --git a/flexidag/src/types/ghostdata.rs b/flexidag/src/types/ghostdata.rs index 80ba6c6523..5de610d7b9 100644 --- a/flexidag/src/types/ghostdata.rs +++ b/flexidag/src/types/ghostdata.rs @@ -14,7 +14,7 @@ pub struct GhostdagData { pub blues_anticone_sizes: HashKTypeMap, } -#[derive(Clone, Debug, Default, Serialize, Deserialize, Copy)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, Copy, PartialEq, Eq)] pub struct CompactGhostdagData { pub blue_score: u64, pub blue_work: BlueWorkType, diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 2acf9f457c..00561ef00a 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -1103,10 +1103,11 @@ fn test_verification_blue_block() -> anyhow::Result<()> { println!("normal: {:?}", ghostdag_data_from_normal); println!("makeup: {:?}", ghostdag_data_from_makeup); + assert_eq!(ghostdag_data_from_makeup.blue_score, ghostdag_data_from_normal.blue_score); + dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_normal)?; dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_makeup)?; - let together_mine = dag.ghostdata(&[block_from_normal.id(), block_from_makeup.id()])?; let mine_together = add_and_print(8, together_mine.selected_parent, vec![block_from_normal.id(), block_from_makeup.id()], genesis.parent_hash(), &mut dag)?; let together_ghost_data = dag.storage.ghost_dag_store.get_data(mine_together.id())?; diff --git a/sync/src/store/tests.rs b/sync/src/store/tests.rs index 618116d81e..1b6901c4a0 100644 --- a/sync/src/store/tests.rs +++ b/sync/src/store/tests.rs @@ -78,45 +78,6 @@ fn build_version_0_block(number: BlockNumber) -> Block { Block::new(header, body) } -#[test] -fn test_add_reachability_data() -> anyhow::Result<()> { - let mut sync_dag_store = SyncDagStore::create_for_testing()?; - let reachability_store = sync_dag_store.reachability_store.clone(); - - let mut writer = reachability_store.write(); - - let x = HashValue::random(); - let a = HashValue::random(); - let b = HashValue::random(); - let c = HashValue::random(); - let d = HashValue::random(); - let e = HashValue::random(); - - inquirer::init_with_params(writer.deref_mut(), x, Interval::maximal())?; - - inquirer::add_block(writer.deref_mut(), a, x, &mut [x].into_iter())?; - inquirer::add_block(writer.deref_mut(), b, a, &mut [a].into_iter())?; - inquirer::add_block(writer.deref_mut(), c, a, &mut [a].into_iter())?; - inquirer::add_block(writer.deref_mut(), d, a, &mut [a].into_iter())?; - inquirer::add_block(writer.deref_mut(), e, b, &mut [c, d].into_iter())?; - - drop(writer); - - let reader = reachability_store.read(); - - assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, b)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, c)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, d)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), a, e)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), b, e)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), c, e)?); - assert!(inquirer::is_dag_ancestor_of(reader.deref(), d, e)?); - - drop(reader); - - anyhow::Ok(()) -} - #[test] fn test_sync_dag_absent_store() -> anyhow::Result<()> { let dag = BlockDAG::create_for_testing()?; From 30ecb996292b266cb3afe09124d3f42b68b80c73 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 3 Sep 2024 15:39:00 +0800 Subject: [PATCH 17/60] add verify blue block in verifier --- chain/api/src/chain.rs | 7 +- chain/src/chain.rs | 13 ++-- chain/src/verifier/mod.rs | 108 ++++++++++++++++-------------- flexidag/src/blockdag.rs | 4 ++ flexidag/src/ghostdag/protocol.rs | 57 ++++++++++++++++ 5 files changed, 134 insertions(+), 55 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index b2be6ca7b1..9d8452283a 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -3,6 +3,7 @@ use anyhow::Result; use starcoin_crypto::HashValue; +use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_state_api::ChainStateReader; use starcoin_statedb::ChainStateDB; use starcoin_time_service::TimeService; @@ -22,7 +23,10 @@ pub use starcoin_types::block::ExecutedBlock; use starcoin_vm_types::access_path::AccessPath; use starcoin_vm_types::contract_event::ContractEvent; -pub struct VerifiedBlock(pub Block); +pub struct VerifiedBlock { + pub block: Block, + pub ghostdata: Option, +} pub type MintedUncleNumber = u64; pub trait ChainReader { @@ -105,6 +109,7 @@ pub trait ChainReader { fn current_tips_hash(&self) -> Result>; fn has_dag_block(&self, header_id: HashValue) -> Result; fn check_chain_type(&self) -> Result; + fn verify_and_ghostdata(&self, uncles: &[BlockHeader], header: &BlockHeader) -> Result; } pub trait ChainWriter { diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 59771a653e..e1c00ff88d 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -458,8 +458,8 @@ impl BlockChain { } fn execute_dag_block(&mut self, verified_block: VerifiedBlock) -> Result { - info!("execute dag block:{:?}", verified_block.0); - let block = verified_block.0; + info!("execute dag block:{:?}", verified_block.block); + let block = verified_block.block; let selected_parent = block.parent_hash(); let block_info_past = self .storage @@ -1210,8 +1210,7 @@ impl ChainReader for BlockChain { } fn verify(&self, block: Block) -> Result { - DagVerifier::verify_header(self, block.header())?; - Ok(VerifiedBlock(block)) + DagVerifier::verify_block(self, block) } fn execute(&mut self, verified_block: VerifiedBlock) -> Result { @@ -1225,7 +1224,7 @@ impl ChainReader for BlockChain { self.block_accumulator.fork(None), &self.epoch, Some(self.status.status.clone()), - verified_block.0, + verified_block.block, self.vm_metrics.clone(), ) } @@ -1348,6 +1347,10 @@ impl ChainReader for BlockChain { fn check_chain_type(&self) -> Result { Ok(ChainType::Dag) } + + fn verify_and_ghostdata(&self, uncles: &[BlockHeader], header: &BlockHeader) -> Result { + self.dag().verify_and_ghostdata(uncles, header) + } } impl BlockChain { diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index 8fb03a8ea0..d8bb8234cf 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -7,6 +7,7 @@ use starcoin_chain_api::{ verify_block, ChainReader, ConnectBlockError, VerifiedBlock, VerifyBlockField, }; use starcoin_consensus::{Consensus, ConsensusVerifyError}; +use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_logger::prelude::debug; use starcoin_open_block::AddressFilter; use starcoin_types::block::{Block, BlockHeader, ALLOWED_FUTURE_BLOCKTIME}; @@ -76,13 +77,16 @@ pub trait BlockVerifier { StaticVerifier::verify_body_hash(&new_block)?; watch(CHAIN_WATCH_NAME, "n13"); //verify uncles - Self::verify_uncles( + let ghostdata = Self::verify_uncles( current_chain, new_block.uncles().unwrap_or_default(), new_block_header, )?; watch(CHAIN_WATCH_NAME, "n14"); - Ok(VerifiedBlock(new_block)) + Ok(VerifiedBlock{ + block: new_block, + ghostdata: None, + }) } fn verify_blacklisted_txns(new_block: &Block) -> Result<()> { @@ -101,7 +105,7 @@ pub trait BlockVerifier { current_chain: &R, uncles: &[BlockHeader], header: &BlockHeader, - ) -> Result<()> + ) -> Result> where R: ChainReader, { @@ -118,7 +122,7 @@ pub trait BlockVerifier { } if uncles.is_empty() { - return Ok(()); + return Ok(None); } verify_block!( VerifyBlockField::Uncle, @@ -163,7 +167,7 @@ pub trait BlockVerifier { Self::verify_header(&uncle_branch, uncle)?; uncle_ids.insert(uncle_id); } - Ok(()) + Ok(None) } fn can_be_uncle(current_chain: &R, block_header: &BlockHeader) -> Result @@ -318,25 +322,28 @@ impl BlockVerifier for NoneVerifier { where R: ChainReader, { - Ok(VerifiedBlock(new_block)) + Ok(VerifiedBlock{ + block: new_block, + ghostdata: None, + }) } fn verify_uncles( _current_chain: &R, _uncles: &[BlockHeader], _header: &BlockHeader, - ) -> Result<()> + ) -> Result> where R: ChainReader, { - Ok(()) + Ok(None) } } -//TODO: Implement it. -pub struct DagVerifier; -impl BlockVerifier for DagVerifier { - fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> + +struct BasicDagVerifier; +impl BasicDagVerifier { + pub fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> where R: ChainReader, { @@ -379,51 +386,54 @@ impl BlockVerifier for DagVerifier { ConsensusVerifier::verify_header(current_chain, new_block_header) } + + fn verify_blue_blocks(current_chain: &R, uncles: &[BlockHeader], header: &BlockHeader) -> Result where R: ChainReader { + current_chain.verify_and_ghostdata(uncles, header) + } + + + +} +//TODO: Implement it. +pub struct DagVerifier; +impl BlockVerifier for DagVerifier { + fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> + where + R: ChainReader, + { + BasicDagVerifier::verify_header(current_chain, new_block_header) + } fn verify_uncles( _current_chain: &R, _uncles: &[BlockHeader], _header: &BlockHeader, - ) -> Result<()> + ) -> Result> where R: ChainReader, { - // let mut uncle_ids = HashSet::new(); - // for uncle in uncles { - // let uncle_id = uncle.id(); - // verify_block!( - // VerifyBlockField::Uncle, - // !uncle_ids.contains(&uncle.id()), - // "repeat uncle {:?} in current block {:?}", - // uncle_id, - // header.id() - // ); - - // if !header.is_dag() { - // verify_block!( - // VerifyBlockField::Uncle, - // uncle.number() < header.number() , - // "uncle block number bigger than or equal to current block ,uncle block number is {} , current block number is {}", uncle.number(), header.number() - // ); - // } - - // verify_block!( - // VerifyBlockField::Uncle, - // current_chain.get_block_info(Some(uncle_id))?.is_some(), - // "Invalid block: uncle {} does not exist", - // uncle_id - // ); - - // debug!( - // "verify_uncle header number {} hash {:?} uncle number {} hash {:?}", - // header.number(), - // header.id(), - // uncle.number(), - // uncle.id() - // ); - // uncle_ids.insert(uncle_id); - // } + Ok(None) + } +} - Ok(()) + +pub struct DagVerifierWithGhostData; +impl BlockVerifier for DagVerifierWithGhostData { + fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> + where + R: ChainReader, + { + BasicDagVerifier::verify_header(current_chain, new_block_header) + } + + fn verify_uncles( + current_chain: &R, + uncles: &[BlockHeader], + header: &BlockHeader, + ) -> Result> + where + R: ChainReader, + { + Ok(Some(BasicDagVerifier::verify_blue_blocks(current_chain, uncles, header)?)) } } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index cd6716b82d..5a18e8a57d 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -545,4 +545,8 @@ impl BlockDAG { pub fn reachability_store(&self) -> Arc> { self.storage.reachability_store.clone() } + + pub fn verify_and_ghostdata(&self, blue_blocks: &[BlockHeader], header: &BlockHeader) -> Result { + self.ghost_dag_manager().verify_and_ghostdata(blue_blocks, header) + } } diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 9993fa8ac2..29dfaf2646 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -171,6 +171,61 @@ impl< Ok(new_block_data) } + pub(crate) fn verify_and_ghostdata(&self, blue_blocks: &[BlockHeader], header: &BlockHeader) -> std::result::Result { + let mut new_block_data = GhostdagData::new_with_selected_parent(header.parent_hash(), self.k); + for blue_candidate in blue_blocks { + let coloring = self.check_blue_candidate(&new_block_data, blue_candidate.id())?; + if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { + new_block_data.add_blue(blue_candidate.id(), blue_anticone_size, &blues_anticone_sizes); + } else { + new_block_data.add_red(blue_candidate.id()); + } + } + + if blue_blocks.len() != new_block_data.mergeset_blues.len() { + return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, checking data: {}", blue_blocks.len(), new_block_data.mergeset_blues.len())); + } + if blue_blocks.iter().map(|block_header| block_header.id()).collect::>() != new_block_data.mergeset_blues.iter().cloned().collect::>() { + return Err(anyhow::anyhow!("The blue set is not equal")); + } + + if !new_block_data.mergeset_reds.is_empty() { + return Err(anyhow::anyhow!("The red set is not empty when checking the block for ghost data: {:?}", header.id())); + } + + BlockHashes::make_mut(&mut new_block_data.mergeset_blues).push(new_block_data.selected_parent); + + let blue_score = self + .ghostdag_store + .get_blue_score(header.parent_hash())? + .checked_add(new_block_data.mergeset_blues.len() as u64) + .expect("blue score size should less than u64"); + + let added_blue_work: BlueWorkType = new_block_data + .mergeset_blues + .iter() + .cloned() + .map(|hash| { + self.headers_store + .get_difficulty(hash) + .unwrap_or_else(|err| { + error!("Failed to get difficulty of block: {}, {}", hash, err); + 0.into() + }) + }) + .sum(); + + let blue_work = self + .ghostdag_store + .get_blue_work(new_block_data.selected_parent)? + .checked_add(added_blue_work) + .expect("blue work should less than u256"); + + new_block_data.finalize_score_and_work(blue_score, blue_work); + + Ok(new_block_data) + } + pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { let mut check_ghostdata = GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); for blue_candidate in ghostdata.mergeset_blues.iter().skip(1).cloned() { @@ -381,6 +436,8 @@ impl< }); Ok(sorted_blocks) } + + } /// Chain block with attached ghostdag data From a2f64bc5def9ecab37a8dcd11d23ab50f567f584 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 4 Sep 2024 09:50:18 +0800 Subject: [PATCH 18/60] add some code --- chain/api/src/chain.rs | 3 + chain/src/chain.rs | 17 +++- chain/src/verifier/mod.rs | 2 +- flexidag/src/ghostdag/protocol.rs | 125 +++++++++++++++++++++++++----- sync/src/parallel/executor.rs | 5 +- sync/src/parallel/sender.rs | 19 ++++- sync/src/tasks/block_sync_task.rs | 13 +--- sync/src/tasks/mod.rs | 2 +- 8 files changed, 145 insertions(+), 41 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index 9d8452283a..17c2324a27 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -120,6 +120,9 @@ pub trait ChainWriter { /// Verify, Execute and Connect block to current chain. fn apply(&mut self, block: Block) -> Result; + /// Verify, Execute and Connect block to current chain. + fn apply_for_sync(&mut self, block: Block) -> Result; + fn chain_state(&mut self) -> &ChainStateDB; } diff --git a/chain/src/chain.rs b/chain/src/chain.rs index e1c00ff88d..4eba88ad86 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1,7 +1,7 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::verifier::{BlockVerifier, DagVerifier, FullVerifier}; +use crate::verifier::{BlockVerifier, DagVerifier, DagVerifierWithGhostData, FullVerifier}; use anyhow::{bail, ensure, format_err, Ok, Result}; use sp_utils::stop_watch::{watch, CHAIN_WATCH_NAME}; use starcoin_accumulator::inmemory::InMemoryAccumulator; @@ -645,9 +645,14 @@ impl BlockChain { .storage .get_block_header_by_hash(self.genesis_hash)? .ok_or_else(|| format_err!("failed to get genesis because it is none"))?; - let result = self - .dag - .commit(header.to_owned(), genesis_header.parent_hash()); + let result = match verified_block.ghostdata { + Some(trusted_ghostdata) => { + self.dag.commit_trusted_block(header.to_owned(), genesis_header.parent_hash(), Arc::new(trusted_ghostdata)) + } + None => { + self.dag.commit(header.to_owned(), genesis_header.parent_hash()) + } + }; match result { anyhow::Result::Ok(_) => info!("finish to commit dag block: {:?}", block_id), Err(e) => { @@ -1535,6 +1540,10 @@ impl ChainWriter for BlockChain { fn chain_state(&mut self) -> &ChainStateDB { &self.statedb } + + fn apply_for_sync(&mut self, block: Block) -> Result { + self.apply_with_verifier::(block) + } } pub(crate) fn info_2_accumulator( diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index d8bb8234cf..69015821d7 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -85,7 +85,7 @@ pub trait BlockVerifier { watch(CHAIN_WATCH_NAME, "n14"); Ok(VerifiedBlock{ block: new_block, - ghostdata: None, + ghostdata, }) } diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 29dfaf2646..862ee4a7ce 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -2,7 +2,7 @@ use super::util::Refs; use crate::consensusdb::schemadb::{GhostdagStoreReader, HeaderStoreReader, RelationsStoreReader}; use crate::reachability::reachability_service::ReachabilityService; use crate::types::{ghostdata::GhostdagData, ordering::*}; -use anyhow::{ensure, Context, Result}; +use anyhow::{bail, ensure, Context, Result}; use parking_lot::RwLock; use starcoin_crypto::HashValue as Hash; use starcoin_logger::prelude::*; @@ -172,36 +172,53 @@ impl< } pub(crate) fn verify_and_ghostdata(&self, blue_blocks: &[BlockHeader], header: &BlockHeader) -> std::result::Result { - let mut new_block_data = GhostdagData::new_with_selected_parent(header.parent_hash(), self.k); - for blue_candidate in blue_blocks { - let coloring = self.check_blue_candidate(&new_block_data, blue_candidate.id())?; + let parents = header.parents_hash(); + assert!( + !parents.is_empty(), + "genesis must be added via a call to init" + ); + // Run the GHOSTDAG parent selection algorithm + let selected_parent = header.parent_hash(); + // Initialize new GHOSTDAG block data with the selected parent + let mut new_block_data = GhostdagData::new_with_selected_parent(selected_parent, self.k); + // Get the mergeset in consensus-agreed topological order (topological here means forward in time from blocks to children) + // let ordered_mergeset = + // self.ordered_mergeset_without_selected_parent(selected_parent, &parents)?; + + // let last_blue_block = self.sort_blocks(blue_blocks.into_iter().map(|header| header.id()))?.last().cloned(); + let ordered_mergeset = self.sort_blocks(header.parents_hash().into_iter().filter(|header_id| { + *header_id != header.parent_hash() + }).chain(blue_blocks.into_iter().filter(|header| { + header.id() != new_block_data.selected_parent + }).map(|header| header.id())).collect::>().into_iter().collect::>())?; + + for blue_candidate in ordered_mergeset.iter().cloned() { + let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { - new_block_data.add_blue(blue_candidate.id(), blue_anticone_size, &blues_anticone_sizes); + // No k-cluster violation found, we can now set the candidate block as blue + new_block_data.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); } else { - new_block_data.add_red(blue_candidate.id()); + new_block_data.add_red(blue_candidate); } } - if blue_blocks.len() != new_block_data.mergeset_blues.len() { - return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, checking data: {}", blue_blocks.len(), new_block_data.mergeset_blues.len())); - } - if blue_blocks.iter().map(|block_header| block_header.id()).collect::>() != new_block_data.mergeset_blues.iter().cloned().collect::>() { - return Err(anyhow::anyhow!("The blue set is not equal")); - } - if !new_block_data.mergeset_reds.is_empty() { - return Err(anyhow::anyhow!("The red set is not empty when checking the block for ghost data: {:?}", header.id())); - } + if new_block_data.mergeset_blues.iter().skip(1).cloned().collect::>() != blue_blocks.into_iter().map(|header| header.id()).collect::>() { - BlockHashes::make_mut(&mut new_block_data.mergeset_blues).push(new_block_data.selected_parent); + // if blue_blocks.len() == 1 && blue_blocks.first().expect("it should not be none").id() == new_block_data.selected_parent { + // *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = blue_blocks.into_iter().map(|header| header.id()).collect(); + // } else { + bail!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks, new_block_data.mergeset_blues); + // } + } let blue_score = self .ghostdag_store - .get_blue_score(header.parent_hash())? + .get_blue_score(selected_parent)? .checked_add(new_block_data.mergeset_blues.len() as u64) .expect("blue score size should less than u64"); - let added_blue_work: BlueWorkType = new_block_data + let added_blue_work: BlueWorkType = new_block_data .mergeset_blues .iter() .cloned() @@ -217,13 +234,82 @@ impl< let blue_work = self .ghostdag_store - .get_blue_work(new_block_data.selected_parent)? + .get_blue_work(selected_parent)? .checked_add(added_blue_work) .expect("blue work should less than u256"); new_block_data.finalize_score_and_work(blue_score, blue_work); Ok(new_block_data) + + // let mut new_block_data = GhostdagData::new_with_selected_parent(header.parent_hash(), self.k); + // let mut mergetset = header.parents_hash().into_iter().filter(|header_id| { + // *header_id != header.parent_hash() + // }).chain(blue_blocks.into_iter().filter(|header| { + // header.id() != new_block_data.selected_parent + // }).map(|header| header.id())).collect::>().into_iter().collect::>(); + // info!("jacktest: merget set = {:?}", mergetset); + // mergetset = self.sort_blocks(mergetset.into_iter())?; + // let ordered_mergeset = + // self.ordered_mergeset_without_selected_parent(new_block_data.selected_parent, &vec![new_block_data.selected_parent])?; + + + // for blue_candidate in ordered_mergeset { + // let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; + // if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { + // new_block_data.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); + // } else { + // new_block_data.add_red(blue_candidate); + // } + // } + // let mut valid_mergeset_blues = vec![new_block_data.selected_parent]; + // valid_mergeset_blues.append(&mut new_block_data.mergeset_blues.iter().cloned().collect::>().into_iter().filter(|header_id| { + // *header_id != new_block_data.selected_parent + // }).collect()); + // *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = valid_mergeset_blues; + // *BlockHashes::make_mut(&mut new_block_data.mergeset_reds) = new_block_data.mergeset_reds.iter().cloned().collect::>().into_iter().collect::>(); + // let selectd_ghostdata = self.ghostdag(&vec![header.parent_hash()])?; + // if blue_blocks.len() != new_block_data.mergeset_blues.len().saturating_sub(1) { + // return Err(anyhow::anyhow!("The len of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues)); + // } + + // let mut expected_blue_blocks = blue_blocks.iter().map(|header| header.id()).collect::>(); + // expected_blue_blocks.insert(new_block_data.selected_parent); + // if expected_blue_blocks != new_block_data.mergeset_blues.iter().cloned().collect::>() { + // // return Err(anyhow::anyhow!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues)); + // info!("The data of blue set is not equal, for {:?}, checking data: {:?}, run ghost protocol to get the valid data", blue_blocks, new_block_data.mergeset_blues); + // return Ok(self.ghostdag(&header.parents_hash())?); + // } + + // let blue_score = self + // .ghostdag_store + // .get_blue_score(header.parent_hash())? + // .checked_add(new_block_data.mergeset_blues.len() as u64) + // .expect("blue score size should less than u64"); + + // let added_blue_work: BlueWorkType = new_block_data + // .mergeset_blues + // .iter() + // .cloned() + // .map(|hash| { + // self.headers_store + // .get_difficulty(hash) + // .unwrap_or_else(|err| { + // error!("Failed to get difficulty of block: {}, {}", hash, err); + // 0.into() + // }) + // }) + // .sum(); + + // let blue_work = self + // .ghostdag_store + // .get_blue_work(new_block_data.selected_parent)? + // .checked_add(added_blue_work) + // .expect("blue work should less than u256"); + + // new_block_data.finalize_score_and_work(blue_score, blue_work); + + // Ok(new_block_data) } pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { @@ -299,6 +385,7 @@ impl< .reachability_service .is_dag_ancestor_of(hash, blue_candidate) { + info!("jacktest: because {:?} is_dag_ancestor_of {:?}, return blue", hash, blue_candidate); return Ok(ColoringState::Blue); } } diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index ed4c9480d7..6401958f2b 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use starcoin_chain::{verifier::DagVerifier, BlockChain, ChainReader}; +use starcoin_chain::{verifier::{DagVerifier, DagVerifierWithGhostData}, BlockChain, ChainReader}; use starcoin_chain_api::ExecutedBlock; use starcoin_config::TimeService; use starcoin_crypto::HashValue; @@ -73,7 +73,6 @@ impl DagBlockExecutor { Some(block) => { let header = block.header().clone(); - info!("worker will process header {:?}", header); loop { match Self::waiting_for_parents( &self.dag, @@ -128,7 +127,7 @@ impl DagBlockExecutor { } info!("sync parallel worker {:p} will execute block: {:?}", &self, block.header().id()); - match chain.as_mut().expect("it cannot be none!").apply_with_verifier::(block) { + match chain.as_mut().expect("it cannot be none!").apply_with_verifier::(block) { Ok(executed_block) => { info!( "succeed to execute block: number: {:?}, id: {:?}", diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index a98715e421..9a0a721e2f 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -10,7 +10,7 @@ use starcoin_storage::Store; use starcoin_types::block::{Block, BlockHeader}; use tokio::{sync::mpsc::{self, Receiver, Sender}, task::JoinHandle}; -use crate::store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::{self, SyncDagStore}}; +use crate::{store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::{self, SyncDagStore}}, tasks::continue_execute_absent_block::ContinueChainOperator}; use super::executor::{DagBlockExecutor, ExecuteState}; @@ -21,7 +21,7 @@ struct DagBlockWorker { pub handle: JoinHandle<()>, } -pub struct DagBlockSender { +pub struct DagBlockSender<'a> { sync_dag_store: SyncDagStore, executors: Vec, queue_size: usize, @@ -29,9 +29,10 @@ pub struct DagBlockSender { storage: Arc, vm_metrics: Option, dag: BlockDAG, + notifier: &'a mut dyn ContinueChainOperator, } -impl DagBlockSender { +impl<'a> DagBlockSender<'a> { pub fn new( sync_dag_store: SyncDagStore, queue_size: usize, @@ -39,6 +40,7 @@ impl DagBlockSender { storage: Arc, vm_metrics: Option, dag: BlockDAG, + notifier: &'a mut dyn ContinueChainOperator, ) -> Self { Self { sync_dag_store, @@ -48,6 +50,7 @@ impl DagBlockSender { storage, vm_metrics, dag, + notifier, } } @@ -95,6 +98,7 @@ impl DagBlockSender { // Finding the executing state is the priority if self.dispatch_to_worker(&block).await? { + self.flush_executor_state().await?; continue; } @@ -134,6 +138,8 @@ impl DagBlockSender { match state { ExecuteState::Executed(executed_block) => { self.sync_dag_store.delete_dag_sync_block(executed_block.block().header().number(), executed_block.header().id())?; + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify(executed_block.clone())?; worker.state = ExecuteState::Executed(executed_block); } _ => () @@ -148,6 +154,7 @@ impl DagBlockSender { } } + let len = self.executors.len(); self.executors.retain(|worker| { if let ExecuteState::Closed = worker.state { false @@ -155,7 +162,11 @@ impl DagBlockSender { true } }); - info!("sync workers count: {:?}", self.executors.len()); + + if len != self.executors.len() { + info!("sync workers count: {:?}", self.executors.len()); + } + anyhow::Ok(()) } diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index b4647e59fd..a32aba529d 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -354,7 +354,7 @@ where self.chain .apply_with_verifier::(block.clone()) } else { - self.chain.apply(block.clone()) + self.chain.apply_for_sync(block.clone()) }; if let Err(err) = apply_result { let error_msg = err.to_string(); @@ -460,17 +460,15 @@ where 100000, self.chain.time_service(), self.local_store.clone(), - None, self.chain.dag()); + None, self.chain.dag(), self); parallel_execute.process_absent_blocks().await?; anyhow::Ok(ParallelSign::Executed) } else { - info!("now save the dag block in order"); self.local_store.save_dag_sync_block(starcoin_storage::block::DagSyncBlock { block: block.clone(), children: vec![], })?; self.sync_dag_store.save_block(block)?; - info!("finish saving"); anyhow::Ok(ParallelSign::NeedMoreBlocks) } @@ -652,15 +650,12 @@ where let timestamp = block.header().timestamp(); - let block_info = if self.chain.check_chain_type()? == ChainType::Dag { + let block_info = if self.chain.has_dag_block(block.header().id())? { block_info } else { None - } - } else { - block_info - }; + }; let (block_info, action) = match block_info { Some(block_info) => { diff --git a/sync/src/tasks/mod.rs b/sync/src/tasks/mod.rs index f4f5989508..48abe6d18d 100644 --- a/sync/src/tasks/mod.rs +++ b/sync/src/tasks/mod.rs @@ -589,7 +589,7 @@ where mod accumulator_sync_task; mod block_sync_task; -mod continue_execute_absent_block; +pub mod continue_execute_absent_block; mod find_ancestor_task; mod inner_sync_task; #[cfg(test)] From 763f1d3ab07308612bc8e27556884855484c76da Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 4 Sep 2024 12:34:01 +0800 Subject: [PATCH 19/60] add verification --- flexidag/src/ghostdag/protocol.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 862ee4a7ce..9a9f0ecd94 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -177,15 +177,9 @@ impl< !parents.is_empty(), "genesis must be added via a call to init" ); - // Run the GHOSTDAG parent selection algorithm let selected_parent = header.parent_hash(); // Initialize new GHOSTDAG block data with the selected parent let mut new_block_data = GhostdagData::new_with_selected_parent(selected_parent, self.k); - // Get the mergeset in consensus-agreed topological order (topological here means forward in time from blocks to children) - // let ordered_mergeset = - // self.ordered_mergeset_without_selected_parent(selected_parent, &parents)?; - - // let last_blue_block = self.sort_blocks(blue_blocks.into_iter().map(|header| header.id()))?.last().cloned(); let ordered_mergeset = self.sort_blocks(header.parents_hash().into_iter().filter(|header_id| { *header_id != header.parent_hash() }).chain(blue_blocks.into_iter().filter(|header| { @@ -202,14 +196,14 @@ impl< } } + *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = self.sort_blocks(new_block_data.mergeset_blues.iter().cloned())?; if new_block_data.mergeset_blues.iter().skip(1).cloned().collect::>() != blue_blocks.into_iter().map(|header| header.id()).collect::>() { - - // if blue_blocks.len() == 1 && blue_blocks.first().expect("it should not be none").id() == new_block_data.selected_parent { - // *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = blue_blocks.into_iter().map(|header| header.id()).collect(); - // } else { + if header.number() < 10000000 { + warn!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks, new_block_data.mergeset_blues); + } else { bail!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks, new_block_data.mergeset_blues); - // } + } } let blue_score = self @@ -385,7 +379,6 @@ impl< .reachability_service .is_dag_ancestor_of(hash, blue_candidate) { - info!("jacktest: because {:?} is_dag_ancestor_of {:?}, return blue", hash, blue_candidate); return Ok(ColoringState::Blue); } } From be34e3b882dc212fdccc8a2491f88f21ff42ffb9 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 4 Sep 2024 16:15:41 +0800 Subject: [PATCH 20/60] fix some bugs --- flexidag/src/ghostdag/protocol.rs | 19 +++++++++++++++++- flexidag/src/types/ordering.rs | 32 +++++++++++++++++++++++++++++++ sync/src/parallel/sender.rs | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 9a9f0ecd94..549d884b66 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -196,7 +196,7 @@ impl< } } - *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = self.sort_blocks(new_block_data.mergeset_blues.iter().cloned())?; + *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = self.sort_blocks_for_work_type(new_block_data.mergeset_blues.iter().cloned())?; if new_block_data.mergeset_blues.iter().skip(1).cloned().collect::>() != blue_blocks.into_iter().map(|header| header.id()).collect::>() { if header.number() < 10000000 { @@ -517,7 +517,24 @@ impl< Ok(sorted_blocks) } + pub fn sort_blocks_for_work_type(&self, blocks: impl IntoIterator) -> Result> { + let mut sorted_blocks: Vec = blocks.into_iter().collect(); + sorted_blocks.sort_by_cached_key(|block| { + let blue_work = self + .ghostdag_store + .get_blue_work(*block) + .unwrap_or_else(|err| { + error!("Failed to get blue work of block: {}, {}", *block, err); + 0.into() + }); + SortableBlockWithWorkType { + hash: *block, + blue_work, + } + }); + Ok(sorted_blocks) + } } /// Chain block with attached ghostdag data diff --git a/flexidag/src/types/ordering.rs b/flexidag/src/types/ordering.rs index a1ed8c2561..882d3401d5 100644 --- a/flexidag/src/types/ordering.rs +++ b/flexidag/src/types/ordering.rs @@ -34,3 +34,35 @@ impl Ord for SortableBlock { .then_with(|| self.hash.cmp(&other.hash)) } } + +#[derive(Eq, Clone, Debug, Serialize, Deserialize)] +pub struct SortableBlockWithWorkType { + pub hash: Hash, + pub blue_work: BlueWorkType, +} + +impl SortableBlockWithWorkType { + pub fn new(hash: Hash, blue_work: BlueWorkType) -> Self { + Self { hash, blue_work } + } +} + +impl PartialEq for SortableBlockWithWorkType { + fn eq(&self, other: &Self) -> bool { + self.hash == other.hash + } +} + +impl PartialOrd for SortableBlockWithWorkType { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for SortableBlockWithWorkType { + fn cmp(&self, other: &Self) -> Ordering { + other.blue_work + .cmp(&self.blue_work) + .then_with(|| self.hash.cmp(&other.hash)) + } +} diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index 9a0a721e2f..ec17e49a5c 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -127,6 +127,7 @@ impl<'a> DagBlockSender<'a> { } self.wait_for_finish().await?; + sync_dag_store.delete_all_dag_sync_block()?; Ok(()) } @@ -137,7 +138,6 @@ impl<'a> DagBlockSender<'a> { Ok(state) => { match state { ExecuteState::Executed(executed_block) => { - self.sync_dag_store.delete_dag_sync_block(executed_block.block().header().number(), executed_block.header().id())?; info!("finish to execute block {:?}", executed_block.header()); self.notifier.notify(executed_block.clone())?; worker.state = ExecuteState::Executed(executed_block); From 429989476d152a576f2a55b7b282111d9f28e97a Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 4 Sep 2024 17:05:20 +0800 Subject: [PATCH 21/60] add yeilding after execution for processing the main chain in other service --- sync/src/parallel/executor.rs | 9 +++++---- sync/src/parallel/sender.rs | 17 +++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index 6401958f2b..9bc9f716f6 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use parking_lot::RwLock; use starcoin_chain::{verifier::{DagVerifier, DagVerifierWithGhostData}, BlockChain, ChainReader}; use starcoin_chain_api::ExecutedBlock; use starcoin_config::TimeService; @@ -13,9 +14,10 @@ use tokio::{ sync::mpsc::{self, Receiver, Sender}, task::JoinHandle, time::{timeout, Duration} }; +use crate::tasks::continue_execute_absent_block::ContinueChainOperator; + #[derive(Debug)] pub enum ExecuteState { - Ready(HashValue), Executing(HashValue), Executed(ExecutedBlock), Error(BlockHeader), @@ -28,7 +30,7 @@ pub struct DagBlockExecutor { time_service: Arc, storage: Arc, vm_metrics: Option, - dag: BlockDAG + dag: BlockDAG, } impl DagBlockExecutor { @@ -36,7 +38,6 @@ impl DagBlockExecutor { sender_to_main: Sender, buffer_size: usize, time_service: Arc, - head_block_hash: HashValue, storage: Arc, vm_metrics: Option, dag: BlockDAG, @@ -139,7 +140,7 @@ impl DagBlockExecutor { .send(ExecuteState::Executed(executed_block)) .await { - Ok(_) => (), + Ok(_) => tokio::task::yield_now().await, Err(e) => { error!( "failed to send waiting state: {:?}, for reason: {:?}", diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index ec17e49a5c..a83ea41396 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -64,7 +64,7 @@ impl<'a> DagBlockSender<'a> { return anyhow::Ok(true); } } - ExecuteState::Executed(_) | ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + ExecuteState::Executed(_) | ExecuteState::Error(_) | ExecuteState::Closed => { continue; } } @@ -78,7 +78,7 @@ impl<'a> DagBlockSender<'a> { return anyhow::Ok(true); } - ExecuteState::Executing(_) | ExecuteState::Ready(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + ExecuteState::Executing(_) | ExecuteState::Error(_) | ExecuteState::Closed => { continue; } } @@ -108,7 +108,6 @@ impl<'a> DagBlockSender<'a> { sender_to_main, self.queue_size, self.time_service.clone(), - block.header().parent_hash(), self.storage.clone(), self.vm_metrics.clone(), self.dag.clone(), @@ -170,11 +169,17 @@ impl<'a> DagBlockSender<'a> { anyhow::Ok(()) } - async fn wait_for_finish(self) -> anyhow::Result<()> { + async fn wait_for_finish(mut self) -> anyhow::Result<()> { for mut worker in self.executors { drop(worker.sender_to_executor); - while let Some(_) = worker.receiver_from_executor.recv().await { - () + while let Some(state) = worker.receiver_from_executor.recv().await { + match state { + ExecuteState::Executed(executed_block) => { + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify(executed_block.clone())?; + } + ExecuteState::Executing(_) | ExecuteState::Error(_) | ExecuteState::Closed => (), + } } worker.handle.await?; } From 8437fe8d4aeec5978f5c76c5c35b500d5e127a47 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 4 Sep 2024 23:23:07 +0800 Subject: [PATCH 22/60] finish debug, it works --- flexidag/src/ghostdag/protocol.rs | 12 ++++++------ flexidag/src/types/ordering.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 549d884b66..4bd3b9d55b 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -177,11 +177,11 @@ impl< !parents.is_empty(), "genesis must be added via a call to init" ); - let selected_parent = header.parent_hash(); + let selected_parent = self.find_selected_parent(header.parents_hash().into_iter())?; // Initialize new GHOSTDAG block data with the selected parent let mut new_block_data = GhostdagData::new_with_selected_parent(selected_parent, self.k); let ordered_mergeset = self.sort_blocks(header.parents_hash().into_iter().filter(|header_id| { - *header_id != header.parent_hash() + *header_id != new_block_data.selected_parent }).chain(blue_blocks.into_iter().filter(|header| { header.id() != new_block_data.selected_parent }).map(|header| header.id())).collect::>().into_iter().collect::>())?; @@ -196,13 +196,11 @@ impl< } } - *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = self.sort_blocks_for_work_type(new_block_data.mergeset_blues.iter().cloned())?; - if new_block_data.mergeset_blues.iter().skip(1).cloned().collect::>() != blue_blocks.into_iter().map(|header| header.id()).collect::>() { if header.number() < 10000000 { - warn!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks, new_block_data.mergeset_blues); + warn!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.into_iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); } else { - bail!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks, new_block_data.mergeset_blues); + bail!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.into_iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); } } @@ -234,6 +232,8 @@ impl< new_block_data.finalize_score_and_work(blue_score, blue_work); + info!("verified the block: {:?}, its ghost data: {:?}", header.id(), new_block_data); + Ok(new_block_data) // let mut new_block_data = GhostdagData::new_with_selected_parent(header.parent_hash(), self.k); diff --git a/flexidag/src/types/ordering.rs b/flexidag/src/types/ordering.rs index 882d3401d5..e903082f09 100644 --- a/flexidag/src/types/ordering.rs +++ b/flexidag/src/types/ordering.rs @@ -63,6 +63,6 @@ impl Ord for SortableBlockWithWorkType { fn cmp(&self, other: &Self) -> Ordering { other.blue_work .cmp(&self.blue_work) - .then_with(|| self.hash.cmp(&other.hash)) + .then_with(|| other.hash.cmp(&self.hash)) } } From ef84a9b05afd525751262ac171af4212e74dfc7c Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 5 Sep 2024 11:27:31 +0800 Subject: [PATCH 23/60] fmt and clippy --- chain/api/src/chain.rs | 6 +- chain/src/chain.rs | 24 +++-- chain/src/verifier/mod.rs | 28 +++--- flexidag/src/blockdag.rs | 63 +++++++++--- flexidag/src/ghostdag/protocol.rs | 90 +++++++++++++---- flexidag/src/types/ordering.rs | 3 +- flexidag/tests/tests.rs | 157 ++++++++++++++++++++++++------ sync/src/lib.rs | 2 +- sync/src/parallel/executor.rs | 50 +++++++--- sync/src/parallel/sender.rs | 70 ++++++------- sync/src/store/sync_dag_store.rs | 7 +- sync/src/store/tests.rs | 17 +--- sync/src/sync.rs | 2 +- sync/src/tasks/block_sync_task.rs | 35 ++++--- sync/src/tasks/inner_sync_task.rs | 3 +- sync/src/tasks/mock.rs | 3 +- 16 files changed, 380 insertions(+), 180 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index 17c2324a27..2d801f1d32 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -109,7 +109,11 @@ pub trait ChainReader { fn current_tips_hash(&self) -> Result>; fn has_dag_block(&self, header_id: HashValue) -> Result; fn check_chain_type(&self) -> Result; - fn verify_and_ghostdata(&self, uncles: &[BlockHeader], header: &BlockHeader) -> Result; + fn verify_and_ghostdata( + &self, + uncles: &[BlockHeader], + header: &BlockHeader, + ) -> Result; } pub trait ChainWriter { diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 4eba88ad86..925414f136 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -646,12 +646,14 @@ impl BlockChain { .get_block_header_by_hash(self.genesis_hash)? .ok_or_else(|| format_err!("failed to get genesis because it is none"))?; let result = match verified_block.ghostdata { - Some(trusted_ghostdata) => { - self.dag.commit_trusted_block(header.to_owned(), genesis_header.parent_hash(), Arc::new(trusted_ghostdata)) - } - None => { - self.dag.commit(header.to_owned(), genesis_header.parent_hash()) - } + Some(trusted_ghostdata) => self.dag.commit_trusted_block( + header.to_owned(), + genesis_header.parent_hash(), + Arc::new(trusted_ghostdata), + ), + None => self + .dag + .commit(header.to_owned(), genesis_header.parent_hash()), }; match result { anyhow::Result::Ok(_) => info!("finish to commit dag block: {:?}", block_id), @@ -1352,8 +1354,12 @@ impl ChainReader for BlockChain { fn check_chain_type(&self) -> Result { Ok(ChainType::Dag) } - - fn verify_and_ghostdata(&self, uncles: &[BlockHeader], header: &BlockHeader) -> Result { + + fn verify_and_ghostdata( + &self, + uncles: &[BlockHeader], + header: &BlockHeader, + ) -> Result { self.dag().verify_and_ghostdata(uncles, header) } } @@ -1540,7 +1546,7 @@ impl ChainWriter for BlockChain { fn chain_state(&mut self) -> &ChainStateDB { &self.statedb } - + fn apply_for_sync(&mut self, block: Block) -> Result { self.apply_with_verifier::(block) } diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index 69015821d7..bd8870685c 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -83,7 +83,7 @@ pub trait BlockVerifier { new_block_header, )?; watch(CHAIN_WATCH_NAME, "n14"); - Ok(VerifiedBlock{ + Ok(VerifiedBlock { block: new_block, ghostdata, }) @@ -322,10 +322,10 @@ impl BlockVerifier for NoneVerifier { where R: ChainReader, { - Ok(VerifiedBlock{ + Ok(VerifiedBlock { block: new_block, ghostdata: None, - }) + }) } fn verify_uncles( @@ -340,7 +340,6 @@ impl BlockVerifier for NoneVerifier { } } - struct BasicDagVerifier; impl BasicDagVerifier { pub fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> @@ -386,13 +385,17 @@ impl BasicDagVerifier { ConsensusVerifier::verify_header(current_chain, new_block_header) } - - fn verify_blue_blocks(current_chain: &R, uncles: &[BlockHeader], header: &BlockHeader) -> Result where R: ChainReader { + + fn verify_blue_blocks( + current_chain: &R, + uncles: &[BlockHeader], + header: &BlockHeader, + ) -> Result + where + R: ChainReader, + { current_chain.verify_and_ghostdata(uncles, header) } - - - } //TODO: Implement it. pub struct DagVerifier; @@ -416,7 +419,6 @@ impl BlockVerifier for DagVerifier { } } - pub struct DagVerifierWithGhostData; impl BlockVerifier for DagVerifierWithGhostData { fn verify_header(current_chain: &R, new_block_header: &BlockHeader) -> Result<()> @@ -434,6 +436,10 @@ impl BlockVerifier for DagVerifierWithGhostData { where R: ChainReader, { - Ok(Some(BasicDagVerifier::verify_blue_blocks(current_chain, uncles, header)?)) + Ok(Some(BasicDagVerifier::verify_blue_blocks( + current_chain, + uncles, + header, + )?)) } } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 5a18e8a57d..054f01af07 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -12,7 +12,6 @@ use crate::consensusdb::{ }; use crate::ghostdag::protocol::GhostdagManager; use crate::prune::pruning_point_manager::PruningPointManagerT; -use crate::types::ghostdata::CompactGhostdagData; use crate::{process_key_already_error, reachability}; use anyhow::{bail, ensure, format_err, Ok}; use starcoin_accumulator::node::AccumulatorStoreType; @@ -26,7 +25,6 @@ use starcoin_types::{ blockhash::{BlockHashes, KType}, consensus_header::ConsensusHeader, }; -use std::char::EscapeUnicode; use std::collections::HashSet; use std::ops::DerefMut; use std::sync::Arc; @@ -145,7 +143,12 @@ impl BlockDAG { Ok(()) } - pub fn commit_trusted_block(&mut self, header: BlockHeader, origin: HashValue, trusted_ghostdata: Arc) -> anyhow::Result<()> { + pub fn commit_trusted_block( + &mut self, + header: BlockHeader, + origin: HashValue, + trusted_ghostdata: Arc, + ) -> anyhow::Result<()> { info!( "start to commit header: {:?}, number: {:?}", header.id(), @@ -165,16 +168,39 @@ impl BlockDAG { if header.is_genesis() { Arc::new(self.ghostdag_manager.genesis_ghostdag_data(&header)) } else { - self.storage.ghost_dag_store.insert(header.id(), trusted_ghostdata.clone())?; + self.storage + .ghost_dag_store + .insert(header.id(), trusted_ghostdata.clone())?; trusted_ghostdata } } Some(ghostdata) => { - ensure!(ghostdata.blue_score == trusted_ghostdata.blue_score, "blue score is not same"); - ensure!(ghostdata.blue_work == trusted_ghostdata.blue_work, "blue work is not same"); - ensure!(ghostdata.mergeset_blues.len() == trusted_ghostdata.mergeset_blues.len(), "blue len is not same"); - ensure!(ghostdata.mergeset_blues.iter().cloned().collect::>() == trusted_ghostdata.mergeset_blues.iter().cloned().collect::>(), "blue values are not same"); - trusted_ghostdata + ensure!( + ghostdata.blue_score == trusted_ghostdata.blue_score, + "blue score is not same" + ); + ensure!( + ghostdata.blue_work == trusted_ghostdata.blue_work, + "blue work is not same" + ); + ensure!( + ghostdata.mergeset_blues.len() == trusted_ghostdata.mergeset_blues.len(), + "blue len is not same" + ); + ensure!( + ghostdata + .mergeset_blues + .iter() + .cloned() + .collect::>() + == trusted_ghostdata + .mergeset_blues + .iter() + .cloned() + .collect::>(), + "blue values are not same" + ); + trusted_ghostdata } }; // Store ghostdata @@ -265,8 +291,6 @@ impl BlockDAG { Ok(()) } - - pub fn commit(&mut self, header: BlockHeader, origin: HashValue) -> anyhow::Result<()> { info!( "start to commit header: {:?}, number: {:?}", @@ -541,12 +565,19 @@ impl BlockDAG { anyhow::Ok(()) } - - pub fn reachability_store(&self) -> Arc> { + + pub fn reachability_store( + &self, + ) -> Arc> { self.storage.reachability_store.clone() } - - pub fn verify_and_ghostdata(&self, blue_blocks: &[BlockHeader], header: &BlockHeader) -> Result { - self.ghost_dag_manager().verify_and_ghostdata(blue_blocks, header) + + pub fn verify_and_ghostdata( + &self, + blue_blocks: &[BlockHeader], + header: &BlockHeader, + ) -> Result { + self.ghost_dag_manager() + .verify_and_ghostdata(blue_blocks, header) } } diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 4bd3b9d55b..96a6abe37c 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -171,7 +171,11 @@ impl< Ok(new_block_data) } - pub(crate) fn verify_and_ghostdata(&self, blue_blocks: &[BlockHeader], header: &BlockHeader) -> std::result::Result { + pub(crate) fn verify_and_ghostdata( + &self, + blue_blocks: &[BlockHeader], + header: &BlockHeader, + ) -> std::result::Result { let parents = header.parents_hash(); assert!( !parents.is_empty(), @@ -180,11 +184,21 @@ impl< let selected_parent = self.find_selected_parent(header.parents_hash().into_iter())?; // Initialize new GHOSTDAG block data with the selected parent let mut new_block_data = GhostdagData::new_with_selected_parent(selected_parent, self.k); - let ordered_mergeset = self.sort_blocks(header.parents_hash().into_iter().filter(|header_id| { - *header_id != new_block_data.selected_parent - }).chain(blue_blocks.into_iter().filter(|header| { - header.id() != new_block_data.selected_parent - }).map(|header| header.id())).collect::>().into_iter().collect::>())?; + let ordered_mergeset = self.sort_blocks( + header + .parents_hash() + .into_iter() + .filter(|header_id| *header_id != new_block_data.selected_parent) + .chain( + blue_blocks + .iter() + .filter(|header| header.id() != new_block_data.selected_parent) + .map(|header| header.id()), + ) + .collect::>() + .into_iter() + .collect::>(), + )?; for blue_candidate in ordered_mergeset.iter().cloned() { let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; @@ -196,11 +210,21 @@ impl< } } - if new_block_data.mergeset_blues.iter().skip(1).cloned().collect::>() != blue_blocks.into_iter().map(|header| header.id()).collect::>() { - if header.number() < 10000000 { - warn!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.into_iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); + if new_block_data + .mergeset_blues + .iter() + .skip(1) + .cloned() + .collect::>() + != blue_blocks + .iter() + .map(|header| header.id()) + .collect::>() + { + if header.number() < 10000000 { + warn!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); } else { - bail!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.into_iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); + bail!("The data of blue set is not equal when executing the block: {:?}, for {:?}, checking data: {:?}", header.id(), blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues); } } @@ -232,7 +256,11 @@ impl< new_block_data.finalize_score_and_work(blue_score, blue_work); - info!("verified the block: {:?}, its ghost data: {:?}", header.id(), new_block_data); + info!( + "verified the block: {:?}, its ghost data: {:?}", + header.id(), + new_block_data + ); Ok(new_block_data) @@ -247,7 +275,6 @@ impl< // let ordered_mergeset = // self.ordered_mergeset_without_selected_parent(new_block_data.selected_parent, &vec![new_block_data.selected_parent])?; - // for blue_candidate in ordered_mergeset { // let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; // if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { @@ -281,7 +308,7 @@ impl< // .checked_add(new_block_data.mergeset_blues.len() as u64) // .expect("blue score size should less than u64"); - // let added_blue_work: BlueWorkType = new_block_data + // let added_blue_work: BlueWorkType = new_block_data // .mergeset_blues // .iter() // .cloned() @@ -307,7 +334,8 @@ impl< } pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { - let mut check_ghostdata = GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); + let mut check_ghostdata = + GhostdagData::new_with_selected_parent(ghostdata.selected_parent, self.k); for blue_candidate in ghostdata.mergeset_blues.iter().skip(1).cloned() { let coloring = self.check_blue_candidate(&check_ghostdata, blue_candidate)?; if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { @@ -317,9 +345,23 @@ impl< } } if ghostdata.mergeset_blues.len() != check_ghostdata.mergeset_blues.len() { - return Err(anyhow::anyhow!("The len of blue set is not equal, for {}, checking data: {}", ghostdata.mergeset_blues.len(), check_ghostdata.mergeset_blues.len())); + return Err(anyhow::anyhow!( + "The len of blue set is not equal, for {}, checking data: {}", + ghostdata.mergeset_blues.len(), + check_ghostdata.mergeset_blues.len() + )); } - if ghostdata.mergeset_blues.iter().cloned().collect::>() != check_ghostdata.mergeset_blues.iter().cloned().collect::>() { + if ghostdata + .mergeset_blues + .iter() + .cloned() + .collect::>() + != check_ghostdata + .mergeset_blues + .iter() + .cloned() + .collect::>() + { return Err(anyhow::anyhow!("The blue set is not equal")); } @@ -349,9 +391,14 @@ impl< .checked_add(added_blue_work) .expect("blue work should less than u256"); - check_ghostdata.finalize_score_and_work(blue_score, blue_work); + check_ghostdata.finalize_score_and_work(blue_score, blue_work); - ensure!(check_ghostdata.to_compact() == ghostdata.to_compact(), "check_ghostdata: {:?} is not the same as ghostdata: {:?}", check_ghostdata.to_compact(), ghostdata.to_compact()); + ensure!( + check_ghostdata.to_compact() == ghostdata.to_compact(), + "check_ghostdata: {:?} is not the same as ghostdata: {:?}", + check_ghostdata.to_compact(), + ghostdata.to_compact() + ); Ok(()) } @@ -516,8 +563,11 @@ impl< }); Ok(sorted_blocks) } - - pub fn sort_blocks_for_work_type(&self, blocks: impl IntoIterator) -> Result> { + + pub fn sort_blocks_for_work_type( + &self, + blocks: impl IntoIterator, + ) -> Result> { let mut sorted_blocks: Vec = blocks.into_iter().collect(); sorted_blocks.sort_by_cached_key(|block| { diff --git a/flexidag/src/types/ordering.rs b/flexidag/src/types/ordering.rs index e903082f09..3b6d1fadb5 100644 --- a/flexidag/src/types/ordering.rs +++ b/flexidag/src/types/ordering.rs @@ -61,7 +61,8 @@ impl PartialOrd for SortableBlockWithWorkType { impl Ord for SortableBlockWithWorkType { fn cmp(&self, other: &Self) -> Ordering { - other.blue_work + other + .blue_work .cmp(&self.blue_work) .then_with(|| other.hash.cmp(&self.hash)) } diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 00561ef00a..e3208e7bcc 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -4,18 +4,28 @@ use anyhow::{bail, format_err, Ok, Result}; use starcoin_crypto::HashValue as Hash; use starcoin_dag::{ - blockdag::{BlockDAG, MineNewDagBlockInfo}, consensusdb::{ + blockdag::{BlockDAG, MineNewDagBlockInfo}, + consensusdb::{ consenses_state::{DagState, DagStateReader, DagStateStore}, schemadb::{ - DbReachabilityStore, GhostdagStoreReader, ReachabilityStore, ReachabilityStoreReader, RelationsStore, RelationsStoreReader + DbReachabilityStore, GhostdagStoreReader, ReachabilityStore, ReachabilityStoreReader, + RelationsStore, RelationsStoreReader, }, - }, ghostdag, reachability::{inquirer, ReachabilityError}, types::{ghostdata::GhostdagData, interval::Interval} + }, + reachability::{inquirer, ReachabilityError}, + types::{ghostdata::GhostdagData, interval::Interval}, }; use starcoin_logger::prelude::debug; -use starcoin_types::{block::{BlockHeader, BlockHeaderBuilder, BlockNumber}, blockhash::{BlockHashMap, HashKTypeMap, KType}}; +use starcoin_types::{ + block::{BlockHeader, BlockHeaderBuilder, BlockNumber}, + blockhash::{BlockHashMap, HashKTypeMap, KType}, +}; use std::{ - io::Read, ops::{Deref, DerefMut}, sync::Arc, time::Instant, vec + ops::{Deref, DerefMut}, + sync::Arc, + time::Instant, + vec, }; #[test] @@ -1052,31 +1062,59 @@ fn test_verification_blue_block() -> anyhow::Result<()> { &mut dag, )?; - // let's obser the blue scores which show how blue the tips are let observer1 = dag.ghostdata(&[block_red_3.id()])?; println!("observer 1 data: {:?}, ", observer1); let observer2 = dag.ghostdata(&[block_red_3.id(), block_main_5.id()])?; println!("observer 2 dag data: {:?}, ", observer2); - assert!(dag.ghost_dag_manager().check_ghostdata_blue_block(&observer2).is_ok()); + assert!(dag + .ghost_dag_manager() + .check_ghostdata_blue_block(&observer2) + .is_ok()); let mut false_observer2 = observer2.clone(); - let red_block_id = false_observer2.mergeset_reds.first().expect("the k is wrong, modify it to create a red block!").clone(); + let red_block_id = *false_observer2 + .mergeset_reds + .first() + .expect("the k is wrong, modify it to create a red block!"); if red_block_id == block_red_2.id() { - false_observer2.mergeset_blues = Arc::new(vec![red_block_id].into_iter().chain(false_observer2.mergeset_blues.iter().cloned().filter(|id| { - *id != block_red_2_1.id() - })).collect()); + false_observer2.mergeset_blues = Arc::new( + vec![red_block_id] + .into_iter() + .chain( + false_observer2 + .mergeset_blues + .iter() + .cloned() + .filter(|id| *id != block_red_2_1.id()), + ) + .collect(), + ); false_observer2.mergeset_reds = Arc::new(vec![block_red_2_1.id()]); } else { - false_observer2.mergeset_blues = Arc::new(vec![red_block_id].into_iter().chain(false_observer2.mergeset_blues.iter().cloned().filter(|id| { - *id != block_red_2.id() - })).collect()); + false_observer2.mergeset_blues = Arc::new( + vec![red_block_id] + .into_iter() + .chain( + false_observer2 + .mergeset_blues + .iter() + .cloned() + .filter(|id| *id != block_red_2.id()), + ) + .collect(), + ); false_observer2.mergeset_reds = Arc::new(vec![block_red_2.id()]); } - let check_error = dag.ghost_dag_manager().check_ghostdata_blue_block(&false_observer2); - println!("check error: {:?} after the blue block turns red and the red turns blue maliciously", check_error); + let check_error = dag + .ghost_dag_manager() + .check_ghostdata_blue_block(&false_observer2); + println!( + "check error: {:?} after the blue block turns red and the red turns blue maliciously", + check_error + ); assert!(check_error.is_err()); let observer3 = dag.ghostdata(&[block_main_5.id()])?; @@ -1088,30 +1126,89 @@ fn test_verification_blue_block() -> anyhow::Result<()> { // assert_eq!(observer3.blue_score, observer2.blue_score); // assert_eq!(observer3.selected_parent, observer2.selected_parent); - let normal_block = add_and_print(6, block_main_5.id(), vec![block_main_5.id(), block_red_3.id()], genesis.parent_hash(), &mut dag)?; - assert_eq!(observer2, dag.ghostdata_by_hash(normal_block.id())?.expect("the data cannot be none").as_ref().clone()); + let normal_block = add_and_print( + 6, + block_main_5.id(), + vec![block_main_5.id(), block_red_3.id()], + genesis.parent_hash(), + &mut dag, + )?; + assert_eq!( + observer2, + dag.ghostdata_by_hash(normal_block.id())? + .expect("the data cannot be none") + .as_ref() + .clone() + ); - let makeup_ghostdata = GhostdagData::new(observer2.blue_score, observer2.blue_work, observer2.selected_parent, observer2.mergeset_blues.clone(), Arc::new(vec![]), HashKTypeMap::new(BlockHashMap::::new())); - dag.ghost_dag_manager().check_ghostdata_blue_block(&makeup_ghostdata)?; - let makeup_block = add_and_print_with_ghostdata(6, block_main_5.id(), vec![block_main_5.id(), block_red_3.id()], genesis.parent_hash(), &mut dag, makeup_ghostdata.clone())?; + let makeup_ghostdata = GhostdagData::new( + observer2.blue_score, + observer2.blue_work, + observer2.selected_parent, + observer2.mergeset_blues.clone(), + Arc::new(vec![]), + HashKTypeMap::new(BlockHashMap::::new()), + ); + dag.ghost_dag_manager() + .check_ghostdata_blue_block(&makeup_ghostdata)?; + let makeup_block = add_and_print_with_ghostdata( + 6, + block_main_5.id(), + vec![block_main_5.id(), block_red_3.id()], + genesis.parent_hash(), + &mut dag, + makeup_ghostdata.clone(), + )?; - let block_from_normal = add_and_print(7, normal_block.id(), vec![normal_block.id()], genesis.parent_hash(), &mut dag)?; - let block_from_makeup = add_and_print(7, makeup_block.id(), vec![makeup_block.id()], genesis.parent_hash(), &mut dag)?; + let block_from_normal = add_and_print( + 7, + normal_block.id(), + vec![normal_block.id()], + genesis.parent_hash(), + &mut dag, + )?; + let block_from_makeup = add_and_print( + 7, + makeup_block.id(), + vec![makeup_block.id()], + genesis.parent_hash(), + &mut dag, + )?; - let ghostdag_data_from_normal = dag.ghostdata_by_hash(block_from_normal.id())?.expect("the data cannot be none").as_ref().clone(); - let ghostdag_data_from_makeup = dag.ghostdata_by_hash(block_from_makeup.id())?.expect("the data cannot be none").as_ref().clone(); + let ghostdag_data_from_normal = dag + .ghostdata_by_hash(block_from_normal.id())? + .expect("the data cannot be none") + .as_ref() + .clone(); + let ghostdag_data_from_makeup = dag + .ghostdata_by_hash(block_from_makeup.id())? + .expect("the data cannot be none") + .as_ref() + .clone(); println!("normal: {:?}", ghostdag_data_from_normal); println!("makeup: {:?}", ghostdag_data_from_makeup); - assert_eq!(ghostdag_data_from_makeup.blue_score, ghostdag_data_from_normal.blue_score); + assert_eq!( + ghostdag_data_from_makeup.blue_score, + ghostdag_data_from_normal.blue_score + ); - dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_normal)?; - dag.ghost_dag_manager().check_ghostdata_blue_block(&ghostdag_data_from_makeup)?; + dag.ghost_dag_manager() + .check_ghostdata_blue_block(&ghostdag_data_from_normal)?; + dag.ghost_dag_manager() + .check_ghostdata_blue_block(&ghostdag_data_from_makeup)?; let together_mine = dag.ghostdata(&[block_from_normal.id(), block_from_makeup.id()])?; - let mine_together = add_and_print(8, together_mine.selected_parent, vec![block_from_normal.id(), block_from_makeup.id()], genesis.parent_hash(), &mut dag)?; + let mine_together = add_and_print( + 8, + together_mine.selected_parent, + vec![block_from_normal.id(), block_from_makeup.id()], + genesis.parent_hash(), + &mut dag, + )?; let together_ghost_data = dag.storage.ghost_dag_store.get_data(mine_together.id())?; - dag.ghost_dag_manager().check_ghostdata_blue_block(&together_ghost_data)?; + dag.ghost_dag_manager() + .check_ghostdata_blue_block(&together_ghost_data)?; anyhow::Result::Ok(()) } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index bb5860ab2c..0d5ae0a43c 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -10,5 +10,5 @@ pub mod sync_metrics; pub mod tasks; pub mod txn_sync; +pub mod parallel; pub mod verified_rpc_client; -pub mod parallel; \ No newline at end of file diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index 9bc9f716f6..c9eae33f46 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -1,7 +1,6 @@ use std::sync::Arc; -use parking_lot::RwLock; -use starcoin_chain::{verifier::{DagVerifier, DagVerifierWithGhostData}, BlockChain, ChainReader}; +use starcoin_chain::{verifier::DagVerifierWithGhostData, BlockChain, ChainReader}; use starcoin_chain_api::ExecutedBlock; use starcoin_config::TimeService; use starcoin_crypto::HashValue; @@ -11,16 +10,15 @@ use starcoin_logger::prelude::{error, info}; use starcoin_storage::Store; use starcoin_types::block::{Block, BlockHeader}; use tokio::{ - sync::mpsc::{self, Receiver, Sender}, task::JoinHandle, time::{timeout, Duration} + sync::mpsc::{self, Receiver, Sender}, + task::JoinHandle, }; -use crate::tasks::continue_execute_absent_block::ContinueChainOperator; - #[derive(Debug)] pub enum ExecuteState { Executing(HashValue), - Executed(ExecutedBlock), - Error(BlockHeader), + Executed(Box), + Error(Box), Closed, } @@ -88,7 +86,7 @@ impl DagBlockExecutor { ); match self .sender - .send(ExecuteState::Error(header.clone())) + .send(ExecuteState::Error(Box::new(header.clone()))) .await { Ok(_) => (), @@ -104,16 +102,26 @@ impl DagBlockExecutor { match chain { None => { - chain = match BlockChain::new(self.time_service.clone(), block.header().parent_hash(), self.storage.clone(), self.vm_metrics.clone(), self.dag.clone()) { + chain = match BlockChain::new( + self.time_service.clone(), + block.header().parent_hash(), + self.storage.clone(), + self.vm_metrics.clone(), + self.dag.clone(), + ) { Ok(new_chain) => Some(new_chain), Err(e) => { - error!("failed to create chain for block: {:?} for {:?}", block.header().id(), e); + error!( + "failed to create chain for block: {:?} for {:?}", + block.header().id(), + e + ); return; } } } Some(old_chain) => { - if old_chain.status().head().id() != block.header().parent_hash(){ + if old_chain.status().head().id() != block.header().parent_hash() { chain = match old_chain.fork(block.header().parent_hash()) { Ok(new_chain) => Some(new_chain), Err(e) => { @@ -127,8 +135,16 @@ impl DagBlockExecutor { } } - info!("sync parallel worker {:p} will execute block: {:?}", &self, block.header().id()); - match chain.as_mut().expect("it cannot be none!").apply_with_verifier::(block) { + info!( + "sync parallel worker {:p} will execute block: {:?}", + &self, + block.header().id() + ); + match chain + .as_mut() + .expect("it cannot be none!") + .apply_with_verifier::(block) + { Ok(executed_block) => { info!( "succeed to execute block: number: {:?}, id: {:?}", @@ -137,7 +153,7 @@ impl DagBlockExecutor { ); match self .sender - .send(ExecuteState::Executed(executed_block)) + .send(ExecuteState::Executed(Box::new(executed_block))) .await { Ok(_) => tokio::task::yield_now().await, @@ -155,7 +171,11 @@ impl DagBlockExecutor { "failed to execute block: {:?}, for reason: {:?}", header, e ); - match self.sender.send(ExecuteState::Error(header.clone())).await { + match self + .sender + .send(ExecuteState::Error(Box::new(header.clone()))) + .await + { Ok(_) => (), Err(e) => { error!( diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index a83ea41396..a24b7e0b14 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -1,16 +1,20 @@ -use std::{ops::Deref, sync::Arc, vec}; +use std::{sync::Arc, vec}; use starcoin_config::TimeService; -use starcoin_crypto::HashValue; -use starcoin_dag::{blockdag::BlockDAG, consensusdb::schema::ValueCodec, reachability::inquirer}; +use starcoin_dag::{blockdag::BlockDAG, consensusdb::schema::ValueCodec}; use starcoin_executor::VMMetrics; -use starcoin_logger::prelude::{error, info}; -use starcoin_network::worker; +use starcoin_logger::prelude::info; use starcoin_storage::Store; -use starcoin_types::block::{Block, BlockHeader}; -use tokio::{sync::mpsc::{self, Receiver, Sender}, task::JoinHandle}; +use starcoin_types::block::Block; +use tokio::{ + sync::mpsc::{self, Receiver, Sender}, + task::JoinHandle, +}; -use crate::{store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::{self, SyncDagStore}}, tasks::continue_execute_absent_block::ContinueChainOperator}; +use crate::{ + store::{sync_absent_ancestor::DagSyncBlock, sync_dag_store::SyncDagStore}, + tasks::continue_execute_absent_block::ContinueChainOperator, +}; use super::executor::{DagBlockExecutor, ExecuteState}; @@ -58,7 +62,9 @@ impl<'a> DagBlockSender<'a> { for executor in &mut self.executors { match &executor.state { ExecuteState::Executing(header_id) => { - if *header_id == block.header().parent_hash() || block.header.parents_hash().contains(header_id) { + if *header_id == block.header().parent_hash() + || block.header.parents_hash().contains(header_id) + { executor.state = ExecuteState::Executing(block.id()); executor.sender_to_executor.send(block.clone()).await?; return anyhow::Ok(true); @@ -103,7 +109,8 @@ impl<'a> DagBlockSender<'a> { } // no suitable worker found, create a new worker - let (sender_to_main, receiver_from_executor) = mpsc::channel::(self.queue_size); + let (sender_to_main, receiver_from_executor) = + mpsc::channel::(self.queue_size); let (sender_to_worker, executor) = DagBlockExecutor::new( sender_to_main, self.queue_size, @@ -130,37 +137,27 @@ impl<'a> DagBlockSender<'a> { Ok(()) } - + async fn flush_executor_state(&mut self) -> anyhow::Result<()> { for worker in &mut self.executors { match worker.receiver_from_executor.try_recv() { Ok(state) => { - match state { - ExecuteState::Executed(executed_block) => { - info!("finish to execute block {:?}", executed_block.header()); - self.notifier.notify(executed_block.clone())?; - worker.state = ExecuteState::Executed(executed_block); - } - _ => () - } - } - Err(e) => { - match e { - mpsc::error::TryRecvError::Empty => (), - mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + if let ExecuteState::Executed(executed_block) = state { + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify((*executed_block).clone())?; + worker.state = ExecuteState::Executed(executed_block); } } + Err(e) => match e { + mpsc::error::TryRecvError::Empty => (), + mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + }, } } let len = self.executors.len(); - self.executors.retain(|worker| { - if let ExecuteState::Closed = worker.state { - false - } else { - true - } - }); + self.executors + .retain(|worker| !matches!(worker.state, ExecuteState::Closed)); if len != self.executors.len() { info!("sync workers count: {:?}", self.executors.len()); @@ -169,16 +166,13 @@ impl<'a> DagBlockSender<'a> { anyhow::Ok(()) } - async fn wait_for_finish(mut self) -> anyhow::Result<()> { + async fn wait_for_finish(self) -> anyhow::Result<()> { for mut worker in self.executors { drop(worker.sender_to_executor); while let Some(state) = worker.receiver_from_executor.recv().await { - match state { - ExecuteState::Executed(executed_block) => { - info!("finish to execute block {:?}", executed_block.header()); - self.notifier.notify(executed_block.clone())?; - } - ExecuteState::Executing(_) | ExecuteState::Error(_) | ExecuteState::Closed => (), + if let ExecuteState::Executed(executed_block) = state { + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify(*executed_block)?; } } worker.handle.await?; diff --git a/sync/src/store/sync_dag_store.rs b/sync/src/store/sync_dag_store.rs index 7d90b8d894..8d3dca1492 100644 --- a/sync/src/store/sync_dag_store.rs +++ b/sync/src/store/sync_dag_store.rs @@ -1,10 +1,9 @@ -use std::{ops::DerefMut, path::Path, sync::Arc}; +use std::{path::Path, sync::Arc}; use anyhow::format_err; -use parking_lot::RwLock; use starcoin_config::{temp_dir, RocksdbConfig, StorageConfig}; use starcoin_crypto::HashValue; -use starcoin_dag::{consensusdb::{prelude::StoreError, schemadb::{DbReachabilityStore, MemoryReachabilityStore, ReachabilityStore, REACHABILITY_DATA_CF}}, reachability::inquirer}; +use starcoin_dag::consensusdb::{prelude::StoreError, schemadb::REACHABILITY_DATA_CF}; use starcoin_logger::prelude::error; use starcoin_storage::db_storage::{DBStorage, SchemaIterator}; use starcoin_types::block::{Block, BlockNumber}; @@ -112,7 +111,7 @@ impl SyncDagStore { block: Some(block.clone()), }]) .map_err(|e| format_err!("Failed to save absent block: {:?}", e))?; - + Ok(()) } _ => Err(format_err!( diff --git a/sync/src/store/tests.rs b/sync/src/store/tests.rs index 1b6901c4a0..881b1badc0 100644 --- a/sync/src/store/tests.rs +++ b/sync/src/store/tests.rs @@ -1,18 +1,6 @@ -use std::{ - ops::{Deref, DerefMut}, - sync::Arc, - u64, -}; - use anyhow::Ok; -use parking_lot::RwLock; use starcoin_crypto::HashValue; -use starcoin_dag::{ - blockdag::BlockDAG, consensusdb::{ - schema::{KeyCodec, ValueCodec}, - schemadb::MemoryReachabilityStore, - }, reachability::inquirer, types::interval::Interval -}; +use starcoin_dag::consensusdb::schema::{KeyCodec, ValueCodec}; use starcoin_types::{ account_address::AccountAddress, block::{Block, BlockBody, BlockHeader, BlockHeaderBuilder, BlockHeaderExtra, BlockNumber}, @@ -20,6 +8,7 @@ use starcoin_types::{ transaction::{authenticator::AuthenticationKey, SignedUserTransaction}, U256, }; +use std::u64; use crate::store::sync_absent_ancestor::DagSyncBlockKey; @@ -80,7 +69,6 @@ fn build_version_0_block(number: BlockNumber) -> Block { #[test] fn test_sync_dag_absent_store() -> anyhow::Result<()> { - let dag = BlockDAG::create_for_testing()?; let sync_dag_store = SyncDagStore::create_for_testing()?; // write and read @@ -152,7 +140,6 @@ fn test_sync_dag_absent_store() -> anyhow::Result<()> { #[test] fn test_write_read_in_order() -> anyhow::Result<()> { - let dag = BlockDAG::create_for_testing()?; let sync_dag_store = SyncDagStore::create_for_testing()?; // write and read diff --git a/sync/src/sync.rs b/sync/src/sync.rs index 535d7be53a..cb1cdd937e 100644 --- a/sync/src/sync.rs +++ b/sync/src/sync.rs @@ -29,7 +29,7 @@ use starcoin_sync_api::{ SyncProgressRequest, SyncServiceHandler, SyncStartRequest, SyncStatusRequest, SyncTarget, }; use starcoin_txpool::TxPoolService; -use starcoin_types::block::{Block, BlockIdAndNumber}; +use starcoin_types::block::BlockIdAndNumber; use starcoin_types::startup_info::ChainStatus; use starcoin_types::sync_status::SyncStatus; use starcoin_types::system_events::{NewHeadBlock, SyncStatusChangeEvent, SystemStarted}; diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index a32aba529d..84d028f98d 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -454,20 +454,26 @@ where self.find_absent_ancestor(vec![block_header.clone()]) .await?; - if block_header.number() % 10000 == 0 || block_header.number() >= self.target.target_id.number() { + if block_header.number() % 10000 == 0 + || block_header.number() >= self.target.target_id.number() + { let parallel_execute = DagBlockSender::new( - self.sync_dag_store.clone(), + self.sync_dag_store.clone(), 100000, - self.chain.time_service(), - self.local_store.clone(), - None, self.chain.dag(), self); + self.chain.time_service(), + self.local_store.clone(), + None, + self.chain.dag(), + self, + ); parallel_execute.process_absent_blocks().await?; anyhow::Ok(ParallelSign::Executed) } else { - self.local_store.save_dag_sync_block(starcoin_storage::block::DagSyncBlock { - block: block.clone(), - children: vec![], - })?; + self.local_store + .save_dag_sync_block(starcoin_storage::block::DagSyncBlock { + block: block.clone(), + children: vec![], + })?; self.sync_dag_store.save_block(block)?; anyhow::Ok(ParallelSign::NeedMoreBlocks) } @@ -650,12 +656,11 @@ where let timestamp = block.header().timestamp(); - let block_info = - if self.chain.has_dag_block(block.header().id())? { - block_info - } else { - None - }; + let block_info = if self.chain.has_dag_block(block.header().id())? { + block_info + } else { + None + }; let (block_info, action) = match block_info { Some(block_info) => { diff --git a/sync/src/tasks/inner_sync_task.rs b/sync/src/tasks/inner_sync_task.rs index ba25d78b24..0128200f68 100644 --- a/sync/src/tasks/inner_sync_task.rs +++ b/sync/src/tasks/inner_sync_task.rs @@ -4,7 +4,6 @@ use starcoin_accumulator::node::AccumulatorStoreType; use starcoin_chain::BlockChain; use starcoin_dag::blockdag::BlockDAG; use starcoin_executor::VMMetrics; -use starcoin_logger::prelude::{error, info}; use starcoin_network_rpc_api::{MAX_BLOCK_IDS_REQUEST_SIZE, MAX_BLOCK_REQUEST_SIZE}; use starcoin_storage::Store; use starcoin_sync_api::SyncTarget; @@ -146,7 +145,7 @@ where vm_metrics, self.dag.clone(), )?; - let mut block_collector = BlockCollector::new_with_handle( + let block_collector = BlockCollector::new_with_handle( current_block_info.clone(), self.target.clone(), chain, diff --git a/sync/src/tasks/mock.rs b/sync/src/tasks/mock.rs index 15a59bb79c..96b9822d1b 100644 --- a/sync/src/tasks/mock.rs +++ b/sync/src/tasks/mock.rs @@ -155,7 +155,8 @@ impl SyncNodeMocker { None, ); let peer_selector = PeerSelector::new(vec![peer_info], PeerStrategy::default(), None); - let sync_dag_store = SyncDagStore::create_for_testing().context("Failed to create SyncDagStore for testing")?; + let sync_dag_store = SyncDagStore::create_for_testing() + .context("Failed to create SyncDagStore for testing")?; Ok(Self::new_inner( peer_id, chain, From d1edfb74bf8703e54d1344cb946a3ccda503bb66 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 5 Sep 2024 11:49:21 +0800 Subject: [PATCH 24/60] rebase master set the number 4500000 for vega updating --- flexidag/src/ghostdag/protocol.rs | 68 ------------------------------- types/src/block/mod.rs | 2 +- 2 files changed, 1 insertion(+), 69 deletions(-) diff --git a/flexidag/src/ghostdag/protocol.rs b/flexidag/src/ghostdag/protocol.rs index 96a6abe37c..c219be7af4 100644 --- a/flexidag/src/ghostdag/protocol.rs +++ b/flexidag/src/ghostdag/protocol.rs @@ -263,74 +263,6 @@ impl< ); Ok(new_block_data) - - // let mut new_block_data = GhostdagData::new_with_selected_parent(header.parent_hash(), self.k); - // let mut mergetset = header.parents_hash().into_iter().filter(|header_id| { - // *header_id != header.parent_hash() - // }).chain(blue_blocks.into_iter().filter(|header| { - // header.id() != new_block_data.selected_parent - // }).map(|header| header.id())).collect::>().into_iter().collect::>(); - // info!("jacktest: merget set = {:?}", mergetset); - // mergetset = self.sort_blocks(mergetset.into_iter())?; - // let ordered_mergeset = - // self.ordered_mergeset_without_selected_parent(new_block_data.selected_parent, &vec![new_block_data.selected_parent])?; - - // for blue_candidate in ordered_mergeset { - // let coloring = self.check_blue_candidate(&new_block_data, blue_candidate)?; - // if let ColoringOutput::Blue(blue_anticone_size, blues_anticone_sizes) = coloring { - // new_block_data.add_blue(blue_candidate, blue_anticone_size, &blues_anticone_sizes); - // } else { - // new_block_data.add_red(blue_candidate); - // } - // } - // let mut valid_mergeset_blues = vec![new_block_data.selected_parent]; - // valid_mergeset_blues.append(&mut new_block_data.mergeset_blues.iter().cloned().collect::>().into_iter().filter(|header_id| { - // *header_id != new_block_data.selected_parent - // }).collect()); - // *BlockHashes::make_mut(&mut new_block_data.mergeset_blues) = valid_mergeset_blues; - // *BlockHashes::make_mut(&mut new_block_data.mergeset_reds) = new_block_data.mergeset_reds.iter().cloned().collect::>().into_iter().collect::>(); - // let selectd_ghostdata = self.ghostdag(&vec![header.parent_hash()])?; - // if blue_blocks.len() != new_block_data.mergeset_blues.len().saturating_sub(1) { - // return Err(anyhow::anyhow!("The len of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues)); - // } - - // let mut expected_blue_blocks = blue_blocks.iter().map(|header| header.id()).collect::>(); - // expected_blue_blocks.insert(new_block_data.selected_parent); - // if expected_blue_blocks != new_block_data.mergeset_blues.iter().cloned().collect::>() { - // // return Err(anyhow::anyhow!("The data of blue set is not equal, for {:?}, checking data: {:?}", blue_blocks.iter().map(|header| header.id()).collect::>(), new_block_data.mergeset_blues)); - // info!("The data of blue set is not equal, for {:?}, checking data: {:?}, run ghost protocol to get the valid data", blue_blocks, new_block_data.mergeset_blues); - // return Ok(self.ghostdag(&header.parents_hash())?); - // } - - // let blue_score = self - // .ghostdag_store - // .get_blue_score(header.parent_hash())? - // .checked_add(new_block_data.mergeset_blues.len() as u64) - // .expect("blue score size should less than u64"); - - // let added_blue_work: BlueWorkType = new_block_data - // .mergeset_blues - // .iter() - // .cloned() - // .map(|hash| { - // self.headers_store - // .get_difficulty(hash) - // .unwrap_or_else(|err| { - // error!("Failed to get difficulty of block: {}, {}", hash, err); - // 0.into() - // }) - // }) - // .sum(); - - // let blue_work = self - // .ghostdag_store - // .get_blue_work(new_block_data.selected_parent)? - // .checked_add(added_blue_work) - // .expect("blue work should less than u256"); - - // new_block_data.finalize_score_and_work(blue_score, blue_work); - - // Ok(new_block_data) } pub fn check_ghostdata_blue_block(&self, ghostdata: &GhostdagData) -> Result<()> { diff --git a/types/src/block/mod.rs b/types/src/block/mod.rs index 68a6995052..056051e01e 100644 --- a/types/src/block/mod.rs +++ b/types/src/block/mod.rs @@ -510,7 +510,7 @@ impl BlockHeader { if number == 0 { false } else if chain_id.is_vega() { - number >= 3300000 + number >= 4500000 } else if chain_id.is_halley() { number >= 3100000 } else if chain_id.is_proxima() { From 532d9b6e52308e47a29ebc563c55281d842f87df Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 5 Sep 2024 12:09:46 +0800 Subject: [PATCH 25/60] remove some commented code --- sync/src/sync.rs | 14 -------------- sync/src/tasks/block_sync_task.rs | 24 ------------------------ sync/src/tasks/inner_sync_task.rs | 28 ---------------------------- 3 files changed, 66 deletions(-) diff --git a/sync/src/sync.rs b/sync/src/sync.rs index cb1cdd937e..4778a9a566 100644 --- a/sync/src/sync.rs +++ b/sync/src/sync.rs @@ -618,20 +618,6 @@ impl EventHandler for SyncService { } } -// #[derive(Debug, Clone)] -// pub struct SaveSyncBlock { -// pub block: Block, -// } - -// impl EventHandler for SyncService { -// fn handle_event(&mut self, msg: SaveSyncBlock, _ctx: &mut ServiceContext) { -// let block = msg.block; -// if let Err(e) = self.sync_dag_store.save_block(block) { -// error!("[sync] Save absent block error: {:?}", e); -// } -// } -// } - impl ServiceHandler for SyncService { fn handle(&mut self, _msg: SyncStatusRequest, _ctx: &mut ServiceContext) -> SyncStatus { self.sync_status.clone() diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index 84d028f98d..f171525b70 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -477,30 +477,6 @@ where self.sync_dag_store.save_block(block)?; anyhow::Ok(ParallelSign::NeedMoreBlocks) } - - // let sync_dag_store = self.sync_dag_store.clone(); - // let mut absent_block_iter = sync_dag_store - // .iter_at_first() - // .context("Failed to create iterator for sync_dag_store")?; - // loop { - // debug!("start to read local absent block and try to execute the dag if its parents are ready."); - // let mut local_absent_block = vec![]; - // match self.read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) - // { - // anyhow::Result::Ok(_) => { - // if local_absent_block.is_empty() { - // info!("absent block is empty, continue to sync"); - // break; - // } - // self.execute_absent_block(&mut local_absent_block) - // .context("Failed to execute absent block")?; - // } - // Err(e) => { - // error!("failed to read local absent block, error: {:?}", e); - // return Err(e); - // } - // } - // } }; async_std::task::block_on(fut) } diff --git a/sync/src/tasks/inner_sync_task.rs b/sync/src/tasks/inner_sync_task.rs index 0128200f68..7d91778143 100644 --- a/sync/src/tasks/inner_sync_task.rs +++ b/sync/src/tasks/inner_sync_task.rs @@ -157,34 +157,6 @@ where self.sync_dag_store.clone(), ); - // let mut absent_block_iter = self.sync_dag_store.iter_at_first()?; - // loop { - // let mut local_absent_block = vec![]; - // match block_collector - // .read_local_absent_block(&mut absent_block_iter, &mut local_absent_block) - // { - // anyhow::Result::Ok(_) => { - // if local_absent_block.is_empty() { - // info!("absent block is empty, continue to sync"); - // break; - // } - // match block_collector.execute_absent_block(&mut local_absent_block) { - // anyhow::Result::Ok(_) => (), - // Err(e) => { - // error!("failed to execute absent block, error: {:?}, break from the continuing block execution", e); - // break; - // } - // } - // } - // Err(e) => { - // error!("failed to read local absent block, error: {:?}, break from the continuing block execution", e); - // break; - // } - // } - // } - // // clear the dag sync if fork happened - // self.sync_dag_store.delete_all_dag_sync_block()?; - Ok(TaskGenerator::new( block_sync_task, buffer_size, From d46c9adb0a95fa80c0c6cecea4a25bf012d2b3fc Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 5 Sep 2024 16:14:59 +0800 Subject: [PATCH 26/60] fix: return continue if the dag block is ready --- sync/src/parallel/executor.rs | 16 ++++++++--- sync/src/parallel/sender.rs | 45 +++++++++++++++++++++++-------- sync/src/tasks/block_sync_task.rs | 8 +++--- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index c9eae33f46..5279dec192 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -24,7 +24,7 @@ pub enum ExecuteState { pub struct DagBlockExecutor { sender: Sender, - receiver: Receiver, + receiver: Receiver>, time_service: Arc, storage: Arc, vm_metrics: Option, @@ -39,8 +39,8 @@ impl DagBlockExecutor { storage: Arc, vm_metrics: Option, dag: BlockDAG, - ) -> anyhow::Result<(Sender, Self)> { - let (sender_for_main, receiver) = mpsc::channel::(buffer_size); + ) -> anyhow::Result<(Sender>, Self)> { + let (sender_for_main, receiver) = mpsc::channel::>(buffer_size); let executor = Self { sender: sender_to_main, receiver, @@ -69,7 +69,15 @@ impl DagBlockExecutor { let mut chain = None; loop { match self.receiver.recv().await { - Some(block) => { + Some(op_block) => { + let block = match op_block { + Some(block) => block, + None => { + info!("sync worker channel closed"); + drop(self.sender); + return; + } + }; let header = block.header().clone(); loop { diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index a24b7e0b14..ae96282ee3 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -19,7 +19,7 @@ use crate::{ use super::executor::{DagBlockExecutor, ExecuteState}; struct DagBlockWorker { - pub sender_to_executor: Sender, + pub sender_to_executor: Sender>, pub receiver_from_executor: Receiver, pub state: ExecuteState, pub handle: JoinHandle<()>, @@ -66,7 +66,10 @@ impl<'a> DagBlockSender<'a> { || block.header.parents_hash().contains(header_id) { executor.state = ExecuteState::Executing(block.id()); - executor.sender_to_executor.send(block.clone()).await?; + executor + .sender_to_executor + .send(Some(block.clone())) + .await?; return anyhow::Ok(true); } } @@ -80,7 +83,10 @@ impl<'a> DagBlockSender<'a> { match &executor.state { ExecuteState::Executed(_) => { executor.state = ExecuteState::Executing(block.id()); - executor.sender_to_executor.send(block.clone()).await?; + executor + .sender_to_executor + .send(Some(block.clone())) + .await?; return anyhow::Ok(true); } @@ -127,7 +133,7 @@ impl<'a> DagBlockSender<'a> { handle: executor.start_to_execute()?, }); - sender_to_worker.send(block).await?; + sender_to_worker.send(Some(block)).await?; self.flush_executor_state().await?; } @@ -166,15 +172,32 @@ impl<'a> DagBlockSender<'a> { anyhow::Ok(()) } - async fn wait_for_finish(self) -> anyhow::Result<()> { - for mut worker in self.executors { - drop(worker.sender_to_executor); - while let Some(state) = worker.receiver_from_executor.recv().await { - if let ExecuteState::Executed(executed_block) = state { - info!("finish to execute block {:?}", executed_block.header()); - self.notifier.notify(*executed_block)?; + async fn wait_for_finish(mut self) -> anyhow::Result<()> { + // tell the workers to exit + for worker in &self.executors { + worker.sender_to_executor.send(None).await?; + } + + for worker in &mut self.executors { + if let ExecuteState::Closed = worker.state { + continue; + } + + match worker.receiver_from_executor.try_recv() { + Ok(state) => { + if let ExecuteState::Executed(executed_block) = state { + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify(*executed_block)?; + } } + Err(e) => match e { + mpsc::error::TryRecvError::Empty => (), + mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + }, } + } + + for worker in self.executors { worker.handle.await?; } diff --git a/sync/src/tasks/block_sync_task.rs b/sync/src/tasks/block_sync_task.rs index f171525b70..b143d39318 100644 --- a/sync/src/tasks/block_sync_task.rs +++ b/sync/src/tasks/block_sync_task.rs @@ -34,7 +34,7 @@ use super::{BlockConnectAction, BlockConnectedFinishEvent}; enum ParallelSign { NeedMoreBlocks, - Executed, + Continue, } #[derive(Clone, Debug)] @@ -442,7 +442,7 @@ where block_header.id(), block_header.number() ); - return Ok(ParallelSign::NeedMoreBlocks); + return Ok(ParallelSign::Continue); } info!( "the block is a dag block, its id: {:?}, number: {:?}, its parents: {:?}", @@ -467,7 +467,7 @@ where self, ); parallel_execute.process_absent_blocks().await?; - anyhow::Ok(ParallelSign::Executed) + anyhow::Ok(ParallelSign::Continue) } else { self.local_store .save_dag_sync_block(starcoin_storage::block::DagSyncBlock { @@ -607,7 +607,7 @@ where info!("now sync dag block -- ensure_dag_parent_blocks_exist"); match self.ensure_dag_parent_blocks_exist(block.clone())? { ParallelSign::NeedMoreBlocks => return Ok(CollectorState::Need), - ParallelSign::Executed => (), + ParallelSign::Continue => (), } let state = self.check_enough(); if let anyhow::Result::Ok(CollectorState::Enough) = &state { From 7d535d6243e76985e1a0e6c129c184e4e0fa15f4 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 5 Sep 2024 17:17:49 +0800 Subject: [PATCH 27/60] add loop if the connection of the workers are not closed --- sync/src/parallel/sender.rs | 38 ++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index ae96282ee3..f4a5f71cbf 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -178,22 +178,34 @@ impl<'a> DagBlockSender<'a> { worker.sender_to_executor.send(None).await?; } - for worker in &mut self.executors { - if let ExecuteState::Closed = worker.state { - continue; - } + loop { + for worker in &mut self.executors { + if let ExecuteState::Closed = worker.state { + continue; + } - match worker.receiver_from_executor.try_recv() { - Ok(state) => { - if let ExecuteState::Executed(executed_block) = state { - info!("finish to execute block {:?}", executed_block.header()); - self.notifier.notify(*executed_block)?; + match worker.receiver_from_executor.try_recv() { + Ok(state) => { + if let ExecuteState::Executed(executed_block) = state { + info!("finish to execute block {:?}", executed_block.header()); + self.notifier.notify(*executed_block)?; + } } + Err(e) => match e { + mpsc::error::TryRecvError::Empty => (), + mpsc::error::TryRecvError::Disconnected => { + worker.state = ExecuteState::Closed + } + }, } - Err(e) => match e { - mpsc::error::TryRecvError::Empty => (), - mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, - }, + } + + if self + .executors + .iter() + .all(|worker| matches!(worker.state, ExecuteState::Closed)) + { + break; } } From 58fa314dfc100b813db910515f3985f1f1ba1404 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 6 Sep 2024 15:50:51 +0800 Subject: [PATCH 28/60] 3300000 will be version 1 in vega --- types/src/block/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/src/block/mod.rs b/types/src/block/mod.rs index 056051e01e..68a6995052 100644 --- a/types/src/block/mod.rs +++ b/types/src/block/mod.rs @@ -510,7 +510,7 @@ impl BlockHeader { if number == 0 { false } else if chain_id.is_vega() { - number >= 4500000 + number >= 3300000 } else if chain_id.is_halley() { number >= 3100000 } else if chain_id.is_proxima() { From 03981e3d080ddadda38e87bfb992120c5f59356f Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sat, 7 Sep 2024 09:38:17 +0800 Subject: [PATCH 29/60] use selected parent to get he parent --- chain/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 925414f136..58fb3aadc4 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1482,8 +1482,8 @@ impl BlockChain { // Caculate the ghostdata of the virutal node created by all tips. // And the ghostdata.selected of the tips will be the latest head. let block_hash = { - let ghost_of_tips = dag.ghostdata(tips.as_slice())?; - ghost_of_tips.selected_parent + // let ghost_of_tips = dag.ghostdata(tips.as_slice())?; + dag.ghost_dag_manager().find_selected_parent(tips.iter().copied())? }; let (block, block_info) = { let block = self From c5a40937085f6cf461c18b16910e9df91a270d69 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sat, 7 Sep 2024 09:39:08 +0800 Subject: [PATCH 30/60] remove comments --- chain/src/chain.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 58fb3aadc4..b8a06fbc60 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1482,7 +1482,6 @@ impl BlockChain { // Caculate the ghostdata of the virutal node created by all tips. // And the ghostdata.selected of the tips will be the latest head. let block_hash = { - // let ghost_of_tips = dag.ghostdata(tips.as_slice())?; dag.ghost_dag_manager().find_selected_parent(tips.iter().copied())? }; let (block, block_info) = { From 6d27f2ca882bc87a5ebbbf1c266aff393bfe1db7 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sat, 7 Sep 2024 09:40:05 +0800 Subject: [PATCH 31/60] remove bracket --- chain/src/chain.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index b8a06fbc60..b2124f8da7 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1481,9 +1481,7 @@ impl BlockChain { } // Caculate the ghostdata of the virutal node created by all tips. // And the ghostdata.selected of the tips will be the latest head. - let block_hash = { - dag.ghost_dag_manager().find_selected_parent(tips.iter().copied())? - }; + let block_hash = dag.ghost_dag_manager().find_selected_parent(tips.iter().copied())?; let (block, block_info) = { let block = self .storage From 96df6fc5be2be5404c15c6888cd14cceac730a9d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sun, 8 Sep 2024 11:15:56 +0800 Subject: [PATCH 32/60] fix fmt --- chain/src/chain.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index b2124f8da7..d83f16caa9 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1481,7 +1481,9 @@ impl BlockChain { } // Caculate the ghostdata of the virutal node created by all tips. // And the ghostdata.selected of the tips will be the latest head. - let block_hash = dag.ghost_dag_manager().find_selected_parent(tips.iter().copied())?; + let block_hash = dag + .ghost_dag_manager() + .find_selected_parent(tips.iter().copied())?; let (block, block_info) = { let block = self .storage From 77f24d2d3bacf9d9c6c38f8b7d8db601e2eb3ff5 Mon Sep 17 00:00:00 2001 From: Jack Huang Date: Sun, 21 Jul 2024 16:01:24 +0800 Subject: [PATCH 33/60] add pruning logic and compatible logic fix some test cases --- chain/src/chain.rs | 5 +- chain/src/verifier/mod.rs | 2 +- chain/tests/test_txn_info_and_proof.rs | 139 ++++++++++++++++++ config/src/genesis_config.rs | 3 - flexidag/src/blockdag.rs | 16 +- flexidag/src/consensusdb/consenses_state.rs | 6 +- flexidag/src/prune/pruning_point_manager.rs | 18 ++- flexidag/tests/tests.rs | 3 +- .../src/block_connector/test_illegal_block.rs | 4 +- .../block_connector/test_write_block_chain.rs | 2 + sync/src/tasks/tests_dag.rs | 1 - types/src/block/tests.rs | 47 +++++- vm/types/src/block_metadata/legacy.rs | 2 +- 13 files changed, 227 insertions(+), 21 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index d83f16caa9..7cc411b0c1 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1519,7 +1519,10 @@ impl BlockChain { if self.epoch.end_block_number() == block.header().number() { self.epoch = get_epoch_from_statedb(&self.statedb)?; } - self.dag.save_dag_state(DagState { tips })?; + self.dag.save_dag_state(DagState { + tips, + pruning_point: block.header().pruning_point(), + })?; Ok(executed_block) } } diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index bd8870685c..74fc59869d 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -347,7 +347,6 @@ impl BasicDagVerifier { R: ChainReader, { let parents_hash = new_block_header.parents_hash(); - verify_block!( VerifyBlockField::Header, parents_hash.len() == parents_hash.iter().collect::>().len(), @@ -363,6 +362,7 @@ impl BasicDagVerifier { parents_hash, new_block_header.parent_hash() ); + parents_hash.iter().try_for_each(|parent_hash| { verify_block!( VerifyBlockField::Header, diff --git a/chain/tests/test_txn_info_and_proof.rs b/chain/tests/test_txn_info_and_proof.rs index d902703b93..92e3694f82 100644 --- a/chain/tests/test_txn_info_and_proof.rs +++ b/chain/tests/test_txn_info_and_proof.rs @@ -123,3 +123,142 @@ fn test_transaction_info_and_proof_1() -> Result<()> { ); Ok(()) } + +#[stest::test(timeout = 480)] +fn test_transaction_info_and_proof() -> Result<()> { + let config = Arc::new(NodeConfig::random_for_test()); + let mut block_chain = test_helper::gen_blockchain_for_test(config.net())?; + let mut current_header = block_chain.current_header(); + let miner_account = AccountInfo::random(); + + let mut rng = rand::thread_rng(); + + let block_count: u64 = rng.gen_range(2..10); + let mut seq_number = 0; + let mut all_txns = vec![]; + let mut all_address = HashMap::::new(); + + let genesis_block = block_chain.get_block_by_number(0).unwrap().unwrap(); + //put the genesis txn, the genesis block metadata txn do not generate txn info + + all_txns.push(Transaction::UserTransaction( + genesis_block.body.transactions.first().cloned().unwrap(), + )); + + (0..block_count).for_each(|_block_idx| { + let txn_count: u64 = rng.gen_range(1..10); + let txns: Vec = (0..txn_count) + .map(|_txn_idx| { + let account_address = AccountAddress::random(); + + let txn = peer_to_peer_txn_sent_as_association( + account_address, + seq_number, + 10000, + config.net().time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + config.net(), + ); + all_address.insert(txn.id(), account_address); + seq_number += 1; + txn + }) + .collect(); + + let (template, _) = block_chain + .create_block_template( + *miner_account.address(), + Some(current_header.id()), + txns.clone(), + vec![], + None, + vec![], + HashValue::zero(), + ) + .unwrap(); + + let block = block_chain + .consensus() + .create_block(template, config.net().time_service().as_ref()) + .unwrap(); + debug!("apply block:{:?}", &block); + block_chain.apply(block.clone()).unwrap(); + all_txns.push(Transaction::BlockMetadata( + block.to_metadata(current_header.gas_used()), + )); + all_txns.extend(txns.into_iter().map(Transaction::UserTransaction)); + current_header = block.header().clone(); + }); + + let txn_index = rng.gen_range(0..all_txns.len()); + debug!("all txns len: {}, txn index:{}", all_txns.len(), txn_index); + + for txn_global_index in 0..all_txns.len() { + let txn = all_txns.get(txn_global_index).cloned().unwrap(); + let txn_hash = txn.id(); + let txn_info = block_chain.get_transaction_info(txn_hash)?.ok_or_else(|| { + format_err!( + "Can not get txn info by txn hash:{}, txn:{:?}", + txn_hash, + txn + ) + })?; + + let txn_info_leaf = block_chain + .get_txn_accumulator() + .get_leaf(txn_global_index as u64)? + .unwrap(); + assert_eq!( + txn_info.transaction_info.id(), + txn_info_leaf, + "txn_info hash do not match txn info leaf in accumulator, index: {}", + txn_global_index + ); + + assert_eq!( + txn_info.transaction_global_index, txn_global_index as u64, + "txn_global_index:{}", + txn_global_index + ); + + let account_address = match &txn { + Transaction::UserTransaction(user_txn) => user_txn.sender(), + Transaction::BlockMetadata(metadata_txn) => metadata_txn.author(), + }; + let access_path: Option = Some(AccessPath::resource_access_path( + account_address, + AccountResource::struct_tag(), + )); + + let events = block_chain + .get_events(txn_info.transaction_info.id())? + .unwrap(); + + for (event_index, event) in events.into_iter().enumerate() { + let txn_proof = block_chain + .get_transaction_proof( + current_header.id(), + txn_global_index as u64, + Some(event_index as u64), + access_path.clone(), + )? + .expect("get transaction proof return none"); + assert_eq!(&event, &txn_proof.event_proof.as_ref().unwrap().event); + + let result = txn_proof.verify( + current_header.txn_accumulator_root(), + txn_global_index as u64, + Some(event_index as u64), + access_path.clone(), + ); + + assert!( + result.is_ok(), + "txn index: {}, {:?} verify failed, reason: {:?}", + txn_global_index, + txn_proof, + result.err().unwrap() + ); + } + } + Ok(()) +} diff --git a/config/src/genesis_config.rs b/config/src/genesis_config.rs index 50a1136ffe..e479c4de8f 100644 --- a/config/src/genesis_config.rs +++ b/config/src/genesis_config.rs @@ -654,13 +654,10 @@ pub struct GenesisConfig { pub time_service_type: TimeServiceType, /// transaction timeout pub transaction_timeout: u64, - /// pruning depth pub pruning_depth: u64, - /// pruning finality pub pruning_finality: u64, - /// block header version pub block_header_version: starcoin_types::block::Version, } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 054f01af07..0194049775 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -93,6 +93,14 @@ impl BlockDAG { Ok(Self::new(k, dag_storage)) } + pub fn new_by_config(db_path: &Path) -> anyhow::Result { + let config = FlexiDagStorageConfig::create_with_params(1, RocksdbConfig::default()); + let db = FlexiDagStorage::create_from_path(db_path, config)?; + let dag = Self::new(DEFAULT_GHOSTDAG_K, db); + Ok(dag) +>>>>>>> 2ba8ddcfe (add pruning logic and compatible logic) + } + pub fn has_dag_block(&self, hash: Hash) -> anyhow::Result { Ok(self.storage.header_store.has(hash)?) } @@ -116,6 +124,7 @@ impl BlockDAG { self.commit(genesis, origin)?; self.save_dag_state(DagState { tips: vec![genesis_id], + pruning_point: genesis_id, })?; Ok(origin) } @@ -443,7 +452,6 @@ impl BlockDAG { ) -> anyhow::Result { let dag_state = self.get_dag_state()?; let ghostdata = self.ghost_dag_manager().ghostdag(&dag_state.tips)?; - anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, blue_blocks: (*ghostdata.mergeset_blues).clone(), @@ -486,9 +494,13 @@ impl BlockDAG { block_header: &BlockHeader, genesis_id: HashValue, ) -> anyhow::Result<()> { + let dag_state = DagState { + tips: block_header.parents(), + pruning_point: block_header.pruning_point(), + }; let ghostdata = self.ghost_dag_manager().ghostdag(&block_header.parents())?; let next_pruning_point = self.pruning_point_manager().next_pruning_point( - block_header.pruning_point(), + &dag_state, &ghostdata, pruning_depth, pruning_finality, diff --git a/flexidag/src/consensusdb/consenses_state.rs b/flexidag/src/consensusdb/consenses_state.rs index 481c415fdb..a6b0f3cf09 100644 --- a/flexidag/src/consensusdb/consenses_state.rs +++ b/flexidag/src/consensusdb/consenses_state.rs @@ -9,6 +9,7 @@ use std::sync::Arc; #[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug, Default)] pub struct DagState { pub tips: Vec, + pub pruning_point: Hash, } pub(crate) const DAG_STATE_STORE_CF: &str = "dag-state-store"; @@ -87,6 +88,9 @@ pub struct DagStateView { impl DagStateView { pub fn into_state(self) -> DagState { - DagState { tips: self.tips } + DagState { + tips: self.tips, + pruning_point: self.pruning_point, + } } } diff --git a/flexidag/src/prune/pruning_point_manager.rs b/flexidag/src/prune/pruning_point_manager.rs index b7496e456a..b7b2656d09 100644 --- a/flexidag/src/prune/pruning_point_manager.rs +++ b/flexidag/src/prune/pruning_point_manager.rs @@ -40,10 +40,9 @@ impl PruningPointManagerT { pub fn prune( &self, dag_state: &DagState, - current_pruning_point: HashValue, next_pruning_point: HashValue, ) -> anyhow::Result> { - if current_pruning_point == HashValue::zero() { + if dag_state.pruning_point == HashValue::zero() { return Ok(dag_state.tips.clone()); } anyhow::Ok( @@ -58,15 +57,15 @@ impl PruningPointManagerT { .collect(), ) } - + pub(crate) fn next_pruning_point( &self, - pruning_point: HashValue, + dag_state: &DagState, ghostdata: &GhostdagData, pruning_depth: u64, pruning_finality: u64, ) -> anyhow::Result { - let pruning_ghostdata = self.ghost_dag_store.get_data(pruning_point)?; + let pruning_ghostdata = self.ghost_dag_store.get_data(dag_state.pruning_point)?; let min_required_blue_score_for_next_pruning_point = (self.finality_score(pruning_ghostdata.blue_score, pruning_finality) + 1) * pruning_finality; @@ -75,10 +74,13 @@ impl PruningPointManagerT { "min_required_blue_score_for_next_pruning_point: {:?}", min_required_blue_score_for_next_pruning_point ); - let mut latest_pruning_ghost_data = self.ghost_dag_store.get_compact_data(pruning_point)?; + + let mut latest_pruning_ghost_data = self + .ghost_dag_store + .get_compact_data(dag_state.pruning_point)?; if min_required_blue_score_for_next_pruning_point + pruning_depth <= ghostdata.blue_score { for child in self.reachability_service().forward_chain_iterator( - pruning_point, + dag_state.pruning_point, ghostdata.selected_parent, true, ) { @@ -105,7 +107,7 @@ impl PruningPointManagerT { } if latest_pruning_ghost_data.selected_parent == HashValue::new(ORIGIN) { - anyhow::Ok(pruning_point) // still genesis + anyhow::Ok(dag_state.pruning_point) // still genesis } else { anyhow::Ok(latest_pruning_ghost_data.selected_parent) } diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index e3208e7bcc..2393dd5c24 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -319,6 +319,7 @@ fn test_dag_tips_store() { let state = DagState { tips: vec![Hash::random()], + pruning_point: Hash::random(), }; dag.storage .state_store @@ -869,7 +870,6 @@ fn test_big_data_commit() -> anyhow::Result<()> { anyhow::Result::Ok(()) } -#[ignore = "pruning will be tested in next release"] #[test] fn test_prune() -> anyhow::Result<()> { // initialzie the dag firstly @@ -969,6 +969,7 @@ fn test_prune() -> anyhow::Result<()> { // prunning process begins dag.save_dag_state(DagState { tips: vec![block_red_3.id(), block_main_5.id()], + pruning_point: genesis.id(), })?; let MineNewDagBlockInfo { diff --git a/sync/src/block_connector/test_illegal_block.rs b/sync/src/block_connector/test_illegal_block.rs index d9bb234e9d..f081964f54 100644 --- a/sync/src/block_connector/test_illegal_block.rs +++ b/sync/src/block_connector/test_illegal_block.rs @@ -1,7 +1,9 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::arithmetic_side_effects)] -use crate::block_connector::{create_writeable_block_chain, WriteBlockChainService}; +use crate::block_connector::{ + create_writeable_block_chain, WriteBlockChainService, +}; use anyhow::Result; use starcoin_account_api::AccountInfo; use starcoin_chain::BlockChain; diff --git a/sync/src/block_connector/test_write_block_chain.rs b/sync/src/block_connector/test_write_block_chain.rs index ebdc928dff..ae8083687f 100644 --- a/sync/src/block_connector/test_write_block_chain.rs +++ b/sync/src/block_connector/test_write_block_chain.rs @@ -12,6 +12,8 @@ use starcoin_txpool_mock_service::MockTxPoolService; use starcoin_types::startup_info::StartupInfo; use std::sync::Arc; +use super::test_write_dag_block_chain::new_dag_block; + pub async fn create_writeable_dag_block_chain() -> ( WriteBlockChainService, Arc, diff --git a/sync/src/tasks/tests_dag.rs b/sync/src/tasks/tests_dag.rs index b2248cc137..f4fb074658 100644 --- a/sync/src/tasks/tests_dag.rs +++ b/sync/src/tasks/tests_dag.rs @@ -144,7 +144,6 @@ async fn test_continue_sync_dag_blocks() -> Result<()> { .unwrap() .produce_fork_chain(one_fork_count, two_fork_count)?; - ///// let target_dag_genesis_header_id = target_node .chain() .get_storage() diff --git a/types/src/block/tests.rs b/types/src/block/tests.rs index 33bf8b5450..bce998e9e1 100644 --- a/types/src/block/tests.rs +++ b/types/src/block/tests.rs @@ -258,7 +258,52 @@ fn test_header_with_dag_but_pruning_adaptable() -> anyhow::Result<()> { #[test] fn test_block_compatible_for_vega() -> anyhow::Result<()> { - let latest_block = crate::block::Block::rational_random(); + let uncle1 = crate::block::BlockHeaderBuilder::new() + .with_chain_id(ChainId::vega()) + .with_number(512) + .with_parent_hash(HashValue::random()) + .with_parents_hash(vec![ + HashValue::random(), + HashValue::random(), + HashValue::random(), + ]) + .build(); + + let uncle2 = crate::block::BlockHeaderBuilder::new() + .with_number(128) + .with_chain_id(ChainId::vega()) + .with_parent_hash(HashValue::random()) + .with_parents_hash(vec![ + HashValue::random(), + HashValue::random(), + HashValue::random(), + ]) + .build(); + let body = crate::block::BlockBody { + transactions: vec![ + SignedUserTransaction::sample(), + SignedUserTransaction::sample(), + SignedUserTransaction::sample(), + ], + uncles: Some(vec![uncle1, uncle2]), + }; + + let header = crate::block::BlockHeaderBuilder::new() + .with_number(1024) + .with_chain_id(ChainId::vega()) + .with_parent_hash(HashValue::random()) + .with_parents_hash(vec![ + HashValue::random(), + HashValue::random(), + HashValue::random(), + ]) + .with_body_hash(body.hash()) + .build(); + + let latest_block = crate::block::Block { + header: header.clone(), + body, + }; let deserilized_block = crate::block::Block::decode(&latest_block.encode()?)?; diff --git a/vm/types/src/block_metadata/legacy.rs b/vm/types/src/block_metadata/legacy.rs index 9b20891459..40a99b6217 100644 --- a/vm/types/src/block_metadata/legacy.rs +++ b/vm/types/src/block_metadata/legacy.rs @@ -72,7 +72,7 @@ impl From for super::BlockMetadata { number: value.number, chain_id: value.chain_id, parent_gas_used: value.parent_gas_used, - parents_hash: None, + parents_hash: Some(vec![]), } } } From 36c561a2f60abdabc9ad766aea143dc7480c258a Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 6 Aug 2024 10:25:36 +0800 Subject: [PATCH 34/60] fix clippy --- flexidag/src/prune/pruning_point_manager.rs | 2 +- sync/src/block_connector/test_illegal_block.rs | 4 +--- sync/src/block_connector/test_write_block_chain.rs | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/flexidag/src/prune/pruning_point_manager.rs b/flexidag/src/prune/pruning_point_manager.rs index b7b2656d09..bd41eaa35a 100644 --- a/flexidag/src/prune/pruning_point_manager.rs +++ b/flexidag/src/prune/pruning_point_manager.rs @@ -57,7 +57,7 @@ impl PruningPointManagerT { .collect(), ) } - + pub(crate) fn next_pruning_point( &self, dag_state: &DagState, diff --git a/sync/src/block_connector/test_illegal_block.rs b/sync/src/block_connector/test_illegal_block.rs index f081964f54..d9bb234e9d 100644 --- a/sync/src/block_connector/test_illegal_block.rs +++ b/sync/src/block_connector/test_illegal_block.rs @@ -1,9 +1,7 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::arithmetic_side_effects)] -use crate::block_connector::{ - create_writeable_block_chain, WriteBlockChainService, -}; +use crate::block_connector::{create_writeable_block_chain, WriteBlockChainService}; use anyhow::Result; use starcoin_account_api::AccountInfo; use starcoin_chain::BlockChain; diff --git a/sync/src/block_connector/test_write_block_chain.rs b/sync/src/block_connector/test_write_block_chain.rs index ae8083687f..ebdc928dff 100644 --- a/sync/src/block_connector/test_write_block_chain.rs +++ b/sync/src/block_connector/test_write_block_chain.rs @@ -12,8 +12,6 @@ use starcoin_txpool_mock_service::MockTxPoolService; use starcoin_types::startup_info::StartupInfo; use std::sync::Arc; -use super::test_write_dag_block_chain::new_dag_block; - pub async fn create_writeable_dag_block_chain() -> ( WriteBlockChainService, Arc, From bd1d871c7080377536b23b9bd1810427645309cd Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 6 Aug 2024 16:14:27 +0800 Subject: [PATCH 35/60] fix test case --- chain/src/chain.rs | 2 ++ chain/src/verifier/mod.rs | 2 +- flexidag/src/blockdag.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 7cc411b0c1..4430052297 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -275,6 +275,8 @@ impl BlockChain { None => self.current_header(), }; + println!("jacktest: current header: {:?}", previous_header); + self.create_block_template_by_header( author, previous_header, diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index 74fc59869d..69700e5b19 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -11,7 +11,7 @@ use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_logger::prelude::debug; use starcoin_open_block::AddressFilter; use starcoin_types::block::{Block, BlockHeader, ALLOWED_FUTURE_BLOCKTIME}; -use std::{collections::HashSet, str::FromStr}; +use std::{collections::HashSet, hash::Hash, str::FromStr}; #[derive(Debug, Clone)] pub enum Verifier { diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 0194049775..8312283b69 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -452,6 +452,7 @@ impl BlockDAG { ) -> anyhow::Result { let dag_state = self.get_dag_state()?; let ghostdata = self.ghost_dag_manager().ghostdag(&dag_state.tips)?; + println!("jacktest: dag state: {:?}, ghost data: {:?}", dag_state, ghostdata); anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, blue_blocks: (*ghostdata.mergeset_blues).clone(), From b3fdddb9fefe0b7dadc52e8c0602b0da642d2c2d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 6 Aug 2024 16:54:40 +0800 Subject: [PATCH 36/60] remove some single chain test case --- chain/tests/test_txn_info_and_proof.rs | 139 ------------------------- 1 file changed, 139 deletions(-) diff --git a/chain/tests/test_txn_info_and_proof.rs b/chain/tests/test_txn_info_and_proof.rs index 92e3694f82..d902703b93 100644 --- a/chain/tests/test_txn_info_and_proof.rs +++ b/chain/tests/test_txn_info_and_proof.rs @@ -123,142 +123,3 @@ fn test_transaction_info_and_proof_1() -> Result<()> { ); Ok(()) } - -#[stest::test(timeout = 480)] -fn test_transaction_info_and_proof() -> Result<()> { - let config = Arc::new(NodeConfig::random_for_test()); - let mut block_chain = test_helper::gen_blockchain_for_test(config.net())?; - let mut current_header = block_chain.current_header(); - let miner_account = AccountInfo::random(); - - let mut rng = rand::thread_rng(); - - let block_count: u64 = rng.gen_range(2..10); - let mut seq_number = 0; - let mut all_txns = vec![]; - let mut all_address = HashMap::::new(); - - let genesis_block = block_chain.get_block_by_number(0).unwrap().unwrap(); - //put the genesis txn, the genesis block metadata txn do not generate txn info - - all_txns.push(Transaction::UserTransaction( - genesis_block.body.transactions.first().cloned().unwrap(), - )); - - (0..block_count).for_each(|_block_idx| { - let txn_count: u64 = rng.gen_range(1..10); - let txns: Vec = (0..txn_count) - .map(|_txn_idx| { - let account_address = AccountAddress::random(); - - let txn = peer_to_peer_txn_sent_as_association( - account_address, - seq_number, - 10000, - config.net().time_service().now_secs() + DEFAULT_EXPIRATION_TIME, - config.net(), - ); - all_address.insert(txn.id(), account_address); - seq_number += 1; - txn - }) - .collect(); - - let (template, _) = block_chain - .create_block_template( - *miner_account.address(), - Some(current_header.id()), - txns.clone(), - vec![], - None, - vec![], - HashValue::zero(), - ) - .unwrap(); - - let block = block_chain - .consensus() - .create_block(template, config.net().time_service().as_ref()) - .unwrap(); - debug!("apply block:{:?}", &block); - block_chain.apply(block.clone()).unwrap(); - all_txns.push(Transaction::BlockMetadata( - block.to_metadata(current_header.gas_used()), - )); - all_txns.extend(txns.into_iter().map(Transaction::UserTransaction)); - current_header = block.header().clone(); - }); - - let txn_index = rng.gen_range(0..all_txns.len()); - debug!("all txns len: {}, txn index:{}", all_txns.len(), txn_index); - - for txn_global_index in 0..all_txns.len() { - let txn = all_txns.get(txn_global_index).cloned().unwrap(); - let txn_hash = txn.id(); - let txn_info = block_chain.get_transaction_info(txn_hash)?.ok_or_else(|| { - format_err!( - "Can not get txn info by txn hash:{}, txn:{:?}", - txn_hash, - txn - ) - })?; - - let txn_info_leaf = block_chain - .get_txn_accumulator() - .get_leaf(txn_global_index as u64)? - .unwrap(); - assert_eq!( - txn_info.transaction_info.id(), - txn_info_leaf, - "txn_info hash do not match txn info leaf in accumulator, index: {}", - txn_global_index - ); - - assert_eq!( - txn_info.transaction_global_index, txn_global_index as u64, - "txn_global_index:{}", - txn_global_index - ); - - let account_address = match &txn { - Transaction::UserTransaction(user_txn) => user_txn.sender(), - Transaction::BlockMetadata(metadata_txn) => metadata_txn.author(), - }; - let access_path: Option = Some(AccessPath::resource_access_path( - account_address, - AccountResource::struct_tag(), - )); - - let events = block_chain - .get_events(txn_info.transaction_info.id())? - .unwrap(); - - for (event_index, event) in events.into_iter().enumerate() { - let txn_proof = block_chain - .get_transaction_proof( - current_header.id(), - txn_global_index as u64, - Some(event_index as u64), - access_path.clone(), - )? - .expect("get transaction proof return none"); - assert_eq!(&event, &txn_proof.event_proof.as_ref().unwrap().event); - - let result = txn_proof.verify( - current_header.txn_accumulator_root(), - txn_global_index as u64, - Some(event_index as u64), - access_path.clone(), - ); - - assert!( - result.is_ok(), - "txn index: {}, {:?} verify failed, reason: {:?}", - txn_global_index, - txn_proof, - result.err().unwrap() - ); - } - } - Ok(()) -} From 0f891b5bd48f0aefc18d131d8fddfa9a3e3ab970 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 6 Aug 2024 18:12:31 +0800 Subject: [PATCH 37/60] fix clippy --- chain/src/verifier/mod.rs | 2 +- flexidag/src/blockdag.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index 69700e5b19..74fc59869d 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -11,7 +11,7 @@ use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_logger::prelude::debug; use starcoin_open_block::AddressFilter; use starcoin_types::block::{Block, BlockHeader, ALLOWED_FUTURE_BLOCKTIME}; -use std::{collections::HashSet, hash::Hash, str::FromStr}; +use std::{collections::HashSet, str::FromStr}; #[derive(Debug, Clone)] pub enum Verifier { diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 8312283b69..876482050d 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -452,7 +452,10 @@ impl BlockDAG { ) -> anyhow::Result { let dag_state = self.get_dag_state()?; let ghostdata = self.ghost_dag_manager().ghostdag(&dag_state.tips)?; - println!("jacktest: dag state: {:?}, ghost data: {:?}", dag_state, ghostdata); + println!( + "jacktest: dag state: {:?}, ghost data: {:?}", + dag_state, ghostdata + ); anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, blue_blocks: (*ghostdata.mergeset_blues).clone(), From 05ce8066dce303b36515c84819dec6daf9fbf8ae Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 10 Sep 2024 17:00:17 +0800 Subject: [PATCH 38/60] fix flexdag's test case --- chain/src/chain.rs | 2 -- flexidag/src/blockdag.rs | 4 ---- flexidag/tests/tests.rs | 1 + 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 4430052297..7cc411b0c1 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -275,8 +275,6 @@ impl BlockChain { None => self.current_header(), }; - println!("jacktest: current header: {:?}", previous_header); - self.create_block_template_by_header( author, previous_header, diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 876482050d..0194049775 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -452,10 +452,6 @@ impl BlockDAG { ) -> anyhow::Result { let dag_state = self.get_dag_state()?; let ghostdata = self.ghost_dag_manager().ghostdag(&dag_state.tips)?; - println!( - "jacktest: dag state: {:?}, ghost data: {:?}", - dag_state, ghostdata - ); anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, blue_blocks: (*ghostdata.mergeset_blues).clone(), diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 2393dd5c24..ed1a4a3af2 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -870,6 +870,7 @@ fn test_big_data_commit() -> anyhow::Result<()> { anyhow::Result::Ok(()) } +#[ignore = "pruning will be tested in next release"] #[test] fn test_prune() -> anyhow::Result<()> { // initialzie the dag firstly From beea493c92a08936f7d01b331fb33491a4219224 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 6 Aug 2024 22:44:13 +0800 Subject: [PATCH 39/60] fix clippy --- flexidag/src/blockdag.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 0194049775..fb3412fcc9 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -93,7 +93,7 @@ impl BlockDAG { Ok(Self::new(k, dag_storage)) } - pub fn new_by_config(db_path: &Path) -> anyhow::Result { + pub fn new_by_config(db_path: &Path) -> anyhow::Result { let config = FlexiDagStorageConfig::create_with_params(1, RocksdbConfig::default()); let db = FlexiDagStorage::create_from_path(db_path, config)?; let dag = Self::new(DEFAULT_GHOSTDAG_K, db); From de37f592a7bc173688b8185980991a6057b15324 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 7 Aug 2024 20:15:37 +0800 Subject: [PATCH 40/60] add rational random to pass the deserialization verification --- types/src/block/tests.rs | 47 +--------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/types/src/block/tests.rs b/types/src/block/tests.rs index bce998e9e1..33bf8b5450 100644 --- a/types/src/block/tests.rs +++ b/types/src/block/tests.rs @@ -258,52 +258,7 @@ fn test_header_with_dag_but_pruning_adaptable() -> anyhow::Result<()> { #[test] fn test_block_compatible_for_vega() -> anyhow::Result<()> { - let uncle1 = crate::block::BlockHeaderBuilder::new() - .with_chain_id(ChainId::vega()) - .with_number(512) - .with_parent_hash(HashValue::random()) - .with_parents_hash(vec![ - HashValue::random(), - HashValue::random(), - HashValue::random(), - ]) - .build(); - - let uncle2 = crate::block::BlockHeaderBuilder::new() - .with_number(128) - .with_chain_id(ChainId::vega()) - .with_parent_hash(HashValue::random()) - .with_parents_hash(vec![ - HashValue::random(), - HashValue::random(), - HashValue::random(), - ]) - .build(); - let body = crate::block::BlockBody { - transactions: vec![ - SignedUserTransaction::sample(), - SignedUserTransaction::sample(), - SignedUserTransaction::sample(), - ], - uncles: Some(vec![uncle1, uncle2]), - }; - - let header = crate::block::BlockHeaderBuilder::new() - .with_number(1024) - .with_chain_id(ChainId::vega()) - .with_parent_hash(HashValue::random()) - .with_parents_hash(vec![ - HashValue::random(), - HashValue::random(), - HashValue::random(), - ]) - .with_body_hash(body.hash()) - .build(); - - let latest_block = crate::block::Block { - header: header.clone(), - body, - }; + let latest_block = crate::block::Block::rational_random(); let deserilized_block = crate::block::Block::decode(&latest_block.encode()?)?; From d164edc42ae0b1c9212d806575205cc3e5717bd1 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 7 Aug 2024 22:42:05 +0800 Subject: [PATCH 41/60] merge dag-master --- flexidag/src/blockdag.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index fb3412fcc9..fea571ba73 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -98,7 +98,6 @@ impl BlockDAG { let db = FlexiDagStorage::create_from_path(db_path, config)?; let dag = Self::new(DEFAULT_GHOSTDAG_K, db); Ok(dag) ->>>>>>> 2ba8ddcfe (add pruning logic and compatible logic) } pub fn has_dag_block(&self, hash: Hash) -> anyhow::Result { From 7dfb38b3f71d15a1cf7737424357d24335b336f6 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 8 Aug 2024 12:30:31 +0800 Subject: [PATCH 42/60] fix bugs: blockmeta changes into latest version --- storage/src/lib.rs | 4 +++- storage/src/upgrade.rs | 7 +++++++ vm/types/src/block_metadata/legacy.rs | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 2f186aef4d..d6957ec086 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -212,11 +212,12 @@ pub enum StorageVersion { V3 = 3, V4 = 4, V5 = 5, + V6 = 6, } impl StorageVersion { pub fn current_version() -> Self { - Self::V5 + Self::V6 } pub fn get_column_family_names(&self) -> &'static [ColumnFamilyName] { @@ -226,6 +227,7 @@ impl StorageVersion { Self::V3 => &VEC_PREFIX_NAME_V3, Self::V4 => &VEC_PREFIX_NAME_V4, Self::V5 => &VEC_PREFIX_NAME_V5, + Self::V6 => &VEC_PREFIX_NAME_V5, } } } diff --git a/storage/src/upgrade.rs b/storage/src/upgrade.rs index a584a3b560..325248a1fd 100644 --- a/storage/src/upgrade.rs +++ b/storage/src/upgrade.rs @@ -239,6 +239,9 @@ impl DBUpgrade { (StorageVersion::V4, StorageVersion::V5) => { Self::db_upgrade_v4_v5(instance)?; } + (StorageVersion::V5, StorageVersion::V6) => { + Self::db_upgrade_v5_v6(instance)?; + } _ => bail!( "Cannot upgrade db from {:?} to {:?}", version_in_db, @@ -337,6 +340,10 @@ impl DBUpgrade { } Ok(()) } + + fn db_upgrade_v5_v6(_instance: &mut StorageInstance) -> Result<()> { + Ok(()) + } } fn upgrade_store(old_store: T1, store: T2, batch_size: usize) -> Result diff --git a/vm/types/src/block_metadata/legacy.rs b/vm/types/src/block_metadata/legacy.rs index 40a99b6217..9b20891459 100644 --- a/vm/types/src/block_metadata/legacy.rs +++ b/vm/types/src/block_metadata/legacy.rs @@ -72,7 +72,7 @@ impl From for super::BlockMetadata { number: value.number, chain_id: value.chain_id, parent_gas_used: value.parent_gas_used, - parents_hash: Some(vec![]), + parents_hash: None, } } } From 1df1d1abcb24475a200b3ad06e942e92d9a87ec3 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 8 Aug 2024 13:46:42 +0800 Subject: [PATCH 43/60] add update db code --- storage/src/upgrade.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/storage/src/upgrade.rs b/storage/src/upgrade.rs index 325248a1fd..08808226fa 100644 --- a/storage/src/upgrade.rs +++ b/storage/src/upgrade.rs @@ -229,6 +229,12 @@ impl DBUpgrade { Self::db_upgrade_v3_v4(instance)?; Self::db_upgrade_v4_v5(instance)?; } + (StorageVersion::V2, StorageVersion::V6) => { + Self::db_upgrade_v2_v3(instance)?; + Self::db_upgrade_v3_v4(instance)?; + Self::db_upgrade_v4_v5(instance)?; + Self::db_upgrade_v5_v6(instance)?; + } (StorageVersion::V3, StorageVersion::V4) => { Self::db_upgrade_v3_v4(instance)?; } @@ -236,9 +242,18 @@ impl DBUpgrade { Self::db_upgrade_v3_v4(instance)?; Self::db_upgrade_v4_v5(instance)?; } + (StorageVersion::V3, StorageVersion::V6) => { + Self::db_upgrade_v3_v4(instance)?; + Self::db_upgrade_v4_v5(instance)?; + Self::db_upgrade_v5_v6(instance)?; + } (StorageVersion::V4, StorageVersion::V5) => { Self::db_upgrade_v4_v5(instance)?; } + (StorageVersion::V4, StorageVersion::V6) => { + Self::db_upgrade_v4_v5(instance)?; + Self::db_upgrade_v5_v6(instance)?; + } (StorageVersion::V5, StorageVersion::V6) => { Self::db_upgrade_v5_v6(instance)?; } From 01110ba374aff0ffd41650f4f901b1a9240040e9 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 8 Aug 2024 21:24:49 +0800 Subject: [PATCH 44/60] add dag db update --- flexidag/src/blockdag.rs | 4 ++++ storage/src/lib.rs | 4 +--- storage/src/upgrade.rs | 22 ---------------------- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index fea571ba73..71174171f3 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -19,8 +19,12 @@ use starcoin_accumulator::{Accumulator, MerkleAccumulator}; use starcoin_config::temp_dir; use starcoin_crypto::{HashValue as Hash, HashValue}; use starcoin_logger::prelude::{debug, info, warn}; +<<<<<<< HEAD use starcoin_storage::Store; use starcoin_types::block::{AccumulatorInfo, BlockHeader}; +======= +use starcoin_types::block::BlockHeader; +>>>>>>> 32eccfca1 (add dag db update) use starcoin_types::{ blockhash::{BlockHashes, KType}, consensus_header::ConsensusHeader, diff --git a/storage/src/lib.rs b/storage/src/lib.rs index d6957ec086..2f186aef4d 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -212,12 +212,11 @@ pub enum StorageVersion { V3 = 3, V4 = 4, V5 = 5, - V6 = 6, } impl StorageVersion { pub fn current_version() -> Self { - Self::V6 + Self::V5 } pub fn get_column_family_names(&self) -> &'static [ColumnFamilyName] { @@ -227,7 +226,6 @@ impl StorageVersion { Self::V3 => &VEC_PREFIX_NAME_V3, Self::V4 => &VEC_PREFIX_NAME_V4, Self::V5 => &VEC_PREFIX_NAME_V5, - Self::V6 => &VEC_PREFIX_NAME_V5, } } } diff --git a/storage/src/upgrade.rs b/storage/src/upgrade.rs index 08808226fa..a584a3b560 100644 --- a/storage/src/upgrade.rs +++ b/storage/src/upgrade.rs @@ -229,12 +229,6 @@ impl DBUpgrade { Self::db_upgrade_v3_v4(instance)?; Self::db_upgrade_v4_v5(instance)?; } - (StorageVersion::V2, StorageVersion::V6) => { - Self::db_upgrade_v2_v3(instance)?; - Self::db_upgrade_v3_v4(instance)?; - Self::db_upgrade_v4_v5(instance)?; - Self::db_upgrade_v5_v6(instance)?; - } (StorageVersion::V3, StorageVersion::V4) => { Self::db_upgrade_v3_v4(instance)?; } @@ -242,21 +236,9 @@ impl DBUpgrade { Self::db_upgrade_v3_v4(instance)?; Self::db_upgrade_v4_v5(instance)?; } - (StorageVersion::V3, StorageVersion::V6) => { - Self::db_upgrade_v3_v4(instance)?; - Self::db_upgrade_v4_v5(instance)?; - Self::db_upgrade_v5_v6(instance)?; - } (StorageVersion::V4, StorageVersion::V5) => { Self::db_upgrade_v4_v5(instance)?; } - (StorageVersion::V4, StorageVersion::V6) => { - Self::db_upgrade_v4_v5(instance)?; - Self::db_upgrade_v5_v6(instance)?; - } - (StorageVersion::V5, StorageVersion::V6) => { - Self::db_upgrade_v5_v6(instance)?; - } _ => bail!( "Cannot upgrade db from {:?} to {:?}", version_in_db, @@ -355,10 +337,6 @@ impl DBUpgrade { } Ok(()) } - - fn db_upgrade_v5_v6(_instance: &mut StorageInstance) -> Result<()> { - Ok(()) - } } fn upgrade_store(old_store: T1, store: T2, batch_size: usize) -> Result From 0b2da55287624dc1ab239864c4010f9514a5399e Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 8 Aug 2024 22:21:47 +0800 Subject: [PATCH 45/60] update dag db --- flexidag/src/blockdag.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 71174171f3..0518617a8d 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -19,12 +19,8 @@ use starcoin_accumulator::{Accumulator, MerkleAccumulator}; use starcoin_config::temp_dir; use starcoin_crypto::{HashValue as Hash, HashValue}; use starcoin_logger::prelude::{debug, info, warn}; -<<<<<<< HEAD use starcoin_storage::Store; use starcoin_types::block::{AccumulatorInfo, BlockHeader}; -======= -use starcoin_types::block::BlockHeader; ->>>>>>> 32eccfca1 (add dag db update) use starcoin_types::{ blockhash::{BlockHashes, KType}, consensus_header::ConsensusHeader, @@ -566,6 +562,15 @@ impl BlockDAG { Err(_) => { warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", read_guard.get_state()?); None +======= + Err(_) => { + info!("The dag state will be saved as {:?}", dag_state); + self.storage.state_store.write().insert(dag_state)?; + } + }, + Err(_) => { + warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", self.storage.state_store.read().get_state()?); +>>>>>>> e00426dfc (update dag db) } }; @@ -587,12 +592,4 @@ impl BlockDAG { self.storage.reachability_store.clone() } - pub fn verify_and_ghostdata( - &self, - blue_blocks: &[BlockHeader], - header: &BlockHeader, - ) -> Result { - self.ghost_dag_manager() - .verify_and_ghostdata(blue_blocks, header) - } } From 2de6730b30e8a8544de790c015a556091ca05e8d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 8 Aug 2024 23:58:56 +0800 Subject: [PATCH 46/60] update dag db --- chain/src/chain.rs | 5 +---- flexidag/src/blockdag.rs | 16 +--------------- flexidag/src/consensusdb/consenses_state.rs | 6 +----- flexidag/src/prune/pruning_point_manager.rs | 11 ++++++----- flexidag/tests/tests.rs | 2 -- 5 files changed, 9 insertions(+), 31 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 7cc411b0c1..d83f16caa9 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1519,10 +1519,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(DagState { - tips, - pruning_point: block.header().pruning_point(), - })?; + self.dag.save_dag_state(DagState { tips })?; Ok(executed_block) } } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 0518617a8d..5b14e86385 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -123,7 +123,6 @@ impl BlockDAG { self.commit(genesis, origin)?; self.save_dag_state(DagState { tips: vec![genesis_id], - pruning_point: genesis_id, })?; Ok(origin) } @@ -493,13 +492,9 @@ impl BlockDAG { block_header: &BlockHeader, genesis_id: HashValue, ) -> anyhow::Result<()> { - let dag_state = DagState { - tips: block_header.parents(), - pruning_point: block_header.pruning_point(), - }; let ghostdata = self.ghost_dag_manager().ghostdag(&block_header.parents())?; let next_pruning_point = self.pruning_point_manager().next_pruning_point( - &dag_state, + block_header.pruning_point(), &ghostdata, pruning_depth, pruning_finality, @@ -562,15 +557,6 @@ impl BlockDAG { Err(_) => { warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", read_guard.get_state()?); None -======= - Err(_) => { - info!("The dag state will be saved as {:?}", dag_state); - self.storage.state_store.write().insert(dag_state)?; - } - }, - Err(_) => { - warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", self.storage.state_store.read().get_state()?); ->>>>>>> e00426dfc (update dag db) } }; diff --git a/flexidag/src/consensusdb/consenses_state.rs b/flexidag/src/consensusdb/consenses_state.rs index a6b0f3cf09..481c415fdb 100644 --- a/flexidag/src/consensusdb/consenses_state.rs +++ b/flexidag/src/consensusdb/consenses_state.rs @@ -9,7 +9,6 @@ use std::sync::Arc; #[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug, Default)] pub struct DagState { pub tips: Vec, - pub pruning_point: Hash, } pub(crate) const DAG_STATE_STORE_CF: &str = "dag-state-store"; @@ -88,9 +87,6 @@ pub struct DagStateView { impl DagStateView { pub fn into_state(self) -> DagState { - DagState { - tips: self.tips, - pruning_point: self.pruning_point, - } + DagState { tips: self.tips } } } diff --git a/flexidag/src/prune/pruning_point_manager.rs b/flexidag/src/prune/pruning_point_manager.rs index bd41eaa35a..f538a58f76 100644 --- a/flexidag/src/prune/pruning_point_manager.rs +++ b/flexidag/src/prune/pruning_point_manager.rs @@ -40,9 +40,10 @@ impl PruningPointManagerT { pub fn prune( &self, dag_state: &DagState, + current_pruning_point: HashValue, next_pruning_point: HashValue, ) -> anyhow::Result> { - if dag_state.pruning_point == HashValue::zero() { + if current_pruning_point == HashValue::zero() { return Ok(dag_state.tips.clone()); } anyhow::Ok( @@ -60,12 +61,12 @@ impl PruningPointManagerT { pub(crate) fn next_pruning_point( &self, - dag_state: &DagState, + pruning_point: HashValue, ghostdata: &GhostdagData, pruning_depth: u64, pruning_finality: u64, ) -> anyhow::Result { - let pruning_ghostdata = self.ghost_dag_store.get_data(dag_state.pruning_point)?; + let pruning_ghostdata = self.ghost_dag_store.get_data(pruning_point)?; let min_required_blue_score_for_next_pruning_point = (self.finality_score(pruning_ghostdata.blue_score, pruning_finality) + 1) * pruning_finality; @@ -80,7 +81,7 @@ impl PruningPointManagerT { .get_compact_data(dag_state.pruning_point)?; if min_required_blue_score_for_next_pruning_point + pruning_depth <= ghostdata.blue_score { for child in self.reachability_service().forward_chain_iterator( - dag_state.pruning_point, + pruning_point, ghostdata.selected_parent, true, ) { @@ -107,7 +108,7 @@ impl PruningPointManagerT { } if latest_pruning_ghost_data.selected_parent == HashValue::new(ORIGIN) { - anyhow::Ok(dag_state.pruning_point) // still genesis + anyhow::Ok(pruning_point) // still genesis } else { anyhow::Ok(latest_pruning_ghost_data.selected_parent) } diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index ed1a4a3af2..e3208e7bcc 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -319,7 +319,6 @@ fn test_dag_tips_store() { let state = DagState { tips: vec![Hash::random()], - pruning_point: Hash::random(), }; dag.storage .state_store @@ -970,7 +969,6 @@ fn test_prune() -> anyhow::Result<()> { // prunning process begins dag.save_dag_state(DagState { tips: vec![block_red_3.id(), block_main_5.id()], - pruning_point: genesis.id(), })?; let MineNewDagBlockInfo { From 66c1536bc981b93650816230f87fd2c22a6fbe30 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 13 Aug 2024 19:47:13 +0800 Subject: [PATCH 47/60] uncomment the pruning code --- chain/src/chain.rs | 2 + flexidag/src/blockdag.rs | 47 ++++--------------- flexidag/tests/tests.rs | 2 +- miner/src/create_block_template/mod.rs | 2 +- .../block_connector_service.rs | 9 +++- sync/src/block_connector/mod.rs | 6 ++- 6 files changed, 24 insertions(+), 44 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index d83f16caa9..4802547330 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -320,8 +320,10 @@ impl BlockChain { } } else { self.dag().calc_mergeset_and_tips( + &previous_header, G_DAG_TEST_CONFIG.pruning_depth, G_DAG_TEST_CONFIG.pruning_finality, + 0, )? }; debug!( diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 5b14e86385..c856b7f40f 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -123,6 +123,7 @@ impl BlockDAG { self.commit(genesis, origin)?; self.save_dag_state(DagState { tips: vec![genesis_id], + pruning_point: genesis_id, })?; Ok(origin) } @@ -518,48 +519,18 @@ impl BlockDAG { bail!("pruning point is not correct, the local next pruning point is {}, but the block header pruning point is {}", next_pruning_point, block_header.pruning_point()); } anyhow::Ok(()) - } - - pub fn verify( - &self, - pruning_depth: u64, - pruning_finality: u64, - block_header: &BlockHeader, - genesis_id: HashValue, - ) -> anyhow::Result<()> { - self.verify_pruning_point(pruning_depth, pruning_finality, block_header, genesis_id) - } - - pub fn check_upgrade( - &self, - info: AccumulatorInfo, - storage: Arc, - ) -> anyhow::Result<()> { - let accumulator = MerkleAccumulator::new_with_info( - info, - storage.get_accumulator_store(AccumulatorStoreType::Block), - ); - - let read_guard = self.storage.state_store.read(); - - let update_dag_state = match read_guard.get_state_by_hash( - accumulator - .get_leaf(0)? - .ok_or_else(|| format_err!("no leaf when upgrading dag db"))?, - ) { - anyhow::Result::Ok(dag_state) => match read_guard.get_state() { - anyhow::Result::Ok(saved_dag_state) => { - info!("The dag state is {:?}", saved_dag_state); - None +======= + Err(_) => { + info!("The dag state will be saved as {:?}", dag_state); + self.storage.state_store.write().insert(dag_state)?; } - Err(_) => Some(dag_state), }, Err(_) => { - warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", read_guard.get_state()?); - None - } - }; + warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", self.storage.state_store.read().get_state()?); +>>>>>>> e00426dfc (update dag db) + } + pub fn verify( drop(read_guard); if let Some(dag_state) = update_dag_state { diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index e3208e7bcc..6a94673600 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -975,7 +975,7 @@ fn test_prune() -> anyhow::Result<()> { tips, blue_blocks: _, pruning_point, - } = dag.calc_mergeset_and_tips(pruning_depth, pruning_finality)?; + } = dag.calc_mergeset_and_tips(&block_main_5, pruning_depth, pruning_finality, 2)?; assert_eq!(pruning_point, block_main_2.id()); assert_eq!(tips.len(), 1); diff --git a/miner/src/create_block_template/mod.rs b/miner/src/create_block_template/mod.rs index 7fd06ac88d..4b272acbac 100644 --- a/miner/src/create_block_template/mod.rs +++ b/miner/src/create_block_template/mod.rs @@ -188,7 +188,7 @@ where next_difficulty: difficulty, now_milliseconds: mut now_millis, pruning_point, - } = *block_on(self.block_connector_service.send(MinerRequest {}))??; + } = *block_on(self.block_connector_service.send(MinerRequest { version }))??; let block_gas_limit = self .local_block_gas_limit diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 8617bdd39a..344c990dbf 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -375,7 +375,7 @@ where { fn handle( &mut self, - _msg: MinerRequest, + msg: MinerRequest, ctx: &mut ServiceContext, ) -> ::Response { let main = self.chain_service.get_main(); @@ -392,7 +392,12 @@ where tips, blue_blocks, pruning_point, - } = dag.calc_mergeset_and_tips(pruning_depth, pruning_finality)?; + } = dag.calc_mergeset_and_tips( + main.status().head(), + pruning_depth, + pruning_finality, + msg.version, + )?; if blue_blocks.is_empty() { bail!("failed to get the blue blocks from the DAG"); } diff --git a/sync/src/block_connector/mod.rs b/sync/src/block_connector/mod.rs index a1f97a65dc..32f45f26fc 100644 --- a/sync/src/block_connector/mod.rs +++ b/sync/src/block_connector/mod.rs @@ -3,7 +3,7 @@ use starcoin_crypto::HashValue; use starcoin_service_registry::ServiceRequest; -use starcoin_types::block::{Block, ExecutedBlock}; +use starcoin_types::block::{Block, ExecutedBlock, Version}; mod block_connector_service; mod metrics; @@ -48,7 +48,9 @@ impl ServiceRequest for ExecuteRequest { } #[derive(Clone, Debug)] -pub struct MinerRequest {} +pub struct MinerRequest { + pub version: Version, +} #[derive(Clone, Debug)] pub struct MinerResponse { From 940bb8e59c67f13abb5ec85ee69207dd0bb74e2c Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 10 Sep 2024 17:16:40 +0800 Subject: [PATCH 48/60] rebase sync parallel3 --- flexidag/src/blockdag.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index c856b7f40f..6570739991 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -519,15 +519,6 @@ impl BlockDAG { bail!("pruning point is not correct, the local next pruning point is {}, but the block header pruning point is {}", next_pruning_point, block_header.pruning_point()); } anyhow::Ok(()) -======= - Err(_) => { - info!("The dag state will be saved as {:?}", dag_state); - self.storage.state_store.write().insert(dag_state)?; - } - }, - Err(_) => { - warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", self.storage.state_store.read().get_state()?); ->>>>>>> e00426dfc (update dag db) } pub fn verify( From 178499cbd04a480c83b95f00c1394a5076721bc4 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Tue, 10 Sep 2024 20:07:13 +0800 Subject: [PATCH 49/60] fix compiling --- chain/src/chain.rs | 1 - flexidag/src/blockdag.rs | 130 +++++++++++------- flexidag/src/prune/pruning_point_manager.rs | 4 +- flexidag/tests/tests.rs | 2 +- .../block_connector_service.rs | 7 +- 5 files changed, 81 insertions(+), 63 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 4802547330..d58d989463 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -323,7 +323,6 @@ impl BlockChain { &previous_header, G_DAG_TEST_CONFIG.pruning_depth, G_DAG_TEST_CONFIG.pruning_finality, - 0, )? }; debug!( diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 6570739991..53f7c02ad0 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -93,13 +93,6 @@ impl BlockDAG { Ok(Self::new(k, dag_storage)) } - pub fn new_by_config(db_path: &Path) -> anyhow::Result { - let config = FlexiDagStorageConfig::create_with_params(1, RocksdbConfig::default()); - let db = FlexiDagStorage::create_from_path(db_path, config)?; - let dag = Self::new(DEFAULT_GHOSTDAG_K, db); - Ok(dag) - } - pub fn has_dag_block(&self, hash: Hash) -> anyhow::Result { Ok(self.storage.header_store.has(hash)?) } @@ -123,7 +116,6 @@ impl BlockDAG { self.commit(genesis, origin)?; self.save_dag_state(DagState { tips: vec![genesis_id], - pruning_point: genesis_id, })?; Ok(origin) } @@ -446,44 +438,42 @@ impl BlockDAG { pub fn calc_mergeset_and_tips( &self, - _pruning_depth: u64, - _pruning_finality: u64, + block_header: &BlockHeader, + pruning_depth: u64, + pruning_finality: u64, ) -> anyhow::Result { let dag_state = self.get_dag_state()?; - let ghostdata = self.ghost_dag_manager().ghostdag(&dag_state.tips)?; - anyhow::Ok(MineNewDagBlockInfo { - tips: dag_state.tips, - blue_blocks: (*ghostdata.mergeset_blues).clone(), - pruning_point: HashValue::zero(), - }) - - // let next_pruning_point = self.pruning_point_manager().next_pruning_point( - // &dag_state, - // &ghostdata, - // pruning_depth, - // pruning_finality, - // )?; - // if next_pruning_point == dag_state.pruning_point { - // anyhow::Ok(MineNewDagBlockInfo { - // tips: dag_state.tips, - // blue_blocks: (*ghostdata.mergeset_blues).clone(), - // pruning_point: next_pruning_point, - // }) - // } else { - // let pruned_tips = self - // .pruning_point_manager() - // .prune(&dag_state, next_pruning_point)?; - // let mergeset_blues = (*self - // .ghost_dag_manager() - // .ghostdag(&pruned_tips)? - // .mergeset_blues) - // .clone(); - // anyhow::Ok(MineNewDagBlockInfo { - // tips: pruned_tips, - // blue_blocks: mergeset_blues, - // pruning_point: next_pruning_point, - // }) - // } + let ghostdata = self.storage.ghost_dag_store.get_data(block_header.id())?; + + let next_pruning_point = self.pruning_point_manager().next_pruning_point( + block_header.pruning_point(), + ghostdata.as_ref(), + pruning_depth, + pruning_finality, + )?; + if next_pruning_point == block_header.pruning_point() { + anyhow::Ok(MineNewDagBlockInfo { + tips: dag_state.tips, + blue_blocks: (*ghostdata.mergeset_blues).clone(), + pruning_point: next_pruning_point, + }) + } else { + let pruned_tips = self.pruning_point_manager().prune( + &dag_state, + block_header.pruning_point(), + next_pruning_point, + )?; + let mergeset_blues = (*self + .ghost_dag_manager() + .ghostdag(&pruned_tips)? + .mergeset_blues) + .clone(); + anyhow::Ok(MineNewDagBlockInfo { + tips: pruned_tips, + blue_blocks: mergeset_blues, + pruning_point: next_pruning_point, + }) + } } fn verify_pruning_point( @@ -521,7 +511,50 @@ impl BlockDAG { anyhow::Ok(()) } - pub fn verify( + pub fn reachability_store( + &self, + ) -> Arc> { + self.storage.reachability_store.clone() + } + + pub fn verify_and_ghostdata( + &self, + blue_blocks: &[BlockHeader], + header: &BlockHeader, + ) -> Result { + self.ghost_dag_manager() + .verify_and_ghostdata(blue_blocks, header) + } + pub fn check_upgrade( + &self, + info: AccumulatorInfo, + storage: Arc, + ) -> anyhow::Result<()> { + let accumulator = MerkleAccumulator::new_with_info( + info, + storage.get_accumulator_store(AccumulatorStoreType::Block), + ); + + let read_guard = self.storage.state_store.read(); + + let update_dag_state = match read_guard.get_state_by_hash( + accumulator + .get_leaf(0)? + .ok_or_else(|| format_err!("no leaf when upgrading dag db"))?, + ) { + anyhow::Result::Ok(dag_state) => match read_guard.get_state() { + anyhow::Result::Ok(saved_dag_state) => { + info!("The dag state is {:?}", saved_dag_state); + None + } + Err(_) => Some(dag_state), + }, + Err(_) => { + warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", read_guard.get_state()?); + None + } + }; + drop(read_guard); if let Some(dag_state) = update_dag_state { @@ -533,11 +566,4 @@ impl BlockDAG { anyhow::Ok(()) } - - pub fn reachability_store( - &self, - ) -> Arc> { - self.storage.reachability_store.clone() - } - } diff --git a/flexidag/src/prune/pruning_point_manager.rs b/flexidag/src/prune/pruning_point_manager.rs index f538a58f76..c795ac6d16 100644 --- a/flexidag/src/prune/pruning_point_manager.rs +++ b/flexidag/src/prune/pruning_point_manager.rs @@ -76,9 +76,7 @@ impl PruningPointManagerT { min_required_blue_score_for_next_pruning_point ); - let mut latest_pruning_ghost_data = self - .ghost_dag_store - .get_compact_data(dag_state.pruning_point)?; + let mut latest_pruning_ghost_data = self.ghost_dag_store.get_compact_data(pruning_point)?; if min_required_blue_score_for_next_pruning_point + pruning_depth <= ghostdata.blue_score { for child in self.reachability_service().forward_chain_iterator( pruning_point, diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 6a94673600..93c45c75d4 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -975,7 +975,7 @@ fn test_prune() -> anyhow::Result<()> { tips, blue_blocks: _, pruning_point, - } = dag.calc_mergeset_and_tips(&block_main_5, pruning_depth, pruning_finality, 2)?; + } = dag.calc_mergeset_and_tips(&block_main_5, pruning_depth, pruning_finality)?; assert_eq!(pruning_point, block_main_2.id()); assert_eq!(tips.len(), 1); diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 344c990dbf..49d9f9b622 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -392,12 +392,7 @@ where tips, blue_blocks, pruning_point, - } = dag.calc_mergeset_and_tips( - main.status().head(), - pruning_depth, - pruning_finality, - msg.version, - )?; + } = dag.calc_mergeset_and_tips(main.status().head(), pruning_depth, pruning_finality)?; if blue_blocks.is_empty() { bail!("failed to get the blue blocks from the DAG"); } From 53cd23614939c1b5a7cd2a4088134cd76ccf2aed Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 11 Sep 2024 12:26:29 +0800 Subject: [PATCH 50/60] db update for dag state --- chain/src/chain.rs | 13 +- flexidag/src/blockdag.rs | 114 ++++++++++-------- flexidag/src/consensusdb/consenses_state.rs | 12 +- flexidag/tests/tests.rs | 13 +- node/src/node.rs | 5 +- .../block_connector_service.rs | 2 +- 6 files changed, 85 insertions(+), 74 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index d58d989463..24e89530a2 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -178,7 +178,7 @@ impl BlockChain { } fn init_dag(mut dag: BlockDAG, genesis_header: BlockHeader) -> Result { - match dag.get_dag_state() { + match dag.get_dag_state(genesis_header.pruning_point()) { anyhow::Result::Ok(_dag_state) => (), Err(e) => match e.downcast::()? { StoreError::KeyNotFound(_) => { @@ -984,7 +984,7 @@ impl BlockChain { } pub fn get_dag_state(&self) -> Result { - self.dag.get_dag_state() + self.dag.get_dag_state(self.status().head().pruning_point()) } } @@ -1336,7 +1336,9 @@ impl ChainReader for BlockChain { } fn current_tips_hash(&self) -> Result> { - self.dag.get_dag_state().map(|state| state.tips) + self.dag + .get_dag_state(self.status().head().id()) + .map(|state| state.tips) } fn has_dag_block(&self, header_id: HashValue) -> Result { @@ -1520,7 +1522,10 @@ impl BlockChain { if self.epoch.end_block_number() == block.header().number() { self.epoch = get_epoch_from_statedb(&self.statedb)?; } - self.dag.save_dag_state(DagState { tips })?; + self.dag.save_dag_state( + executed_block.block().header().pruning_point(), + DagState { tips }, + )?; Ok(executed_block) } } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 53f7c02ad0..7209a2c430 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -13,14 +13,11 @@ use crate::consensusdb::{ use crate::ghostdag::protocol::GhostdagManager; use crate::prune::pruning_point_manager::PruningPointManagerT; use crate::{process_key_already_error, reachability}; -use anyhow::{bail, ensure, format_err, Ok}; -use starcoin_accumulator::node::AccumulatorStoreType; -use starcoin_accumulator::{Accumulator, MerkleAccumulator}; +use anyhow::{bail, ensure, Ok}; use starcoin_config::temp_dir; use starcoin_crypto::{HashValue as Hash, HashValue}; -use starcoin_logger::prelude::{debug, info, warn}; -use starcoin_storage::Store; -use starcoin_types::block::{AccumulatorInfo, BlockHeader}; +use starcoin_logger::prelude::{debug, info}; +use starcoin_types::block::BlockHeader; use starcoin_types::{ blockhash::{BlockHashes, KType}, consensus_header::ConsensusHeader, @@ -113,10 +110,14 @@ impl BlockDAG { .write() .insert(origin, BlockHashes::new(vec![]))?; + let pruning_point = genesis.pruning_point(); self.commit(genesis, origin)?; - self.save_dag_state(DagState { - tips: vec![genesis_id], - })?; + self.save_dag_state( + pruning_point, + DagState { + tips: vec![genesis_id], + }, + )?; Ok(origin) } pub fn ghostdata(&self, parents: &[HashValue]) -> anyhow::Result { @@ -423,12 +424,12 @@ impl BlockDAG { } } - pub fn get_dag_state(&self) -> anyhow::Result { - Ok(self.storage.state_store.read().get_state()?) + pub fn get_dag_state(&self, hash: Hash) -> anyhow::Result { + Ok(self.storage.state_store.read().get_state_by_hash(hash)?) } - pub fn save_dag_state(&self, state: DagState) -> anyhow::Result<()> { - self.storage.state_store.write().insert(state)?; + pub fn save_dag_state(&self, hash: Hash, state: DagState) -> anyhow::Result<()> { + self.storage.state_store.write().insert(hash, state)?; Ok(()) } @@ -442,12 +443,12 @@ impl BlockDAG { pruning_depth: u64, pruning_finality: u64, ) -> anyhow::Result { - let dag_state = self.get_dag_state()?; - let ghostdata = self.storage.ghost_dag_store.get_data(block_header.id())?; + let dag_state = self.get_dag_state(block_header.id())?; + let ghostdata = self.ghostdata(&dag_state.tips)?; let next_pruning_point = self.pruning_point_manager().next_pruning_point( block_header.pruning_point(), - ghostdata.as_ref(), + &ghostdata, pruning_depth, pruning_finality, )?; @@ -525,43 +526,54 @@ impl BlockDAG { self.ghost_dag_manager() .verify_and_ghostdata(blue_blocks, header) } - pub fn check_upgrade( - &self, - info: AccumulatorInfo, - storage: Arc, - ) -> anyhow::Result<()> { - let accumulator = MerkleAccumulator::new_with_info( - info, - storage.get_accumulator_store(AccumulatorStoreType::Block), - ); - - let read_guard = self.storage.state_store.read(); - - let update_dag_state = match read_guard.get_state_by_hash( - accumulator - .get_leaf(0)? - .ok_or_else(|| format_err!("no leaf when upgrading dag db"))?, - ) { - anyhow::Result::Ok(dag_state) => match read_guard.get_state() { - anyhow::Result::Ok(saved_dag_state) => { - info!("The dag state is {:?}", saved_dag_state); - None + pub fn check_upgrade(&self, main: &BlockHeader) -> anyhow::Result<()> { + // set the state with key 0 + if main.version() == 0 { + let result_dag_state = self + .storage + .state_store + .read() + .get_state_by_hash(main.pruning_point()); + match result_dag_state { + anyhow::Result::Ok(_dag_state) => (), + Err(_) => { + let result_dag_state = + self.storage.state_store.read().get_state_by_hash(0.into()); + match result_dag_state { + anyhow::Result::Ok(dag_state) => self + .storage + .state_store + .write() + .insert(main.pruning_point(), dag_state)?, + Err(_) => { + let dag_state = self + .storage + .state_store + .read() + .get_state_by_hash(main.id())?; + self.storage + .state_store + .write() + .insert(0.into(), dag_state.clone())?; + self.storage + .state_store + .write() + .insert(HashValue::zero(), dag_state)?; + } + } } - Err(_) => Some(dag_state), - }, - Err(_) => { - warn!("Cannot get the dag state by genesis id. Might be it is a new node. The dag state will be: {:?}", read_guard.get_state()?); - None } - }; - - drop(read_guard); - - if let Some(dag_state) = update_dag_state { - let write_guard = self.storage.state_store.write(); - info!("The dag state will be saved as {:?}", dag_state); - write_guard.insert(dag_state)?; - drop(write_guard); + return Ok(()); + } else if main.version() == 1 { + let dag_state = self + .storage + .state_store + .read() + .get_state_by_hash(0.into())?; + self.storage + .state_store + .write() + .insert(HashValue::zero(), dag_state)?; } anyhow::Ok(()) diff --git a/flexidag/src/consensusdb/consenses_state.rs b/flexidag/src/consensusdb/consenses_state.rs index 481c415fdb..229e790db3 100644 --- a/flexidag/src/consensusdb/consenses_state.rs +++ b/flexidag/src/consensusdb/consenses_state.rs @@ -34,13 +34,12 @@ impl ValueCodec for DagState { } pub trait DagStateReader { - fn get_state(&self) -> Result; fn get_state_by_hash(&self, hash: Hash) -> Result; } pub trait DagStateStore: DagStateReader { // This is append only - fn insert(&self, state: DagState) -> Result<(), StoreError>; + fn insert(&self, hash: Hash, state: DagState) -> Result<(), StoreError>; } /// A DB + cache implementation of `HeaderStore` trait, with concurrency support. @@ -60,11 +59,6 @@ impl DbDagStateStore { } impl DagStateReader for DbDagStateStore { - fn get_state(&self) -> Result { - let result = self.dag_state_access.read(0.into())?; - Ok(result) - } - fn get_state_by_hash(&self, hash: Hash) -> Result { let result = self.dag_state_access.read(hash)?; Ok(result) @@ -72,9 +66,9 @@ impl DagStateReader for DbDagStateStore { } impl DagStateStore for DbDagStateStore { - fn insert(&self, state: DagState) -> Result<(), StoreError> { + fn insert(&self, hash: Hash, state: DagState) -> Result<(), StoreError> { self.dag_state_access - .write(DirectDbWriter::new(&self.db), 0.into(), state)?; + .write(DirectDbWriter::new(&self.db), hash, state)?; Ok(()) } } diff --git a/flexidag/tests/tests.rs b/flexidag/tests/tests.rs index 93c45c75d4..76f6754ce1 100644 --- a/flexidag/tests/tests.rs +++ b/flexidag/tests/tests.rs @@ -323,14 +323,14 @@ fn test_dag_tips_store() { dag.storage .state_store .write() - .insert(state.clone()) + .insert(Hash::zero(), state.clone()) .expect("failed to store the dag state"); assert_eq!( dag.storage .state_store .read() - .get_state() + .get_state_by_hash(Hash::zero()) .expect("failed to get the dag state"), state ); @@ -967,9 +967,12 @@ fn test_prune() -> anyhow::Result<()> { assert_eq!(observer3.selected_parent, observer2.selected_parent); // prunning process begins - dag.save_dag_state(DagState { - tips: vec![block_red_3.id(), block_main_5.id()], - })?; + dag.save_dag_state( + Hash::zero(), + DagState { + tips: vec![block_red_3.id(), block_main_5.id()], + }, + )?; let MineNewDagBlockInfo { tips, diff --git a/node/src/node.rs b/node/src/node.rs index e9c2891323..14391f7e59 100644 --- a/node/src/node.rs +++ b/node/src/node.rs @@ -336,10 +336,7 @@ impl NodeService { upgrade_time.as_secs() ); - dag.check_upgrade( - chain_info.status().info().block_accumulator_info.clone(), - storage.clone(), - )?; + dag.check_upgrade(chain_info.status().head())?; registry.put_shared(genesis).await?; diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 49d9f9b622..3f2b5695fd 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -375,7 +375,7 @@ where { fn handle( &mut self, - msg: MinerRequest, + _msg: MinerRequest, ctx: &mut ServiceContext, ) -> ::Response { let main = self.chain_service.get_main(); From 7ffca918f925567905a3ce8e8cf724d6de21f4fa Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Wed, 11 Sep 2024 21:01:40 +0800 Subject: [PATCH 51/60] fix connection --- chain/api/src/chain.rs | 2 +- chain/src/chain.rs | 48 +++++++++++++------ flexidag/src/blockdag.rs | 2 +- .../block_connector_service.rs | 28 +++++++---- .../test_write_dag_block_chain.rs | 4 +- sync/src/block_connector/write_block_chain.rs | 11 ++--- 6 files changed, 64 insertions(+), 31 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index 2d801f1d32..92116f2370 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -106,7 +106,7 @@ pub trait ChainReader { access_path: Option, ) -> Result>; - fn current_tips_hash(&self) -> Result>; + fn current_tips_hash(&self, pruning_point: HashValue) -> Result>; fn has_dag_block(&self, header_id: HashValue) -> Result; fn check_chain_type(&self) -> Result; fn verify_and_ghostdata( diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 24e89530a2..a2b7e80988 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1335,9 +1335,9 @@ impl ChainReader for BlockChain { })) } - fn current_tips_hash(&self) -> Result> { + fn current_tips_hash(&self, pruning_point: HashValue) -> Result> { self.dag - .get_dag_state(self.status().head().id()) + .get_dag_state(pruning_point) .map(|state| state.tips) } @@ -1472,16 +1472,26 @@ 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 parents = executed_block.block.header.parents_hash(); - if !tips.contains(&new_tip_block.id()) { - for hash in parents { - tips.retain(|x| *x != hash); - } - if !dag.check_ancestor_of(new_tip_block.id(), tips.clone())? { - tips.push(new_tip_block.id()); + let parent_header = self + .storage + .get_block_header_by_hash(new_tip_block.header().parent_hash())? + .ok_or_else(|| { + format_err!( + "Dag block should exist, block id: {:?}", + new_tip_block.header().parent_hash() + ) + })?; + let mut tips = self.current_tips_hash(parent_header.pruning_point())?; + + let mut new_tips = vec![]; + for hash in tips { + if !dag.check_ancestor_of(hash, vec![new_tip_block.id()])? { + new_tips.push(hash); } } + tips = new_tips; + tips.push(new_tip_block.id()); + // Caculate the ghostdata of the virutal node created by all tips. // And the ghostdata.selected of the tips will be the latest head. let block_hash = dag @@ -1522,10 +1532,20 @@ impl BlockChain { if self.epoch.end_block_number() == block.header().number() { self.epoch = get_epoch_from_statedb(&self.statedb)?; } - self.dag.save_dag_state( - executed_block.block().header().pruning_point(), - DagState { tips }, - )?; + + if new_tip_block.header().pruning_point() == block.header().pruning_point() { + self.dag + .save_dag_state(block.header().pruning_point(), DagState { tips })?; + } else { + let new_tips = dag.pruning_point_manager().prune( + &DagState { tips }, + block.header().pruning_point(), + new_tip_block.header().pruning_point(), + )?; + self.dag + .save_dag_state(block.header().pruning_point(), DagState { tips: new_tips })?; + } + Ok(executed_block) } } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 7209a2c430..89a573aac3 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -443,7 +443,7 @@ impl BlockDAG { pruning_depth: u64, pruning_finality: u64, ) -> anyhow::Result { - let dag_state = self.get_dag_state(block_header.id())?; + let dag_state = self.get_dag_state(block_header.pruning_point())?; let ghostdata = self.ghostdata(&dag_state.tips)?; let next_pruning_point = self.pruning_point_manager().next_pruning_point( diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 3f2b5695fd..06fe9f664f 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -14,6 +14,7 @@ use crate::sync::{CheckSyncEvent, SyncService}; use crate::tasks::{BlockConnectedEvent, BlockConnectedFinishEvent, BlockDiskCheckEvent}; use anyhow::{bail, format_err, Ok, Result}; use network_api::PeerProvider; +use starcoin_chain::BlockChain; use starcoin_chain_api::{ChainReader, ConnectBlockError, WriteableChainService}; use starcoin_config::{NodeConfig, G_CRATE_VERSION}; use starcoin_consensus::Consensus; @@ -378,30 +379,41 @@ where _msg: MinerRequest, ctx: &mut ServiceContext, ) -> ::Response { - let main = self.chain_service.get_main(); + let main_header = self.chain_service.get_main().status().head().clone(); let dag = self.chain_service.get_dag(); - let epoch = main.epoch().clone(); - let strategy = epoch.strategy(); - let on_chain_block_gas_limit = epoch.block_gas_limit(); + let (pruning_depth, pruning_finality) = ctx .get_shared::>()? .base() .net() .pruning_config(); + let MineNewDagBlockInfo { tips, blue_blocks, pruning_point, - } = dag.calc_mergeset_and_tips(main.status().head(), pruning_depth, pruning_finality)?; + } = dag.calc_mergeset_and_tips(&main_header, pruning_depth, pruning_finality)?; + if blue_blocks.is_empty() { bail!("failed to get the blue blocks from the DAG"); } - let selected_parent = blue_blocks.first().expect("the blue block must exist"); + let selected_parent = *blue_blocks + .first() + .ok_or_else(|| format_err!("the blue blocks must be not be 0!"))?; + + let time_service = self.config.net().time_service(); + let storage = ctx.get_shared::>()?; + let vm_metrics = ctx.get_shared_opt::()?; + let main = BlockChain::new(time_service, selected_parent, storage, vm_metrics, dag)?; + + let epoch = main.epoch().clone(); + let strategy = epoch.strategy(); + let on_chain_block_gas_limit = epoch.block_gas_limit(); let previous_header = main .get_storage() - .get_block_header_by_hash(*selected_parent)? + .get_block_header_by_hash(selected_parent)? .ok_or_else(|| format_err!("BlockHeader should exist by hash: {}", selected_parent))?; - let next_difficulty = epoch.strategy().calculate_next_difficulty(main)?; + let next_difficulty = epoch.strategy().calculate_next_difficulty(&main)?; let now_milliseconds = main.time_service().now_millis(); Ok(Box::new(MinerResponse { 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 bdc0992aa5..4cc259234f 100644 --- a/sync/src/block_connector/test_write_dag_block_chain.rs +++ b/sync/src/block_connector/test_write_dag_block_chain.rs @@ -50,7 +50,9 @@ pub fn new_dag_block( let miner_address = *miner.address(); let block_chain = writeable_block_chain_service.get_main(); - let tips = block_chain.current_tips_hash().expect("failed to get tips"); + let tips = block_chain + .current_tips_hash(block_chain.status().head().pruning_point()) + .expect("failed to get tips"); let (block_template, _) = block_chain .create_block_template( miner_address, diff --git a/sync/src/block_connector/write_block_chain.rs b/sync/src/block_connector/write_block_chain.rs index 36817a9eb3..a0f53d82f8 100644 --- a/sync/src/block_connector/write_block_chain.rs +++ b/sync/src/block_connector/write_block_chain.rs @@ -591,12 +591,11 @@ where return Ok(ConnectOk::Duplicate); } - if self.main.check_chain_type()? == ChainType::Dag - && !block - .header() - .parents_hash() - .iter() - .all(|parent_hash| self.main.dag().has_dag_block(*parent_hash).unwrap_or(false)) + if !block + .header() + .parents_hash() + .iter() + .all(|parent_hash| self.main.dag().has_dag_block(*parent_hash).unwrap_or(false)) { debug!( "block: {:?} is a future dag block, trigger sync to pull other dag blocks", From d012172748607e01f5f2d46e0c5c96a2883a29f9 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Thu, 12 Sep 2024 21:22:22 +0800 Subject: [PATCH 52/60] add verify pruning --- chain/api/src/chain.rs | 2 + chain/src/chain.rs | 50 ++++++++++--- chain/src/verifier/mod.rs | 40 +++++++++- config/src/genesis_config.rs | 35 +++++---- flexidag/src/blockdag.rs | 73 ++++++++++--------- flexidag/src/prune/pruning_point_manager.rs | 2 +- miner/src/create_block_template/mod.rs | 1 + .../block_connector_service.rs | 13 +++- sync/src/block_connector/write_block_chain.rs | 11 +-- 9 files changed, 154 insertions(+), 73 deletions(-) diff --git a/chain/api/src/chain.rs b/chain/api/src/chain.rs index 92116f2370..53bcdd2fb8 100644 --- a/chain/api/src/chain.rs +++ b/chain/api/src/chain.rs @@ -114,6 +114,8 @@ pub trait ChainReader { uncles: &[BlockHeader], header: &BlockHeader, ) -> Result; + fn is_dag_ancestor_of(&self, ancestor: HashValue, descendants: Vec) -> Result; + fn get_pruning_height(&self) -> BlockNumber; } pub trait ChainWriter { diff --git a/chain/src/chain.rs b/chain/src/chain.rs index a2b7e80988..9550a9d179 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -13,7 +13,6 @@ use starcoin_chain_api::{ ExcludedTxns, ExecutedBlock, MintedUncleNumber, TransactionInfoWithProof, VerifiedBlock, VerifyBlockField, }; -use starcoin_config::genesis_config::G_DAG_TEST_CONFIG; use starcoin_consensus::Consensus; use starcoin_crypto::hash::PlainCryptoHash; use starcoin_crypto::HashValue; @@ -319,11 +318,14 @@ impl BlockChain { pruning_point, // TODO: new test cases will need pass this field if they have some special requirements. } } else { - self.dag().calc_mergeset_and_tips( - &previous_header, - G_DAG_TEST_CONFIG.pruning_depth, - G_DAG_TEST_CONFIG.pruning_finality, - )? + let dag_state = self.get_dag_state()?; + let ghostdata = self.dag().ghost_dag_manager().ghostdag(&dag_state.tips)?; + + MineNewDagBlockInfo { + tips: dag_state.tips, + blue_blocks: (*ghostdata.mergeset_blues).clone(), + pruning_point: HashValue::zero(), + } }; debug!( "Blue blocks:{:?} in chain/create_block_template_by_header", @@ -1363,7 +1365,20 @@ impl ChainReader for BlockChain { uncles: &[BlockHeader], header: &BlockHeader, ) -> Result { - self.dag().verify_and_ghostdata(uncles, header) + let previous_header = self + .storage + .get_block_header_by_hash(header.parent_hash())? + .ok_or_else(|| format_err!("cannot find parent block header"))?; + self.dag() + .verify_and_ghostdata(uncles, header, previous_header.pruning_point()) + } + + fn is_dag_ancestor_of(&self, ancestor: HashValue, descendants: Vec) -> Result { + self.dag().check_ancestor_of(ancestor, descendants) + } + + fn get_pruning_height(&self) -> BlockNumber { + self.get_pruning_height() } } @@ -1533,14 +1548,14 @@ impl BlockChain { self.epoch = get_epoch_from_statedb(&self.statedb)?; } - if new_tip_block.header().pruning_point() == block.header().pruning_point() { + if parent_header.pruning_point() == block.header().pruning_point() { self.dag .save_dag_state(block.header().pruning_point(), DagState { tips })?; } else { let new_tips = dag.pruning_point_manager().prune( &DagState { tips }, + parent_header.pruning_point(), block.header().pruning_point(), - new_tip_block.header().pruning_point(), )?; self.dag .save_dag_state(block.header().pruning_point(), DagState { tips: new_tips })?; @@ -1548,6 +1563,23 @@ impl BlockChain { Ok(executed_block) } + + pub fn get_pruning_height(&self) -> BlockNumber { + let chain_id = self.status().head().chain_id(); + if chain_id.is_vega() { + 4000000 + } else if chain_id.is_proxima() { + 700000 + } else if chain_id.is_halley() { + 4200000 + } else if chain_id.is_main() { + 0 + } else if chain_id.is_dag_test() || chain_id.is_test() { + BlockNumber::MAX + } else { + 0 + } + } } impl ChainWriter for BlockChain { diff --git a/chain/src/verifier/mod.rs b/chain/src/verifier/mod.rs index 74fc59869d..03cd95d26d 100644 --- a/chain/src/verifier/mod.rs +++ b/chain/src/verifier/mod.rs @@ -7,6 +7,7 @@ use starcoin_chain_api::{ verify_block, ChainReader, ConnectBlockError, VerifiedBlock, VerifyBlockField, }; use starcoin_consensus::{Consensus, ConsensusVerifyError}; +use starcoin_crypto::HashValue; use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_logger::prelude::debug; use starcoin_open_block::AddressFilter; @@ -383,6 +384,33 @@ impl BasicDagVerifier { Ok::<(), ConnectBlockError>(()) })?; + // verify the pruning point + let parent_header = current_chain.current_header(); + if parent_header.pruning_point() != HashValue::zero() { + // the chain had pruning point already checking the descendants of the pruning point is a must + // check the parents are the descendants of the pruning point + parents_hash.iter().try_for_each(|parent_hash| { + verify_block!( + VerifyBlockField::Header, + current_chain.is_dag_ancestor_of(new_block_header.pruning_point(), vec![*parent_hash]).map_err(|e| { + ConnectBlockError::VerifyBlockFailed( + VerifyBlockField::Header, + anyhow::anyhow!( + "the block {:?} 's parent: {:?} is not the descendant of pruning point {:?}, error: {:?}", + new_block_header.id(), + parent_hash, + new_block_header.pruning_point(), + e + ), + ) + })?, + "Invalid block: parent {} might not exist.", + parent_hash + ); + Ok::<(), ConnectBlockError>(()) + })?; + } + ConsensusVerifier::verify_header(current_chain, new_block_header) } @@ -408,14 +436,18 @@ impl BlockVerifier for DagVerifier { } fn verify_uncles( - _current_chain: &R, - _uncles: &[BlockHeader], - _header: &BlockHeader, + current_chain: &R, + uncles: &[BlockHeader], + header: &BlockHeader, ) -> Result> where R: ChainReader, { - Ok(None) + Ok(Some(BasicDagVerifier::verify_blue_blocks( + current_chain, + uncles, + header, + )?)) } } diff --git a/config/src/genesis_config.rs b/config/src/genesis_config.rs index e479c4de8f..69483e1f29 100644 --- a/config/src/genesis_config.rs +++ b/config/src/genesis_config.rs @@ -754,6 +754,9 @@ static G_DEFAULT_BASE_REWARD_PER_BLOCK: Lazy> = pub static G_BASE_BLOCK_GAS_LIMIT: u64 = 50_000_000; //must big than maximum_number_of_gas_units +pub static G_PRUNING_DEPTH: u64 = 17280; +pub static G_PRUNING_FINALITY: u64 = 8640; + static G_EMPTY_BOOT_NODES: Lazy> = Lazy::new(Vec::new); const ONE_DAY: u64 = 86400; @@ -804,8 +807,8 @@ pub static G_DAG_TEST_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 1000, // 1h }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -857,8 +860,8 @@ pub static G_TEST_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 1000, // 1h }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -913,8 +916,8 @@ pub static G_DEV_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 1000, // 1h }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -974,8 +977,8 @@ pub static G_HALLEY_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 1000, // 1h }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -1036,8 +1039,8 @@ pub static G_PROXIMA_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, // todo: rollback it to zero and initialize BlockDag properly - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -1096,8 +1099,8 @@ pub static G_BARNARD_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 24 * 1000, // 1d }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -1170,8 +1173,8 @@ pub static G_MAIN_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 24 * 1000, // 1d }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); @@ -1228,8 +1231,8 @@ pub static G_VEGA_CONFIG: Lazy = Lazy::new(|| { min_action_delay: 60 * 60 * 24 * 1000, // 1d }, transaction_timeout: ONE_DAY, - pruning_depth: 17280, - pruning_finality: 8640, + pruning_depth: G_PRUNING_DEPTH, + pruning_finality: G_PRUNING_FINALITY, block_header_version: 1, } }); diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 89a573aac3..fff66b94b3 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -14,6 +14,7 @@ use crate::ghostdag::protocol::GhostdagManager; use crate::prune::pruning_point_manager::PruningPointManagerT; use crate::{process_key_already_error, reachability}; use anyhow::{bail, ensure, Ok}; +use starcoin_config::genesis_config::{G_PRUNING_DEPTH, G_PRUNING_FINALITY}; use starcoin_config::temp_dir; use starcoin_crypto::{HashValue as Hash, HashValue}; use starcoin_logger::prelude::{debug, info}; @@ -204,6 +205,7 @@ impl BlockDAG { trusted_ghostdata } }; + // Store ghostdata process_key_already_error( self.storage @@ -318,6 +320,7 @@ impl BlockDAG { } Some(ghostdata) => ghostdata, }; + // Store ghostdata process_key_already_error( self.storage @@ -439,20 +442,20 @@ impl BlockDAG { pub fn calc_mergeset_and_tips( &self, - block_header: &BlockHeader, + previous_header: &BlockHeader, pruning_depth: u64, pruning_finality: u64, ) -> anyhow::Result { - let dag_state = self.get_dag_state(block_header.pruning_point())?; + let dag_state = self.get_dag_state(previous_header.pruning_point())?; let ghostdata = self.ghostdata(&dag_state.tips)?; let next_pruning_point = self.pruning_point_manager().next_pruning_point( - block_header.pruning_point(), + previous_header.pruning_point(), &ghostdata, pruning_depth, pruning_finality, )?; - if next_pruning_point == block_header.pruning_point() { + if next_pruning_point == previous_header.pruning_point() { anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, blue_blocks: (*ghostdata.mergeset_blues).clone(), @@ -461,7 +464,7 @@ impl BlockDAG { } else { let pruned_tips = self.pruning_point_manager().prune( &dag_state, - block_header.pruning_point(), + previous_header.pruning_point(), next_pruning_point, )?; let mergeset_blues = (*self @@ -477,37 +480,35 @@ impl BlockDAG { } } - fn verify_pruning_point( + pub fn verify_pruning_point( &self, - pruning_depth: u64, - pruning_finality: u64, - block_header: &BlockHeader, - genesis_id: HashValue, + previous_pruning_point: HashValue, + next_pruning_point: HashValue, + ghostdata: &GhostdagData, ) -> anyhow::Result<()> { - let ghostdata = self.ghost_dag_manager().ghostdag(&block_header.parents())?; - let next_pruning_point = self.pruning_point_manager().next_pruning_point( - block_header.pruning_point(), - &ghostdata, - pruning_depth, - pruning_finality, + let inside_next_pruning_point = self.pruning_point_manager().next_pruning_point( + previous_pruning_point, + ghostdata, + G_PRUNING_DEPTH, + G_PRUNING_FINALITY, )?; - if (block_header.chain_id().is_vega() - || block_header.chain_id().is_proxima() - || block_header.chain_id().is_halley()) - && block_header.pruning_point() == HashValue::zero() - { - if next_pruning_point == genesis_id { - return anyhow::Ok(()); - } else { - bail!( - "pruning point is not correct, it should update the next pruning point: {}", - next_pruning_point - ); - } - } - if next_pruning_point != block_header.pruning_point() { - bail!("pruning point is not correct, the local next pruning point is {}, but the block header pruning point is {}", next_pruning_point, block_header.pruning_point()); + // if (block_header.chain_id().is_vega() + // || block_header.chain_id().is_proxima() + // || block_header.chain_id().is_halley()) + // && block_header.pruning_point() == HashValue::zero() + // { + // if next_pruning_point == genesis_id { + // return anyhow::Ok(()); + // } else { + // bail!( + // "pruning point is not correct, it should update the next pruning point: {}", + // next_pruning_point + // ); + // } + // } + if next_pruning_point != inside_next_pruning_point { + bail!("pruning point is not correct, the local next pruning point is {}, but the block header pruning point is {}", next_pruning_point, inside_next_pruning_point); } anyhow::Ok(()) } @@ -522,9 +523,13 @@ impl BlockDAG { &self, blue_blocks: &[BlockHeader], header: &BlockHeader, + previous_pruning_point: HashValue, ) -> Result { - self.ghost_dag_manager() - .verify_and_ghostdata(blue_blocks, header) + let ghostdata = self + .ghost_dag_manager() + .verify_and_ghostdata(blue_blocks, header)?; + self.verify_pruning_point(previous_pruning_point, header.pruning_point(), &ghostdata)?; + Ok(ghostdata) } pub fn check_upgrade(&self, main: &BlockHeader) -> anyhow::Result<()> { // set the state with key 0 diff --git a/flexidag/src/prune/pruning_point_manager.rs b/flexidag/src/prune/pruning_point_manager.rs index c795ac6d16..bbad1e23ae 100644 --- a/flexidag/src/prune/pruning_point_manager.rs +++ b/flexidag/src/prune/pruning_point_manager.rs @@ -43,7 +43,7 @@ impl PruningPointManagerT { current_pruning_point: HashValue, next_pruning_point: HashValue, ) -> anyhow::Result> { - if current_pruning_point == HashValue::zero() { + if current_pruning_point == next_pruning_point { return Ok(dag_state.tips.clone()); } anyhow::Ok( diff --git a/miner/src/create_block_template/mod.rs b/miner/src/create_block_template/mod.rs index 4b272acbac..3bae182df7 100644 --- a/miner/src/create_block_template/mod.rs +++ b/miner/src/create_block_template/mod.rs @@ -113,6 +113,7 @@ impl ServiceHandler for BlockBuilderService { .net() .genesis_config() .block_header_version; + self.inner.create_block_template(header_version) } } diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 06fe9f664f..758b912450 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -388,11 +388,22 @@ where .net() .pruning_config(); + // which height to prune the DAG + let MineNewDagBlockInfo { tips, blue_blocks, pruning_point, - } = dag.calc_mergeset_and_tips(&main_header, pruning_depth, pruning_finality)?; + } = if main_header.number() >= self.chain_service.get_main().get_pruning_height() { + dag.calc_mergeset_and_tips(&main_header, pruning_depth, pruning_finality)? + } else { + let tips = dag.get_dag_state(HashValue::zero())?.tips; + MineNewDagBlockInfo { + tips: tips.clone(), + blue_blocks: dag.ghostdata(&tips)?.mergeset_blues.as_ref().clone(), + pruning_point: HashValue::zero(), + } + }; if blue_blocks.is_empty() { bail!("failed to get the blue blocks from the DAG"); diff --git a/sync/src/block_connector/write_block_chain.rs b/sync/src/block_connector/write_block_chain.rs index a0f53d82f8..1802b713de 100644 --- a/sync/src/block_connector/write_block_chain.rs +++ b/sync/src/block_connector/write_block_chain.rs @@ -580,12 +580,6 @@ where fn connect_inner(&mut self, block: Block) -> Result { let block_id = block.id(); - if block_id == *starcoin_storage::BARNARD_HARD_FORK_HASH - && block.header().number() == starcoin_storage::BARNARD_HARD_FORK_HEIGHT - { - debug!("barnard hard fork {}", block_id); - return Err(ConnectBlockError::BarnardHardFork(Box::new(block)).into()); - } if self.main.current_header().id() == block_id { debug!("Repeat connect, current header is {} already.", block_id); return Ok(ConnectOk::Duplicate); @@ -614,7 +608,7 @@ where } let (block_info, fork) = self.find_or_fork(block.header())?; match (block_info, fork) { - //block has been processed in some branch, so just trigger a head selection. + // block has been processed in some branch, so just trigger a head selection. (Some(_block_info), Some(branch)) => { debug!( "Block {} has been processed, trigger head selection, total_difficulty: {}", @@ -624,7 +618,7 @@ where self.select_head(branch)?; Ok(ConnectOk::Duplicate) } - //block has been processed, and its parent is main chain, so just connect it to main chain. + // block has been processed, and its parent is main chain, so just connect it to main chain. (Some(block_info), None) => { let executed_block = self.main.connect(ExecutedBlock { block: block.clone(), @@ -637,6 +631,7 @@ where self.do_new_head(executed_block, 1, vec![block], 0, vec![])?; Ok(ConnectOk::Connect) } + // the block is not processed but its parent branch exists (None, Some(mut branch)) => { let _executed_block = branch.apply(block)?; self.select_head(branch)?; From f5f5dbf748e9ef4c4cfd4cb16261f44f18fc5815 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 10:30:29 +0800 Subject: [PATCH 53/60] add pruning height --- chain/src/chain.rs | 13 +++++++++++-- flexidag/src/blockdag.rs | 8 ++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 9550a9d179..6229e9e860 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1369,8 +1369,17 @@ impl ChainReader for BlockChain { .storage .get_block_header_by_hash(header.parent_hash())? .ok_or_else(|| format_err!("cannot find parent block header"))?; - self.dag() - .verify_and_ghostdata(uncles, header, previous_header.pruning_point()) + let ghostdata = self.dag().verify_and_ghostdata(uncles, header)?; + + if self.get_pruning_height() <= self.status().head().number() { + self.dag().verify_pruning_point( + previous_header.pruning_point(), + header.pruning_point(), + &ghostdata, + )?; + } + + Ok(ghostdata) } fn is_dag_ancestor_of(&self, ancestor: HashValue, descendants: Vec) -> Result { diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index fff66b94b3..e766c6a3b4 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -523,13 +523,9 @@ impl BlockDAG { &self, blue_blocks: &[BlockHeader], header: &BlockHeader, - previous_pruning_point: HashValue, ) -> Result { - let ghostdata = self - .ghost_dag_manager() - .verify_and_ghostdata(blue_blocks, header)?; - self.verify_pruning_point(previous_pruning_point, header.pruning_point(), &ghostdata)?; - Ok(ghostdata) + self.ghost_dag_manager() + .verify_and_ghostdata(blue_blocks, header) } pub fn check_upgrade(&self, main: &BlockHeader) -> anyhow::Result<()> { // set the state with key 0 From f0889746fb268c37f27d6aed0d86d0b714a6b35d Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 11:45:22 +0800 Subject: [PATCH 54/60] no checking the pruning point if the main header still dose not have the pruning point --- chain/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 6229e9e860..9db23c658d 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1371,7 +1371,7 @@ impl ChainReader for BlockChain { .ok_or_else(|| format_err!("cannot find parent block header"))?; let ghostdata = self.dag().verify_and_ghostdata(uncles, header)?; - if self.get_pruning_height() <= self.status().head().number() { + if self.status().head().pruning_point() != HashValue::zero() { self.dag().verify_pruning_point( previous_header.pruning_point(), header.pruning_point(), @@ -1583,7 +1583,7 @@ impl BlockChain { 4200000 } else if chain_id.is_main() { 0 - } else if chain_id.is_dag_test() || chain_id.is_test() { + } else if chain_id.is_dag_test() || chain_id.is_test() || chain_id.is_dev() { BlockNumber::MAX } else { 0 From 9c3a1ac108c433f28af7e18750ea954240a0ce95 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 19:26:03 +0800 Subject: [PATCH 55/60] add is ancestor of command for reachability viewing --- chain/api/src/message.rs | 7 +++++- chain/api/src/service.rs | 24 ++++++++++++++++++- chain/service/src/chain_service.rs | 6 +++++ chain/src/chain.rs | 2 +- cmd/starcoin/src/chain/mod.rs | 2 ++ flexidag/src/blockdag.rs | 22 ++++++++++++++++- flexidag/src/consensusdb/consenses_state.rs | 6 +++++ rpc/api/src/chain/mod.rs | 8 +++++++ rpc/client/src/lib.rs | 11 ++++++++- rpc/server/src/module/chain_rpc.rs | 12 ++++++++++ .../src/fork_chain.rs | 8 +++++++ 11 files changed, 103 insertions(+), 5 deletions(-) diff --git a/chain/api/src/message.rs b/chain/api/src/message.rs index 97e5a8d60b..3e28820552 100644 --- a/chain/api/src/message.rs +++ b/chain/api/src/message.rs @@ -4,7 +4,7 @@ use crate::{ChainType, TransactionInfoWithProof}; use anyhow::Result; use starcoin_crypto::HashValue; -use starcoin_dag::consensusdb::consenses_state::DagStateView; +use starcoin_dag::consensusdb::consenses_state::{DagStateView, ReachabilityView}; use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_service_registry::ServiceRequest; use starcoin_types::transaction::RichTransactionInfo; @@ -68,6 +68,10 @@ pub enum ChainRequest { GetDagStateView, CheckChainType, GetGhostdagData(HashValue), + IsAncestorOfCommand { + ancestor: HashValue, + descendants: Vec, + }, } impl ServiceRequest for ChainRequest { @@ -99,4 +103,5 @@ pub enum ChainResponse { DagStateView(Box), CheckChainType(ChainType), GhostdagDataOption(Box>), + IsAncestorOfCommand { reachability_view: ReachabilityView }, } diff --git a/chain/api/src/service.rs b/chain/api/src/service.rs index 4017174a14..4c78839d4a 100644 --- a/chain/api/src/service.rs +++ b/chain/api/src/service.rs @@ -5,7 +5,7 @@ use crate::message::{ChainRequest, ChainResponse}; use crate::{ChainType, TransactionInfoWithProof}; use anyhow::{bail, Result}; use starcoin_crypto::HashValue; -use starcoin_dag::consensusdb::consenses_state::DagStateView; +use starcoin_dag::consensusdb::consenses_state::{DagStateView, ReachabilityView}; use starcoin_dag::types::ghostdata::GhostdagData; use starcoin_service_registry::{ActorService, ServiceHandler, ServiceRef}; use starcoin_types::contract_event::{ContractEvent, ContractEventInfo}; @@ -149,6 +149,11 @@ pub trait ChainAsyncService: async fn get_dag_state(&self) -> Result; async fn check_chain_type(&self) -> Result; async fn get_ghostdagdata(&self, id: HashValue) -> Result>; + async fn is_ancestor_of( + &self, + ancestor: HashValue, + descendants: Vec, + ) -> Result; } #[async_trait::async_trait] @@ -486,4 +491,21 @@ where bail!("failed to get ghostdag data") } } + async fn is_ancestor_of( + &self, + ancestor: HashValue, + descendants: Vec, + ) -> Result { + let response = self + .send(ChainRequest::IsAncestorOfCommand { + ancestor, + descendants, + }) + .await??; + if let ChainResponse::IsAncestorOfCommand { reachability_view } = response { + Ok(reachability_view) + } else { + bail!("failed to get ghostdag data") + } + } } diff --git a/chain/service/src/chain_service.rs b/chain/service/src/chain_service.rs index 422a70130e..99537ffe5a 100644 --- a/chain/service/src/chain_service.rs +++ b/chain/service/src/chain_service.rs @@ -254,6 +254,12 @@ impl ServiceHandler for ChainReaderService { ChainRequest::GetGhostdagData(id) => Ok(ChainResponse::GhostdagDataOption(Box::new( self.inner.get_ghostdagdata(id)?, ))), + ChainRequest::IsAncestorOfCommand { + ancestor, + descendants, + } => Ok(ChainResponse::IsAncestorOfCommand { + reachability_view: self.inner.dag.is_ancestor_of(ancestor, descendants)?, + }), } } } diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 9db23c658d..d88b23408e 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1578,7 +1578,7 @@ impl BlockChain { if chain_id.is_vega() { 4000000 } else if chain_id.is_proxima() { - 700000 + 500 } else if chain_id.is_halley() { 4200000 } else if chain_id.is_main() { diff --git a/cmd/starcoin/src/chain/mod.rs b/cmd/starcoin/src/chain/mod.rs index c004e3c96f..7206ffbad9 100644 --- a/cmd/starcoin/src/chain/mod.rs +++ b/cmd/starcoin/src/chain/mod.rs @@ -12,6 +12,7 @@ mod get_txn_info_list_cmd; mod get_txn_infos_cmd; pub mod get_txn_proof_cmd; mod info_cmd; +mod is_ancestor_of_cmd; mod list_block_cmd; pub use epoch_info::*; @@ -24,4 +25,5 @@ pub use get_txn_info_cmd::*; pub use get_txn_info_list_cmd::*; pub use get_txn_infos_cmd::*; pub use info_cmd::*; +pub use is_ancestor_of_cmd::*; pub use list_block_cmd::*; diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index e766c6a3b4..6510baedc4 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -1,6 +1,8 @@ use super::reachability::{inquirer, reachability_service::MTReachabilityService}; use super::types::ghostdata::GhostdagData; -use crate::consensusdb::consenses_state::{DagState, DagStateReader, DagStateStore}; +use crate::consensusdb::consenses_state::{ + DagState, DagStateReader, DagStateStore, ReachabilityView, +}; use crate::consensusdb::prelude::{FlexiDagStorageConfig, StoreError}; use crate::consensusdb::schemadb::{GhostdagStoreReader, ReachabilityStore, REINDEX_ROOT_KEY}; use crate::consensusdb::{ @@ -579,4 +581,22 @@ impl BlockDAG { anyhow::Ok(()) } + + pub fn is_ancestor_of( + &self, + ancestor: Hash, + descendants: Vec, + ) -> anyhow::Result { + let de = descendants + .into_iter() + .filter(|descendant| { + self.check_ancestor_of(ancestor, vec![*descendant]) + .unwrap_or(false) + }) + .collect::>(); + anyhow::Ok(ReachabilityView { + ancestor, + descendants: de, + }) + } } diff --git a/flexidag/src/consensusdb/consenses_state.rs b/flexidag/src/consensusdb/consenses_state.rs index 229e790db3..8dcf852d3b 100644 --- a/flexidag/src/consensusdb/consenses_state.rs +++ b/flexidag/src/consensusdb/consenses_state.rs @@ -84,3 +84,9 @@ impl DagStateView { DagState { tips: self.tips } } } + +#[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug, JsonSchema)] +pub struct ReachabilityView { + pub ancestor: Hash, + pub descendants: Vec, +} diff --git a/rpc/api/src/chain/mod.rs b/rpc/api/src/chain/mod.rs index ea4a80afd3..ae95e33f90 100644 --- a/rpc/api/src/chain/mod.rs +++ b/rpc/api/src/chain/mod.rs @@ -132,6 +132,14 @@ pub trait ChainApi { /// Get block ghostdag data #[rpc(name = "chain.get_ghostdagdata")] fn get_ghostdagdata(&self, block_hash: HashValue) -> FutureResult>; + + /// Check the ancestor and descendants' relationship + #[rpc(name = "chain.is_ancestor_of")] + fn is_ancestor_of( + &self, + ancestor: HashValue, + descendants: Vec, + ) -> FutureResult; } #[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)] diff --git a/rpc/client/src/lib.rs b/rpc/client/src/lib.rs index 569ff82333..d8fbc5ad47 100644 --- a/rpc/client/src/lib.rs +++ b/rpc/client/src/lib.rs @@ -21,7 +21,7 @@ use serde_json::Value; use starcoin_abi_types::{FunctionABI, ModuleABI, StructInstantiation}; use starcoin_account_api::AccountInfo; use starcoin_crypto::HashValue; -use starcoin_dag::consensusdb::consenses_state::DagStateView; +use starcoin_dag::consensusdb::consenses_state::{DagStateView, ReachabilityView}; use starcoin_logger::{prelude::*, LogPattern}; use starcoin_rpc_api::chain::{ GetBlockOption, GetBlocksOption, GetEventOption, GetTransactionOption, @@ -790,6 +790,15 @@ impl RpcClient { .map_err(map_err) } + pub fn is_ancestor_of( + &self, + ancestor: HashValue, + descendants: Vec, + ) -> anyhow::Result { + self.call_rpc_blocking(|inner| inner.chain_client.is_ancestor_of(ancestor, descendants)) + .map_err(map_err) + } + pub fn chain_get_blocks_by_number( &self, number: Option, diff --git a/rpc/server/src/module/chain_rpc.rs b/rpc/server/src/module/chain_rpc.rs index dedee3b0e6..ea78017804 100644 --- a/rpc/server/src/module/chain_rpc.rs +++ b/rpc/server/src/module/chain_rpc.rs @@ -485,6 +485,18 @@ where let fut = async move { service.get_ghostdagdata(block_hash).await }.map_err(map_err); Box::pin(fut.boxed()) } + + #[doc = " Check the ancestor and descendants\' relationship "] + fn is_ancestor_of( + &self, + ancestor: HashValue, + descendants: Vec, + ) -> FutureResult { + let service = self.service.clone(); + let fut = + async move { service.is_ancestor_of(ancestor, descendants).await }.map_err(map_err); + Box::pin(fut.boxed()) + } } fn try_decode_block_txns(state: &dyn StateView, block: &mut BlockView) -> anyhow::Result<()> { diff --git a/vm/starcoin-transactional-test-harness/src/fork_chain.rs b/vm/starcoin-transactional-test-harness/src/fork_chain.rs index bebaaa1d0d..bcb118ca1b 100644 --- a/vm/starcoin-transactional-test-harness/src/fork_chain.rs +++ b/vm/starcoin-transactional-test-harness/src/fork_chain.rs @@ -505,6 +505,14 @@ impl ChainApi for MockChainApi { fn get_ghostdagdata(&self, _block_hash: HashValue) -> FutureResult> { unimplemented!() } + + fn is_ancestor_of( + &self, + _ancestor: HashValue, + _descendants: Vec, + ) -> FutureResult { + unimplemented!() + } } fn try_decode_block_txns(state: &dyn StateView, block: &mut BlockView) -> anyhow::Result<()> { From 2a358fdeb96efecd5ce03a69dff83d8388abab29 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 19:41:32 +0800 Subject: [PATCH 56/60] add command file --- cmd/starcoin/src/chain/is_ancestor_of_cmd.rs | 46 ++++++++++++++++++++ cmd/starcoin/src/lib.rs | 3 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 cmd/starcoin/src/chain/is_ancestor_of_cmd.rs diff --git a/cmd/starcoin/src/chain/is_ancestor_of_cmd.rs b/cmd/starcoin/src/chain/is_ancestor_of_cmd.rs new file mode 100644 index 0000000000..cfb9d74676 --- /dev/null +++ b/cmd/starcoin/src/chain/is_ancestor_of_cmd.rs @@ -0,0 +1,46 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +use std::str::FromStr; + +use crate::cli_state::CliState; +use crate::StarcoinOpt; +use anyhow::Result; +use clap::Parser; +use scmd::{CommandAction, ExecContext}; +use starcoin_crypto::HashValue; +use starcoin_dag::consensusdb::consenses_state::ReachabilityView; + +/// Get block info by number +#[derive(Debug, Parser, Clone)] +#[clap(name = "is-ancestor-of", alias = "is_ancestor_of")] +pub struct IsAncestorOfOpt { + #[clap(name = "ancestor", long, short = 'a')] + ancestor: String, + + #[clap(name = "descendants", long, short = 'd')] + descendants: Vec, +} + +pub struct IsAncestorOfCommand; + +impl CommandAction for IsAncestorOfCommand { + type State = CliState; + type GlobalOpt = StarcoinOpt; + type Opt = IsAncestorOfOpt; + type ReturnItem = ReachabilityView; + + fn run( + &self, + ctx: &ExecContext, + ) -> Result { + let opt = ctx.opt().clone(); + ctx.state().client().is_ancestor_of( + HashValue::from_str(&opt.ancestor)?, + opt.descendants + .into_iter() + .map(|id| HashValue::from_str(&id).map_err(|e| anyhow::anyhow!("{:?}", e))) + .collect::>>()?, + ) + } +} diff --git a/cmd/starcoin/src/lib.rs b/cmd/starcoin/src/lib.rs index bc2114cc75..4a5ef258fc 100644 --- a/cmd/starcoin/src/lib.rs +++ b/cmd/starcoin/src/lib.rs @@ -103,7 +103,8 @@ pub fn add_command( .subcommand(chain::GetTransactionInfoListCommand) .subcommand(chain::get_txn_proof_cmd::GetTransactionProofCommand) .subcommand(chain::GetBlockInfoCommand) - .subcommand(chain::GetDagStateCommand), + .subcommand(chain::GetDagStateCommand) + .subcommand(chain::IsAncestorOfCommand), ) .command( CustomCommand::with_name("txpool") From 163e7b27ae344c1cd0e062ab906bccbd10259163 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 19:59:03 +0800 Subject: [PATCH 57/60] use 850000 --- chain/src/chain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index d88b23408e..f1b91bbc39 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1578,7 +1578,7 @@ impl BlockChain { if chain_id.is_vega() { 4000000 } else if chain_id.is_proxima() { - 500 + 850000 } else if chain_id.is_halley() { 4200000 } else if chain_id.is_main() { From 31e0321669494be3c4ff0892a3c700c3b838e6b2 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Fri, 13 Sep 2024 20:54:19 +0800 Subject: [PATCH 58/60] add rpc json new command --- rpc/api/generated_rpc_schema/chain.json | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/rpc/api/generated_rpc_schema/chain.json b/rpc/api/generated_rpc_schema/chain.json index 3f6243e7c9..e79576d8c2 100644 --- a/rpc/api/generated_rpc_schema/chain.json +++ b/rpc/api/generated_rpc_schema/chain.json @@ -4173,6 +4173,57 @@ } } } + }, + { + "name": "chain.is_ancestor_of", + "params": [ + { + "name": "ancestor", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "HashValue", + "type": "string", + "format": "HashValue" + } + }, + { + "name": "descendants", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_HashValue", + "type": "array", + "items": { + "type": "string", + "format": "HashValue" + } + } + } + ], + "result": { + "name": "starcoin_dag :: consensusdb :: consenses_state :: ReachabilityView", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ReachabilityView", + "type": "object", + "required": [ + "ancestor", + "descendants" + ], + "properties": { + "ancestor": { + "type": "string", + "format": "HashValue" + }, + "descendants": { + "type": "array", + "items": { + "type": "string", + "format": "HashValue" + } + } + } + } + } } ] } \ No newline at end of file From df3ed292183594b68d8f0aaa37699c3956d9dde5 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sat, 14 Sep 2024 11:43:42 +0800 Subject: [PATCH 59/60] add some log for debug --- chain/src/chain.rs | 5 ++++- flexidag/src/blockdag.rs | 15 ++++++++++++++- kube/manifest/starcoin-proxima.yaml | 16 ++-------------- network/src/network_p2p_handle.rs | 2 +- .../block_connector/block_connector_service.rs | 1 + sync/src/parallel/executor.rs | 6 ++++++ sync/src/parallel/sender.rs | 2 ++ 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index f1b91bbc39..3eac8e10f0 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1558,14 +1558,17 @@ impl BlockChain { } if parent_header.pruning_point() == block.header().pruning_point() { + info!("pruning point not changed, save dag state without prune. tips are {:?}, pruning point is {:?}", tips, block.header().pruning_point()); self.dag .save_dag_state(block.header().pruning_point(), DagState { tips })?; } else { let new_tips = dag.pruning_point_manager().prune( - &DagState { tips }, + &DagState { tips: tips.clone() }, parent_header.pruning_point(), block.header().pruning_point(), )?; + info!("pruning point changed, previous tips are: {:?}, save dag state with prune. tips are {:?}, previous pruning point is {:?}, current pruning point is {:?}", + tips, new_tips, parent_header.pruning_point(), block.header().pruning_point()); self.dag .save_dag_state(block.header().pruning_point(), DagState { tips: new_tips })?; } diff --git a/flexidag/src/blockdag.rs b/flexidag/src/blockdag.rs index 6510baedc4..dfb05ccd82 100644 --- a/flexidag/src/blockdag.rs +++ b/flexidag/src/blockdag.rs @@ -450,13 +450,21 @@ impl BlockDAG { ) -> anyhow::Result { let dag_state = self.get_dag_state(previous_header.pruning_point())?; let ghostdata = self.ghostdata(&dag_state.tips)?; - + info!( + "start to calculate the mergeset and tips for tips: {:?}, and last pruning point: {:?} and ghostdata: {:?}", + dag_state.tips, previous_header.pruning_point(), ghostdata, + ); let next_pruning_point = self.pruning_point_manager().next_pruning_point( previous_header.pruning_point(), &ghostdata, pruning_depth, pruning_finality, )?; + info!( + "the next pruning point is: {:?}, and the previous pruning point is: {:?}", + next_pruning_point, + previous_header.pruning_point() + ); if next_pruning_point == previous_header.pruning_point() { anyhow::Ok(MineNewDagBlockInfo { tips: dag_state.tips, @@ -474,6 +482,11 @@ impl BlockDAG { .ghostdag(&pruned_tips)? .mergeset_blues) .clone(); + info!( + "previous tips are: {:?}, the pruned tips are: {:?}, the mergeset blues are: {:?}, the next pruning point is: {:?}", + dag_state.tips, + pruned_tips, mergeset_blues, next_pruning_point + ); anyhow::Ok(MineNewDagBlockInfo { tips: pruned_tips, blue_blocks: mergeset_blues, diff --git a/kube/manifest/starcoin-proxima.yaml b/kube/manifest/starcoin-proxima.yaml index 71294b8665..dd8476ae67 100644 --- a/kube/manifest/starcoin-proxima.yaml +++ b/kube/manifest/starcoin-proxima.yaml @@ -23,13 +23,13 @@ spec: starcoin/node-pool: seed-pool containers: - name: starcoin - image: ghcr.io/starcoinorg/starcoin:dag-master + image: ghcr.io/starcoinorg/starcoin:pruning-point imagePullPolicy: Always command: - bash - -c args: - - rm -rf /sc-data/proxima/ /sc-data/proxima/starcoindb/db/starcoindb/LOCK; + - rm -rf /sc-data/proxima/starcoindb/db/starcoindb/LOCK /sc-data/proxima/genesis_config.json; id=$(echo -e $POD_NAME|awk -F'-' '{print $2}') && IFS='; ' read -r -a node_keys <<< $NODE_KEYS && node_key=${node_keys[$id]}; if [ ! -z $node_key ]; then @@ -70,18 +70,6 @@ spec: timeoutSeconds: 2 failureThreshold: 3 successThreshold: 1 - readinessProbe: - exec: - command: - - sh - - -c - - >- - /starcoin/starcoin -n proxima -d /sc-data node sync status|grep Synchronized - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 2 - failureThreshold: 3 - successThreshold: 1 volumeClaimTemplates: - metadata: name: starcoin-volume diff --git a/network/src/network_p2p_handle.rs b/network/src/network_p2p_handle.rs index 8a61623fc0..95dc994e0d 100644 --- a/network/src/network_p2p_handle.rs +++ b/network/src/network_p2p_handle.rs @@ -97,7 +97,7 @@ impl BusinessLayerHandle for Networkp2pHandle { match Status::decode(&received_handshake[..]) { Result::Ok(status) => self.inner_handshake(peer_id, status), Err(err) => { - error!(target: "network-p2p", "Couldn't decode handshake packet sent by {}: {:?}: {}", peer_id, hex::encode(received_handshake), err); + error!(target: "network-p2p", "Couldn't decode handshake packet sent by {}, err: {}", peer_id, err); Err(rep::BAD_MESSAGE) } } diff --git a/sync/src/block_connector/block_connector_service.rs b/sync/src/block_connector/block_connector_service.rs index 758b912450..c31608bb21 100644 --- a/sync/src/block_connector/block_connector_service.rs +++ b/sync/src/block_connector/block_connector_service.rs @@ -395,6 +395,7 @@ where blue_blocks, pruning_point, } = if main_header.number() >= self.chain_service.get_main().get_pruning_height() { + info!("now calculate the next pruning point"); dag.calc_mergeset_and_tips(&main_header, pruning_depth, pruning_finality)? } else { let tips = dag.get_dag_state(HashValue::zero())?.tips; diff --git a/sync/src/parallel/executor.rs b/sync/src/parallel/executor.rs index 5279dec192..eb6014504a 100644 --- a/sync/src/parallel/executor.rs +++ b/sync/src/parallel/executor.rs @@ -80,6 +80,12 @@ impl DagBlockExecutor { }; let header = block.header().clone(); + info!( + "sync parallel worker {:p} received block: {:?}", + &self, + block.header().id() + ); + loop { match Self::waiting_for_parents( &self.dag, diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index f4a5f71cbf..81485e3680 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -66,6 +66,7 @@ impl<'a> DagBlockSender<'a> { || block.header.parents_hash().contains(header_id) { executor.state = ExecuteState::Executing(block.id()); + info!("send block {:?} to executor {:p}", block.id(), &executor); executor .sender_to_executor .send(Some(block.clone())) @@ -83,6 +84,7 @@ impl<'a> DagBlockSender<'a> { match &executor.state { ExecuteState::Executed(_) => { executor.state = ExecuteState::Executing(block.id()); + info!("send block {:?} to executor {:p}", block.id(), &executor); executor .sender_to_executor .send(Some(block.clone())) From ef9acf7104fc388eaa6bc21e4bc14cb6b00f2997 Mon Sep 17 00:00:00 2001 From: jackzhhuang Date: Sat, 14 Sep 2024 14:22:00 +0800 Subject: [PATCH 60/60] dispatch the block to the workers by the selected parent --- sync/src/parallel/sender.rs | 98 ++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/sync/src/parallel/sender.rs b/sync/src/parallel/sender.rs index 81485e3680..2a8d28afa2 100644 --- a/sync/src/parallel/sender.rs +++ b/sync/src/parallel/sender.rs @@ -62,9 +62,7 @@ impl<'a> DagBlockSender<'a> { for executor in &mut self.executors { match &executor.state { ExecuteState::Executing(header_id) => { - if *header_id == block.header().parent_hash() - || block.header.parents_hash().contains(header_id) - { + if *header_id == block.header().parent_hash() { executor.state = ExecuteState::Executing(block.id()); info!("send block {:?} to executor {:p}", block.id(), &executor); executor @@ -80,23 +78,25 @@ impl<'a> DagBlockSender<'a> { } } - for executor in &mut self.executors { - match &executor.state { - ExecuteState::Executed(_) => { - executor.state = ExecuteState::Executing(block.id()); - info!("send block {:?} to executor {:p}", block.id(), &executor); - executor - .sender_to_executor - .send(Some(block.clone())) - .await?; - return anyhow::Ok(true); - } - - ExecuteState::Executing(_) | ExecuteState::Error(_) | ExecuteState::Closed => { - continue; - } - } - } + // for executor in &mut self.executors { + // match &executor.state { + // ExecuteState::Executed(executed_block) => { + // if executed_block.block().header().id() == block.header().parent_hash() { + // executor.state = ExecuteState::Executing(block.id()); + // info!("send block {:?} to executor {:p}", block.id(), &executor); + // executor + // .sender_to_executor + // .send(Some(block.clone())) + // .await?; + // return anyhow::Ok(true); + // } + // } + + // ExecuteState::Executing(_) | ExecuteState::Error(_) | ExecuteState::Closed => { + // continue; + // } + // } + // } anyhow::Ok(false) } @@ -112,7 +112,7 @@ impl<'a> DagBlockSender<'a> { // Finding the executing state is the priority if self.dispatch_to_worker(&block).await? { - self.flush_executor_state().await?; + // self.flush_executor_state().await?; continue; } @@ -137,7 +137,7 @@ impl<'a> DagBlockSender<'a> { sender_to_worker.send(Some(block)).await?; - self.flush_executor_state().await?; + // self.flush_executor_state().await?; } self.wait_for_finish().await?; @@ -146,33 +146,33 @@ impl<'a> DagBlockSender<'a> { Ok(()) } - async fn flush_executor_state(&mut self) -> anyhow::Result<()> { - for worker in &mut self.executors { - match worker.receiver_from_executor.try_recv() { - Ok(state) => { - if let ExecuteState::Executed(executed_block) = state { - info!("finish to execute block {:?}", executed_block.header()); - self.notifier.notify((*executed_block).clone())?; - worker.state = ExecuteState::Executed(executed_block); - } - } - Err(e) => match e { - mpsc::error::TryRecvError::Empty => (), - mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, - }, - } - } - - let len = self.executors.len(); - self.executors - .retain(|worker| !matches!(worker.state, ExecuteState::Closed)); - - if len != self.executors.len() { - info!("sync workers count: {:?}", self.executors.len()); - } - - anyhow::Ok(()) - } + // async fn flush_executor_state(&mut self) -> anyhow::Result<()> { + // for worker in &mut self.executors { + // match worker.receiver_from_executor.try_recv() { + // Ok(state) => { + // if let ExecuteState::Executed(executed_block) = state { + // info!("finish to execute block {:?}", executed_block.header()); + // self.notifier.notify((*executed_block).clone())?; + // worker.state = ExecuteState::Executed(executed_block); + // } + // } + // Err(e) => match e { + // mpsc::error::TryRecvError::Empty => (), + // mpsc::error::TryRecvError::Disconnected => worker.state = ExecuteState::Closed, + // }, + // } + // } + + // let len = self.executors.len(); + // self.executors + // .retain(|worker| !matches!(worker.state, ExecuteState::Closed)); + + // if len != self.executors.len() { + // info!("sync workers count: {:?}", self.executors.len()); + // } + + // anyhow::Ok(()) + // } async fn wait_for_finish(mut self) -> anyhow::Result<()> { // tell the workers to exit