From 6ff7d85aa6435f7c580c0302ab6de82754ecfe78 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 30 Jan 2024 12:02:23 +0800 Subject: [PATCH 1/7] Extract `broadcast_compact_block` from `Relayer::accept_block` --- sync/src/relayer/mod.rs | 139 +++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/sync/src/relayer/mod.rs b/sync/src/relayer/mod.rs index ac801db511..481c8ca1a3 100644 --- a/sync/src/relayer/mod.rs +++ b/sync/src/relayer/mod.rs @@ -299,84 +299,93 @@ impl Relayer { .insert_new_block(&self.chain, Arc::clone(&boxed)) .unwrap_or(false) { + self.broadcast_compact_block(nc, peer, &boxed) + } + } + + fn broadcast_compact_block( + &self, + nc: &dyn CKBProtocolContext, + peer: PeerIndex, + boxed: &Arc, + ) { + debug_target!( + crate::LOG_TARGET_RELAY, + "[block_relay] relayer accept_block {} {}", + boxed.header().hash(), + unix_time_as_millis() + ); + let block_hash = boxed.hash(); + self.shared().state().remove_header_view(&block_hash); + let cb = packed::CompactBlock::build_from_block(&boxed, &HashSet::new()); + let message = packed::RelayMessage::new_builder().set(cb).build(); + + let selected_peers: Vec = nc + .connected_peers() + .into_iter() + .filter(|target_peer| peer != *target_peer) + .take(MAX_RELAY_PEERS) + .collect(); + if let Err(err) = nc.quick_filter_broadcast( + TargetSession::Multi(Box::new(selected_peers.into_iter())), + message.as_bytes(), + ) { debug_target!( crate::LOG_TARGET_RELAY, - "[block_relay] relayer accept_block {} {}", - boxed.header().hash(), - unix_time_as_millis() + "relayer send block when accept block error: {:?}", + err, ); - let block_hash = boxed.hash(); - self.shared().state().remove_header_view(&block_hash); - let cb = packed::CompactBlock::build_from_block(&boxed, &HashSet::new()); - let message = packed::RelayMessage::new_builder().set(cb).build(); + } - let selected_peers: Vec = nc + if let Some(p2p_control) = nc.p2p_control() { + let snapshot = self.shared.shared().snapshot(); + let parent_chain_root = { + let mmr = snapshot.chain_root_mmr(boxed.header().number() - 1); + match mmr.get_root() { + Ok(root) => root, + Err(err) => { + error_target!( + crate::LOG_TARGET_RELAY, + "Generate last state to light client failed: {:?}", + err + ); + return; + } + } + }; + + let tip_header = packed::VerifiableHeader::new_builder() + .header(boxed.header().data()) + .uncles_hash(boxed.calc_uncles_hash()) + .extension(Pack::pack(&boxed.extension())) + .parent_chain_root(parent_chain_root) + .build(); + let light_client_message = { + let content = packed::SendLastState::new_builder() + .last_header(tip_header) + .build(); + packed::LightClientMessage::new_builder() + .set(content) + .build() + }; + let light_client_peers: HashSet = nc .connected_peers() .into_iter() - .filter(|target_peer| peer != *target_peer) - .take(MAX_RELAY_PEERS) + .filter_map(|index| nc.get_peer(index).map(|peer| (index, peer))) + .filter(|(_id, peer)| peer.if_lightclient_subscribed) + .map(|(id, _)| id) .collect(); - if let Err(err) = nc.quick_filter_broadcast( - TargetSession::Multi(Box::new(selected_peers.into_iter())), - message.as_bytes(), + if let Err(err) = p2p_control.filter_broadcast( + TargetSession::Filter(Box::new(move |id| light_client_peers.contains(id))), + SupportProtocols::LightClient.protocol_id(), + light_client_message.as_bytes(), ) { debug_target!( crate::LOG_TARGET_RELAY, - "relayer send block when accept block error: {:?}", + "relayer send last state to light client when accept block, error: {:?}", err, ); } - - if let Some(p2p_control) = nc.p2p_control() { - let snapshot = self.shared.shared().snapshot(); - let parent_chain_root = { - let mmr = snapshot.chain_root_mmr(boxed.header().number() - 1); - match mmr.get_root() { - Ok(root) => root, - Err(err) => { - error_target!( - crate::LOG_TARGET_RELAY, - "Generate last state to light client failed: {:?}", - err - ); - return; - } - } - }; - - let tip_header = packed::VerifiableHeader::new_builder() - .header(boxed.header().data()) - .uncles_hash(boxed.calc_uncles_hash()) - .extension(Pack::pack(&boxed.extension())) - .parent_chain_root(parent_chain_root) - .build(); - let light_client_message = { - let content = packed::SendLastState::new_builder() - .last_header(tip_header) - .build(); - packed::LightClientMessage::new_builder() - .set(content) - .build() - }; - let light_client_peers: HashSet = nc - .connected_peers() - .into_iter() - .filter_map(|index| nc.get_peer(index).map(|peer| (index, peer))) - .filter(|(_id, peer)| peer.if_lightclient_subscribed) - .map(|(id, _)| id) - .collect(); - if let Err(err) = p2p_control.filter_broadcast( - TargetSession::Filter(Box::new(move |id| light_client_peers.contains(id))), - SupportProtocols::LightClient.protocol_id(), - light_client_message.as_bytes(), - ) { - debug_target!( - crate::LOG_TARGET_RELAY, - "relayer send last state to light client when accept block, error: {:?}", - err, - ); - } - } } } From 2828e20263656c22ec6c3a06f654f7a5b6c848ed Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 30 Jan 2024 12:07:37 +0800 Subject: [PATCH 2/7] Relayer::accept_block will return Status::BlockIsInvalid if its an INVALID block --- sync/src/relayer/mod.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sync/src/relayer/mod.rs b/sync/src/relayer/mod.rs index 481c8ca1a3..a2c8ca1508 100644 --- a/sync/src/relayer/mod.rs +++ b/sync/src/relayer/mod.rs @@ -22,7 +22,9 @@ use self::transaction_hashes_process::TransactionHashesProcess; use self::transactions_process::TransactionsProcess; use crate::block_status::BlockStatus; use crate::types::{ActiveChain, BlockNumberAndHash, SyncShared}; -use crate::utils::{metric_ckb_message_bytes, send_message_to, MetricDirection}; +use crate::utils::{ + is_internal_db_error, metric_ckb_message_bytes, send_message_to, MetricDirection, +}; use crate::{Status, StatusCode}; use ckb_chain::chain::ChainController; use ckb_constant::sync::BAD_MESSAGE_BAN_TIME; @@ -284,23 +286,36 @@ impl Relayer { nc: &dyn CKBProtocolContext, peer: PeerIndex, block: core::BlockView, - ) { + ) -> Status { if self .shared() .active_chain() .contains_block_status(&block.hash(), BlockStatus::BLOCK_STORED) { - return; + return Status::ok(); } let boxed = Arc::new(block); - if self + match self .shared() .insert_new_block(&self.chain, Arc::clone(&boxed)) - .unwrap_or(false) { - self.broadcast_compact_block(nc, peer, &boxed) + Ok(true) => self.broadcast_compact_block(nc, peer, &boxed), + Ok(false) => debug_target!( + crate::LOG_TARGET_RELAY, + "Relayer accept_block received an uncle block, don't broadcast compact block" + ), + Err(err) => { + if !is_internal_db_error(&err) { + return StatusCode::BlockIsInvalid.with_context(format!( + "{}, error: {}", + block.hash(), + err, + )); + } + } } + Status::ok() } fn broadcast_compact_block( From cf8ccb7c843f23ecdec547fe5c8ec7d822add669 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 30 Jan 2024 12:08:33 +0800 Subject: [PATCH 3/7] `BlockTransactionsProcess` and `CompactBlockProcess` will return return Status from `accept_block` --- sync/src/relayer/block_transactions_process.rs | 5 +++-- sync/src/relayer/compact_block_process.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sync/src/relayer/block_transactions_process.rs b/sync/src/relayer/block_transactions_process.rs index 7c8487c94c..6b1161b36e 100644 --- a/sync/src/relayer/block_transactions_process.rs +++ b/sync/src/relayer/block_transactions_process.rs @@ -116,9 +116,10 @@ impl<'a> BlockTransactionsProcess<'a> { match ret { ReconstructionResult::Block(block) => { pending.remove(); - self.relayer + let status = self + .relayer .accept_block(self.nc.as_ref(), self.peer, block); - return Status::ok(); + return status; } ReconstructionResult::Missing(transactions, uncles) => { // We need to get all transactions and uncles that do not exist locally diff --git a/sync/src/relayer/compact_block_process.rs b/sync/src/relayer/compact_block_process.rs index d2583b4cb5..3bd1d5043c 100644 --- a/sync/src/relayer/compact_block_process.rs +++ b/sync/src/relayer/compact_block_process.rs @@ -116,7 +116,8 @@ impl<'a> CompactBlockProcess<'a> { >= block.epoch().number() }); shrink_to_fit!(pending_compact_blocks, 20); - self.relayer + let status = self + .relayer .accept_block(self.nc.as_ref(), self.peer, block); if let Some(metrics) = ckb_metrics::handle() { @@ -124,7 +125,7 @@ impl<'a> CompactBlockProcess<'a> { .ckb_relay_cb_verify_duration .observe(instant.elapsed().as_secs_f64()); } - Status::ok() + status } ReconstructionResult::Missing(transactions, uncles) => { let missing_transactions: Vec = From fef053aa164760644ce474152be128a5ea558433 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 30 Jan 2024 12:54:44 +0800 Subject: [PATCH 4/7] Fix compile error reported by cargo-clippy --- sync/src/relayer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sync/src/relayer/mod.rs b/sync/src/relayer/mod.rs index a2c8ca1508..eba37a3f5d 100644 --- a/sync/src/relayer/mod.rs +++ b/sync/src/relayer/mod.rs @@ -295,7 +295,7 @@ impl Relayer { return Status::ok(); } - let boxed = Arc::new(block); + let boxed: Arc = Arc::new(block); match self .shared() .insert_new_block(&self.chain, Arc::clone(&boxed)) @@ -309,7 +309,7 @@ impl Relayer { if !is_internal_db_error(&err) { return StatusCode::BlockIsInvalid.with_context(format!( "{}, error: {}", - block.hash(), + boxed.hash(), err, )); } @@ -332,7 +332,7 @@ impl Relayer { ); let block_hash = boxed.hash(); self.shared().state().remove_header_view(&block_hash); - let cb = packed::CompactBlock::build_from_block(&boxed, &HashSet::new()); + let cb = packed::CompactBlock::build_from_block(boxed, &HashSet::new()); let message = packed::RelayMessage::new_builder().set(cb).build(); let selected_peers: Vec = nc From ffdd04865feccc968064aa63a1602247f3887ebe Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 31 Jan 2024 21:11:37 +0800 Subject: [PATCH 5/7] Fix unit test for ckb-relayer::build_chain should pass full verification --- Cargo.lock | 1 + sync/Cargo.toml | 1 + sync/src/relayer/tests/helper.rs | 107 ++++++++++++++++++++++++++++--- 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d748e9b20..5112ee1c1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1457,6 +1457,7 @@ dependencies = [ "ckb-logger", "ckb-metrics", "ckb-network", + "ckb-proposal-table", "ckb-reward-calculator", "ckb-shared", "ckb-stop-handler", diff --git a/sync/Cargo.toml b/sync/Cargo.toml index cab5ee6080..7005cb1061 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -51,6 +51,7 @@ ckb-chain = { path = "../chain", version = "= 0.114.0-pre", features = ["mock"] faux = "^0.1" once_cell = "1.8.0" ckb-systemtime = { path = "../util/systemtime", version = "= 0.114.0-pre" , features = ["enable_faketime"]} +ckb-proposal-table = { path = "../util/proposal-table", version = "= 0.114.0-pre" } [features] default = [] diff --git a/sync/src/relayer/tests/helper.rs b/sync/src/relayer/tests/helper.rs index 0531c302a6..d81da762a4 100644 --- a/sync/src/relayer/tests/helper.rs +++ b/sync/src/relayer/tests/helper.rs @@ -2,30 +2,36 @@ use crate::{Relayer, SyncShared}; use ckb_app_config::NetworkConfig; use ckb_chain::chain::ChainService; use ckb_chain_spec::consensus::{build_genesis_epoch_ext, ConsensusBuilder}; +use ckb_dao::DaoCalculator; +use ckb_dao_utils::genesis_dao_data; use ckb_network::{ async_trait, bytes::Bytes as P2pBytes, Behaviour, CKBProtocolContext, Error, Flags, NetworkController, NetworkService, NetworkState, Peer, PeerIndex, ProtocolId, SupportProtocols, TargetSession, }; -use ckb_shared::{Shared, SharedBuilder}; +use ckb_reward_calculator::RewardCalculator; +use ckb_shared::{Shared, SharedBuilder, Snapshot}; use ckb_store::ChainStore; use ckb_systemtime::{self, unix_time_as_millis}; -use ckb_test_chain_utils::always_success_cell; +use ckb_test_chain_utils::{always_success_cell, always_success_cellbase}; +use ckb_types::core::cell::resolve_transaction; +use ckb_types::core::{capacity_bytes, BlockView, UncleBlockView}; +use ckb_types::packed::Script; use ckb_types::prelude::*; use ckb_types::{ bytes::Bytes, core::{ - capacity_bytes, BlockBuilder, BlockNumber, Capacity, EpochNumberWithFraction, - HeaderBuilder, HeaderView, TransactionBuilder, TransactionView, + BlockBuilder, BlockNumber, Capacity, EpochNumberWithFraction, HeaderBuilder, HeaderView, + TransactionBuilder, TransactionView, }, packed::{ CellDep, CellInput, CellOutputBuilder, IndexTransaction, IndexTransactionBuilder, OutPoint, - Script, }, utilities::difficulty_to_compact, U256, }; use ckb_verification_traits::Switch; +use std::collections::HashSet; use std::{cell::RefCell, future::Future, pin::Pin, sync::Arc, time::Duration}; pub(crate) fn new_index_transaction(index: usize) -> IndexTransaction { @@ -83,8 +89,8 @@ pub(crate) fn new_transaction( .input(CellInput::new(previous_output, 0)) .output( CellOutputBuilder::default() - .capacity(Capacity::bytes(500 + index).unwrap().pack()) // use capacity to identify transactions - .build(), + .capacity(Capacity::bytes(500 + index).unwrap().pack()) // use capacity to identify transactions + .build(), ) .output_data(Bytes::new().pack()) .cell_dep( @@ -138,8 +144,10 @@ pub(crate) fn build_chain(tip: BlockNumber) -> (Relayer, OutPoint) { let always_success_out_point = OutPoint::new(always_success_tx.hash(), 0); let (shared, mut pack) = { + let dao = genesis_dao_data(vec![&always_success_tx]).unwrap(); let genesis = BlockBuilder::default() .timestamp(unix_time_as_millis().pack()) + .dao(dao) .compact_target(difficulty_to_compact(U256::from(1000u64)).pack()) .transaction(always_success_tx) .build(); @@ -187,8 +195,20 @@ pub(crate) fn build_chain(tip: BlockNumber) -> (Relayer, OutPoint) { .witness(Script::default().into_witness()) .build(); let header = new_header_builder(&shared, &parent.header()).build(); + + let dao = { + let snapshot: &Snapshot = &shared.snapshot(); + let resolved_cellbase = + resolve_transaction(cellbase.clone(), &mut HashSet::new(), snapshot, snapshot) + .unwrap(); + let data_loader = snapshot.borrow_as_data_loader(); + DaoCalculator::new(shared.consensus(), &data_loader) + .dao_field([resolved_cellbase].iter(), &parent.header()) + .unwrap() + }; let block = BlockBuilder::default() .header(header) + .dao(dao) .transaction(cellbase) .build(); chain_controller @@ -207,6 +227,74 @@ pub(crate) fn build_chain(tip: BlockNumber) -> (Relayer, OutPoint) { ) } +pub fn inherit_cellbase(snapshot: &Snapshot, parent_number: BlockNumber) -> TransactionView { + let parent_header = { + let parent_hash = snapshot + .get_block_hash(parent_number) + .expect("parent exist"); + snapshot + .get_block_header(&parent_hash) + .expect("parent exist") + }; + let (_, reward) = RewardCalculator::new(snapshot.consensus(), snapshot) + .block_reward_to_finalize(&parent_header) + .unwrap(); + always_success_cellbase(parent_number + 1, reward.total, snapshot.consensus()) +} + +pub(crate) fn gen_block( + parent_header: &HeaderView, + shared: &Shared, + target_delta: i32, + timestamp_delta: i64, + uncle_opt: Option, +) -> BlockView { + let snapshot: &Snapshot = &shared.snapshot(); + let number = parent_header.number() + 1; + let cellbase = inherit_cellbase(snapshot, parent_header.number()); + let txs = vec![cellbase.clone()]; + + let dao = { + let resolved_cellbase = + resolve_transaction(cellbase, &mut HashSet::new(), snapshot, snapshot).unwrap(); + let data_loader = snapshot.borrow_as_data_loader(); + DaoCalculator::new(shared.consensus(), &data_loader) + .dao_field([resolved_cellbase].iter(), parent_header) + .unwrap() + }; + + let epoch = shared + .consensus() + .next_epoch_ext(parent_header, &shared.store().borrow_as_data_loader()) + .unwrap() + .epoch(); + + let mut block_builder = BlockBuilder::default() + .parent_hash(parent_header.hash()) + .timestamp( + (parent_header + .timestamp() + .checked_add_signed(timestamp_delta) + .unwrap()) + .pack(), + ) + .number(number.pack()) + .compact_target( + (epoch + .compact_target() + .checked_add_signed(target_delta) + .unwrap()) + .pack(), + ) + .dao(dao) + .epoch(epoch.number_with_fraction(number).pack()) + .transactions(txs); + if let Some(uncle) = uncle_opt { + block_builder = block_builder.uncle(uncle) + } + block_builder.build() +} + pub(crate) struct MockProtocolContext { protocol: SupportProtocols, sent_messages: RefCell>, @@ -214,6 +302,7 @@ pub(crate) struct MockProtocolContext { // test mock context with single thread unsafe impl Send for MockProtocolContext {} + unsafe impl Sync for MockProtocolContext {} impl MockProtocolContext { @@ -318,7 +407,7 @@ impl CKBProtocolContext for MockProtocolContext { unimplemented!(); } fn quick_filter_broadcast(&self, _target: TargetSession, _data: P2pBytes) -> Result<(), Error> { - unimplemented!(); + Ok(()) } fn future_task( &self, @@ -356,7 +445,7 @@ impl CKBProtocolContext for MockProtocolContext { unimplemented!(); } fn connected_peers(&self) -> Vec { - unimplemented!(); + vec![] } fn report_peer(&self, _peer_index: PeerIndex, _behaviour: Behaviour) { unimplemented!(); From ce43fb5e890b87d662d471e0350456399dd74271 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 31 Jan 2024 21:13:01 +0800 Subject: [PATCH 6/7] Fix unit test `test_accept_not_a_better_block` --- .../relayer/tests/compact_block_process.rs | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/sync/src/relayer/tests/compact_block_process.rs b/sync/src/relayer/tests/compact_block_process.rs index 6904c649c4..ec937883c9 100644 --- a/sync/src/relayer/tests/compact_block_process.rs +++ b/sync/src/relayer/tests/compact_block_process.rs @@ -1,11 +1,15 @@ use crate::block_status::BlockStatus; use crate::relayer::compact_block_process::CompactBlockProcess; -use crate::relayer::tests::helper::{build_chain, new_header_builder, MockProtocolContext}; +use crate::relayer::tests::helper::{ + build_chain, gen_block, new_header_builder, MockProtocolContext, +}; use crate::{Status, StatusCode}; +use ckb_chain::chain::ChainService; use ckb_network::{PeerIndex, SupportProtocols}; use ckb_store::ChainStore; use ckb_systemtime::unix_time_as_millis; use ckb_tx_pool::{PlugTarget, TxEntry}; +use ckb_types::core::{BlockView, HeaderView}; use ckb_types::prelude::*; use ckb_types::{ bytes::Bytes, @@ -152,25 +156,36 @@ fn test_unknow_parent() { #[test] fn test_accept_not_a_better_block() { let (relayer, _) = build_chain(5); - let header = { + let tip_header = { let active_chain = relayer.shared.active_chain(); active_chain.tip_header() }; + let second_to_last_header: HeaderView = { + let tip_header: HeaderView = relayer.shared().store().get_tip_header().unwrap(); + let second_to_last_header = relayer + .shared() + .store() + .get_block_header(&tip_header.data().raw().parent_hash()) + .unwrap(); + second_to_last_header + }; - // The timestamp is random, so it may be not a better block. - let not_sure_a_better_header = header - .as_advanced_builder() - .timestamp((header.timestamp() + 1).pack()) - .build(); - - let block = BlockBuilder::default() - .header(not_sure_a_better_header) - .transaction(TransactionBuilder::default().build()) - .build(); + let uncle_block: BlockView = gen_block( + &second_to_last_header, + relayer.shared().shared(), + 1, + 1, + None, + ); + //uncle_block's block_hash must not equal to tip's block_hash + assert_ne!(uncle_block.header().hash(), tip_header.hash()); + // uncle_block's difficulty must less than tip's difficulty + assert!(uncle_block.difficulty().lt(&tip_header.difficulty())); let mut prefilled_transactions_indexes = HashSet::new(); prefilled_transactions_indexes.insert(0); - let compact_block = CompactBlock::build_from_block(&block, &prefilled_transactions_indexes); + let compact_block = + CompactBlock::build_from_block(&uncle_block, &prefilled_transactions_indexes); let mock_protocol_context = MockProtocolContext::new(SupportProtocols::RelayV2); let nc = Arc::new(mock_protocol_context); @@ -182,7 +197,7 @@ fn test_accept_not_a_better_block() { Arc::::clone(&nc), peer_index, ); - assert_eq!(compact_block_process.execute(), Status::ok(),); + assert_eq!(compact_block_process.execute(), Status::ok()); } #[test] @@ -323,18 +338,15 @@ fn test_accept_block() { active_chain.tip_header() }; - let header = new_header_builder(relayer.shared.shared(), &parent).build(); - - let uncle = BlockBuilder::default().build(); - let ext = packed::BlockExtBuilder::default() - .verified(Some(true).pack()) - .build(); + let uncle = gen_block(&parent, relayer.shared().shared(), 0, 1, None); - let block = BlockBuilder::default() - .header(header) - .transaction(TransactionBuilder::default().build()) - .uncle(uncle.as_uncle()) - .build(); + let block = gen_block( + &parent, + relayer.shared().shared(), + 0, + 1, + Some(uncle.as_uncle()), + ); let mock_block_1 = BlockBuilder::default() .number(4.pack()) From 740f2f3c464acb81bbe8ed910993acca2bcbef34 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 31 Jan 2024 21:13:12 +0800 Subject: [PATCH 7/7] Fix unit test `test_accept_block` --- sync/src/relayer/tests/compact_block_process.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sync/src/relayer/tests/compact_block_process.rs b/sync/src/relayer/tests/compact_block_process.rs index ec937883c9..17b64a1339 100644 --- a/sync/src/relayer/tests/compact_block_process.rs +++ b/sync/src/relayer/tests/compact_block_process.rs @@ -377,16 +377,18 @@ fn test_accept_block() { ); } - let uncle_hash = uncle.hash(); { - let db_txn = relayer.shared().shared().store().begin_transaction(); - db_txn.insert_block(&uncle).unwrap(); - db_txn.attach_block(&uncle).unwrap(); - db_txn.insert_block_ext(&uncle_hash, &ext.unpack()).unwrap(); - db_txn.commit().unwrap(); + let chain_controller = { + let proposal_window = ckb_proposal_table::ProposalTable::new( + relayer.shared().shared().consensus().tx_proposal_window(), + ); + let chain_service = + ChainService::new(relayer.shared().shared().to_owned(), proposal_window); + chain_service.start::<&str>(None) + }; + chain_controller.process_block(Arc::new(uncle)).unwrap(); } - relayer.shared().shared().refresh_snapshot(); let mut prefilled_transactions_indexes = HashSet::new(); prefilled_transactions_indexes.insert(0); let compact_block = CompactBlock::build_from_block(&block, &prefilled_transactions_indexes);