Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pruning logic #4194

Merged
merged 65 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
542e612
add parallel code
jackzhhuang Aug 28, 2024
a4f0fe3
parallel execution
jackzhhuang Aug 28, 2024
0f0aa78
create chain when the parents are ready in parallel execution
jackzhhuang Aug 28, 2024
11102f9
set executing state in sender
jackzhhuang Aug 28, 2024
22b78f9
add 10000 buffer for parallel execution
jackzhhuang Aug 29, 2024
2455ef6
add log for saving time
jackzhhuang Aug 29, 2024
ca45ef7
add some test
jackzhhuang Sep 2, 2024
e11b137
add false testing case
jackzhhuang Sep 2, 2024
6ca87e3
add more testing code
jackzhhuang Sep 2, 2024
67741c3
add check data
jackzhhuang Sep 3, 2024
86f1817
add verify blue block in verifier
jackzhhuang Sep 3, 2024
c35bd07
add some code
jackzhhuang Sep 4, 2024
f8c3795
add verification
jackzhhuang Sep 4, 2024
93e71f7
fix some bugs
jackzhhuang Sep 4, 2024
df381de
add yeilding after execution for processing the main chain in other s…
jackzhhuang Sep 4, 2024
d757bd6
fmt and clippy
jackzhhuang Sep 5, 2024
fd6d2bb
rebase master
jackzhhuang Sep 5, 2024
0f70ba1
3300000 will be version 1 in vega
jackzhhuang Sep 6, 2024
a75f2f2
add pruning logic and compatible logic
jackzhhuang Jul 21, 2024
d3f8514
fix clippy
jackzhhuang Aug 6, 2024
8f1e647
fix test case
jackzhhuang Aug 6, 2024
296d04a
remove some single chain test case
jackzhhuang Aug 6, 2024
9a94908
fix clippy
jackzhhuang Aug 6, 2024
91a997b
fix flexdag's test case
jackzhhuang Sep 10, 2024
06fbd3e
fix clippy
jackzhhuang Aug 6, 2024
8049c16
add rational random to pass the deserialization verification
jackzhhuang Aug 7, 2024
d32d12f
merge dag-master
jackzhhuang Aug 7, 2024
676e861
fix bugs: blockmeta changes into latest version
jackzhhuang Aug 8, 2024
788cec3
add update db code
jackzhhuang Aug 8, 2024
7689b48
add dag db update
jackzhhuang Aug 8, 2024
e0ec991
update dag db
jackzhhuang Aug 8, 2024
75241a6
update dag db
jackzhhuang Aug 8, 2024
4a39acd
uncomment the pruning code
jackzhhuang Aug 13, 2024
43339b2
rebase sync parallel3
jackzhhuang Sep 10, 2024
07ad098
fix compiling
jackzhhuang Sep 10, 2024
f08687a
db update for dag state
jackzhhuang Sep 11, 2024
4cfc2cc
fix connection
jackzhhuang Sep 11, 2024
b987a31
add verify pruning
jackzhhuang Sep 12, 2024
d55c678
add pruning height
jackzhhuang Sep 13, 2024
954c243
no checking the pruning point if the main header still dose not have …
jackzhhuang Sep 13, 2024
e8f123f
add is ancestor of command for reachability viewing
jackzhhuang Sep 13, 2024
dd1ee2a
add command file
jackzhhuang Sep 13, 2024
109e0bd
use 850000
jackzhhuang Sep 13, 2024
cbc7c55
add rpc json new command
jackzhhuang Sep 13, 2024
153c30d
add some log for debug
jackzhhuang Sep 14, 2024
165690d
if this is the first pruning point, the previous one will be genesis
jackzhhuang Sep 18, 2024
61414cd
save the dag state using the pruning point as the key and if it is 0,…
jackzhhuang Sep 18, 2024
ec341bc
merge dag master
jackzhhuang Sep 18, 2024
7d24357
get the tips by genesis id if the pruning point is 0
jackzhhuang Sep 18, 2024
d5f2762
fix test case as prievious version did
jackzhhuang Sep 18, 2024
a70db10
use genesis id to get the ghost data
jackzhhuang Sep 18, 2024
fd96b21
add genesis in registry in test_miner_service
jackzhhuang Sep 18, 2024
38232f7
use 1000 as parallel buffer
jackzhhuang Sep 19, 2024
f603fc3
remove some logs
jackzhhuang Sep 19, 2024
6e6032d
add pruning arguments in pruning methods to custom the network config
jackzhhuang Sep 20, 2024
41d5def
add test case for pruning calculation and pruning
jackzhhuang Sep 23, 2024
f5807c8
add write lock when saving the tips
jackzhhuang Sep 24, 2024
2be8656
add test pruning for chain
jackzhhuang Sep 24, 2024
b7d157d
add test case
jackzhhuang Sep 24, 2024
2d3745e
if no fork, execute at once
jackzhhuang Sep 25, 2024
07de3ce
add test code
jackzhhuang Sep 27, 2024
998637f
add some rpc param in yaml's cmd
jackzhhuang Sep 27, 2024
ccffd25
use macro to define the parallel count
jackzhhuang Sep 29, 2024
ba5d0b2
use 4090000 as pruning beginning
jackzhhuang Sep 30, 2024
218e7a0
fix the code for robot's comments
jackzhhuang Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion chain/api/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +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 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
137 changes: 117 additions & 20 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ 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;
use starcoin_dag::blockdag::{BlockDAG, MineNewDagBlockInfo};
use starcoin_dag::consensusdb::consenses_state::DagState;
use starcoin_dag::consensusdb::prelude::StoreError;
use starcoin_dag::consensusdb::schemadb::GhostdagStoreReader;
use starcoin_executor::VMMetrics;
use starcoin_logger::prelude::*;
use starcoin_open_block::OpenedBlock;
Expand Down Expand Up @@ -178,7 +178,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.id()) {
anyhow::Result::Ok(_dag_state) => (),
Err(e) => match e.downcast::<StoreError>()? {
StoreError::KeyNotFound(_) => {
Expand Down Expand Up @@ -319,10 +319,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(),
}
jackzhhuang marked this conversation as resolved.
Show resolved Hide resolved
};
debug!(
"Blue blocks:{:?} in chain/create_block_template_by_header",
Expand Down Expand Up @@ -983,7 +987,12 @@ impl BlockChain {
}

pub fn get_dag_state(&self) -> Result<DagState> {
self.dag.get_dag_state()
let current_pruning_point = self.status().head().pruning_point();
if current_pruning_point == HashValue::zero() {
self.dag.get_dag_state(self.genesis_hash)
} else {
self.dag.get_dag_state(current_pruning_point)
}
}
}

Expand Down Expand Up @@ -1334,8 +1343,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 @@ -1360,7 +1371,42 @@ impl ChainReader for BlockChain {
uncles: &[BlockHeader],
header: &BlockHeader,
) -> Result<starcoin_dag::types::ghostdata::GhostdagData> {
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"))?;
let next_ghostdata = self.dag().verify_and_ghostdata(uncles, header)?;

if self.status().head().pruning_point() != HashValue::zero() {
let previous_ghostdata = if previous_header.pruning_point() == HashValue::zero() {
let genesis = self
.storage
.get_genesis()?
.ok_or_else(|| format_err!("the genesis id is none!"))?;
self.dag().storage.ghost_dag_store.get_data(genesis)?
} else {
self.dag()
.storage
.ghost_dag_store
.get_data(previous_header.pruning_point())?
};
self.dag().verify_pruning_point(
previous_header.pruning_point(),
previous_ghostdata.as_ref(),
header.pruning_point(),
&next_ghostdata,
)?;
}

Ok(next_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()
}
}

Expand Down Expand Up @@ -1469,16 +1515,30 @@ 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 = if parent_header.pruning_point() == HashValue::zero() {
self.current_tips_hash(self.genesis_hash)?
} else {
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
Expand Down Expand Up @@ -1519,9 +1579,47 @@ 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());
if block.header().pruning_point() == HashValue::zero() {
self.dag
.save_dag_state(self.genesis_hash, DagState { tips })?;
} else {
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 @@ -1545,7 +1643,6 @@ 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)
}
Expand Down
44 changes: 38 additions & 6 deletions chain/src/verifier/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -347,7 +348,6 @@ impl BasicDagVerifier {
R: ChainReader,
{
let parents_hash = new_block_header.parents_hash();

verify_block!(
VerifyBlockField::Header,
parents_hash.len() == parents_hash.iter().collect::<HashSet<_>>().len(),
Expand All @@ -363,6 +363,7 @@ impl BasicDagVerifier {
parents_hash,
new_block_header.parent_hash()
);

parents_hash.iter().try_for_each(|parent_hash| {
verify_block!(
VerifyBlockField::Header,
Expand All @@ -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)
}

Expand All @@ -397,7 +425,7 @@ impl BasicDagVerifier {
current_chain.verify_and_ghostdata(uncles, header)
}
}
//TODO: Implement it.

pub struct DagVerifier;
impl BlockVerifier for DagVerifier {
fn verify_header<R>(current_chain: &R, new_block_header: &BlockHeader) -> Result<()>
Expand All @@ -408,14 +436,18 @@ impl BlockVerifier for DagVerifier {
}

fn verify_uncles<R>(
_current_chain: &R,
_uncles: &[BlockHeader],
_header: &BlockHeader,
current_chain: &R,
uncles: &[BlockHeader],
header: &BlockHeader,
) -> Result<Option<GhostdagData>>
where
R: ChainReader,
{
Ok(None)
Ok(Some(BasicDagVerifier::verify_blue_blocks(
current_chain,
uncles,
header,
)?))
}
}

Expand Down
Loading
Loading