Skip to content

Commit

Permalink
Merge ef9acf7 into 85564ab
Browse files Browse the repository at this point in the history
  • Loading branch information
jackzhhuang authored Sep 14, 2024
2 parents 85564ab + ef9acf7 commit bb8d060
Show file tree
Hide file tree
Showing 44 changed files with 1,807 additions and 394 deletions.
18 changes: 16 additions & 2 deletions chain/api/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<GhostdagData>,
}
pub type MintedUncleNumber = u64;

pub trait ChainReader {
Expand Down Expand Up @@ -102,9 +106,16 @@ pub trait ChainReader {
access_path: Option<AccessPath>,
) -> Result<Option<TransactionInfoWithProof>>;

fn current_tips_hash(&self) -> Result<Vec<HashValue>>;
fn current_tips_hash(&self, pruning_point: HashValue) -> Result<Vec<HashValue>>;
fn has_dag_block(&self, header_id: HashValue) -> Result<bool>;
fn check_chain_type(&self) -> Result<ChainType>;
fn verify_and_ghostdata(
&self,
uncles: &[BlockHeader],
header: &BlockHeader,
) -> Result<GhostdagData>;
fn is_dag_ancestor_of(&self, ancestor: HashValue, descendants: Vec<HashValue>) -> Result<bool>;
fn get_pruning_height(&self) -> BlockNumber;
}

pub trait ChainWriter {
Expand All @@ -115,6 +126,9 @@ pub trait ChainWriter {
/// Verify, Execute and Connect block to current chain.
fn apply(&mut self, block: Block) -> Result<ExecutedBlock>;

/// Verify, Execute and Connect block to current chain.
fn apply_for_sync(&mut self, block: Block) -> Result<ExecutedBlock>;

fn chain_state(&mut self) -> &ChainStateDB;
}

Expand Down
7 changes: 6 additions & 1 deletion chain/api/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -68,6 +68,10 @@ pub enum ChainRequest {
GetDagStateView,
CheckChainType,
GetGhostdagData(HashValue),
IsAncestorOfCommand {
ancestor: HashValue,
descendants: Vec<HashValue>,
},
}

impl ServiceRequest for ChainRequest {
Expand Down Expand Up @@ -99,4 +103,5 @@ pub enum ChainResponse {
DagStateView(Box<DagStateView>),
CheckChainType(ChainType),
GhostdagDataOption(Box<Option<GhostdagData>>),
IsAncestorOfCommand { reachability_view: ReachabilityView },
}
24 changes: 23 additions & 1 deletion chain/api/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -149,6 +149,11 @@ pub trait ChainAsyncService:
async fn get_dag_state(&self) -> Result<DagStateView>;
async fn check_chain_type(&self) -> Result<ChainType>;
async fn get_ghostdagdata(&self, id: HashValue) -> Result<Option<GhostdagData>>;
async fn is_ancestor_of(
&self,
ancestor: HashValue,
descendants: Vec<HashValue>,
) -> Result<starcoin_dag::consensusdb::consenses_state::ReachabilityView>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -486,4 +491,21 @@ where
bail!("failed to get ghostdag data")
}
}
async fn is_ancestor_of(
&self,
ancestor: HashValue,
descendants: Vec<HashValue>,
) -> Result<ReachabilityView> {
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")
}
}
}
6 changes: 6 additions & 0 deletions chain/service/src/chain_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ impl ServiceHandler<Self, ChainRequest> 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)?,
}),
}
}
}
Expand Down
149 changes: 118 additions & 31 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -178,7 +177,7 @@ impl BlockChain {
}

fn init_dag(mut dag: BlockDAG, genesis_header: BlockHeader) -> Result<BlockDAG> {
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>()? {
StoreError::KeyNotFound(_) => {
Expand Down Expand Up @@ -319,10 +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(
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",
Expand Down Expand Up @@ -458,8 +461,8 @@ impl BlockChain {
}

fn execute_dag_block(&mut self, verified_block: VerifiedBlock) -> Result<ExecutedBlock> {
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
Expand Down Expand Up @@ -645,9 +648,16 @@ 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) => {
Expand Down Expand Up @@ -976,7 +986,7 @@ impl BlockChain {
}

pub fn get_dag_state(&self) -> Result<DagState> {
self.dag.get_dag_state()
self.dag.get_dag_state(self.status().head().pruning_point())
}
}

Expand Down Expand Up @@ -1210,8 +1220,7 @@ impl ChainReader for BlockChain {
}

fn verify(&self, block: Block) -> Result<VerifiedBlock> {
DagVerifier::verify_header(self, block.header())?;
Ok(VerifiedBlock(block))
DagVerifier::verify_block(self, block)
}

fn execute(&mut self, verified_block: VerifiedBlock) -> Result<ExecutedBlock> {
Expand All @@ -1225,7 +1234,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(),
)
}
Expand Down Expand Up @@ -1328,8 +1337,10 @@ impl ChainReader for BlockChain {
}))
}

fn current_tips_hash(&self) -> Result<Vec<HashValue>> {
self.dag.get_dag_state().map(|state| state.tips)
fn current_tips_hash(&self, pruning_point: HashValue) -> Result<Vec<HashValue>> {
self.dag
.get_dag_state(pruning_point)
.map(|state| state.tips)
}

fn has_dag_block(&self, header_id: HashValue) -> Result<bool> {
Expand All @@ -1348,6 +1359,36 @@ impl ChainReader for BlockChain {
fn check_chain_type(&self) -> Result<ChainType> {
Ok(ChainType::Dag)
}

fn verify_and_ghostdata(
&self,
uncles: &[BlockHeader],
header: &BlockHeader,
) -> Result<starcoin_dag::types::ghostdata::GhostdagData> {
let previous_header = self
.storage
.get_block_header_by_hash(header.parent_hash())?
.ok_or_else(|| format_err!("cannot find parent block header"))?;
let ghostdata = self.dag().verify_and_ghostdata(uncles, header)?;

if self.status().head().pruning_point() != HashValue::zero() {
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<HashValue>) -> Result<bool> {
self.dag().check_ancestor_of(ancestor, descendants)
}

fn get_pruning_height(&self) -> BlockNumber {
self.get_pruning_height()
}
}

impl BlockChain {
Expand Down Expand Up @@ -1455,22 +1496,31 @@ impl BlockChain {
fn connect_dag(&mut self, executed_block: ExecutedBlock) -> Result<ExecutedBlock> {
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 = {
let ghost_of_tips = dag.ghostdata(tips.as_slice())?;
ghost_of_tips.selected_parent
};
let block_hash = dag
.ghost_dag_manager()
.find_selected_parent(tips.iter().copied())?;
let (block, block_info) = {
let block = self
.storage
Expand Down Expand Up @@ -1506,9 +1556,42 @@ 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 })?;

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: 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 })?;
}

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() {
850000
} 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() || chain_id.is_dev() {
BlockNumber::MAX
} else {
0
}
}
}

impl ChainWriter for BlockChain {
Expand All @@ -1532,6 +1615,10 @@ impl ChainWriter for BlockChain {
fn chain_state(&mut self) -> &ChainStateDB {
&self.statedb
}

fn apply_for_sync(&mut self, block: Block) -> Result<ExecutedBlock> {
self.apply_with_verifier::<DagVerifierWithGhostData>(block)
}
}

pub(crate) fn info_2_accumulator(
Expand Down
Loading

0 comments on commit bb8d060

Please sign in to comment.