1- use bigint:: H256 ;
1+ use bigint:: { H256 , U256 } ;
22use chain_spec:: consensus:: Consensus ;
33use channel:: { self , Receiver , Sender } ;
44use ckb_notify:: { ForkBlocks , NotifyController , NotifyService } ;
@@ -16,6 +16,7 @@ use std::cmp;
1616use std:: sync:: Arc ;
1717use std:: thread:: { self , JoinHandle } ;
1818use time:: now_ms;
19+ use util:: RwLockUpgradableReadGuard ;
1920use verification:: { BlockVerifier , Verifier } ;
2021
2122pub struct ChainService < CI > {
@@ -129,8 +130,14 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {
129130
130131 fn insert_block ( & self , block : & Block ) -> Result < BlockInsertionResult , SharedError > {
131132 let mut new_best_block = false ;
133+ let mut output_root = H256 :: zero ( ) ;
134+ let mut total_difficulty = U256 :: zero ( ) ;
135+
132136 let mut old_cumulative_blks = Vec :: new ( ) ;
133137 let mut new_cumulative_blks = Vec :: new ( ) ;
138+
139+ let tip_header = self . shared . tip_header ( ) . upgradable_read ( ) ;
140+ let tip_number = tip_header. number ( ) ;
134141 self . shared . store ( ) . save_with_batch ( |batch| {
135142 let root = self . check_transactions ( batch, block) ?;
136143 let parent_ext = self
@@ -150,41 +157,50 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {
150157 self . shared . store ( ) . insert_output_root ( batch, block. header ( ) . hash ( ) , root) ;
151158 self . shared . store ( ) . insert_block_ext ( batch, & block. header ( ) . hash ( ) , & ext) ;
152159
153- {
154- debug ! ( target: "chain" , "acquire lock" ) ;
155- let mut tip_header = self . shared . tip_header ( ) . write ( ) ;
156- let current_total_difficulty = tip_header. total_difficulty ( ) ;
157- debug ! (
158- "difficulty diff = {}; current = {}, cannon = {}" ,
159- cannon_total_difficulty. low_u64( ) as i64
160- - current_total_difficulty. low_u64( ) as i64 ,
161- current_total_difficulty,
162- cannon_total_difficulty,
163- ) ;
160+ let current_total_difficulty = tip_header. total_difficulty ( ) ;
161+ debug ! (
162+ "difficulty diff = {}; current = {}, cannon = {}" ,
163+ cannon_total_difficulty. low_u64( ) as i64
164+ - current_total_difficulty. low_u64( ) as i64 ,
165+ current_total_difficulty,
166+ cannon_total_difficulty,
167+ ) ;
164168
165- if cannon_total_difficulty > current_total_difficulty
166- || ( current_total_difficulty == cannon_total_difficulty
167- && block. header ( ) . hash ( ) < tip_header. hash ( ) )
168- {
169- debug ! ( target: "chain" , "new best block found: {} => {}" , block. header( ) . number( ) , block. header( ) . hash( ) ) ;
170- new_best_block = true ;
171- let new_tip_header = TipHeader :: new (
172- block. header ( ) . clone ( ) ,
173- cannon_total_difficulty,
174- root,
175- ) ;
176-
177- self . update_index ( batch, tip_header. number ( ) , block, & mut old_cumulative_blks, & mut new_cumulative_blks) ;
178- // TODO: Move out
179- * tip_header = new_tip_header;
180- self . shared . store ( ) . insert_tip_header ( batch, & block. header ( ) ) ;
181- self . shared . store ( ) . rebuild_tree ( root) ;
182- }
183- debug ! ( target: "chain" , "lock release" ) ;
169+ if cannon_total_difficulty > current_total_difficulty
170+ || ( current_total_difficulty == cannon_total_difficulty
171+ && block. header ( ) . hash ( ) < tip_header. hash ( ) )
172+ {
173+ debug ! ( target: "chain" , "new best block found: {} => {}" , block. header( ) . number( ) , block. header( ) . hash( ) ) ;
174+ new_best_block = true ;
175+ output_root = root;
176+ total_difficulty = cannon_total_difficulty;
184177 }
185178 Ok ( ( ) )
186179 } ) ?;
187180
181+ if new_best_block {
182+ debug ! ( target: "chain" , "update index" ) ;
183+ let mut guard = RwLockUpgradableReadGuard :: upgrade ( tip_header) ;
184+ let new_tip_header =
185+ TipHeader :: new ( block. header ( ) . clone ( ) , total_difficulty, output_root) ;
186+ self . shared . store ( ) . save_with_batch ( |batch| {
187+ self . update_index (
188+ batch,
189+ tip_number,
190+ block,
191+ & mut old_cumulative_blks,
192+ & mut new_cumulative_blks,
193+ ) ;
194+ self . shared
195+ . store ( )
196+ . insert_tip_header ( batch, & block. header ( ) ) ;
197+ self . shared . store ( ) . rebuild_tree ( output_root) ;
198+ Ok ( ( ) )
199+ } ) ?;
200+ * guard = new_tip_header;
201+ debug ! ( target: "chain" , "update index release" ) ;
202+ }
203+
188204 Ok ( BlockInsertionResult {
189205 new_best_block,
190206 fork_blks : ForkBlocks :: new ( old_cumulative_blks, new_cumulative_blks) ,
@@ -220,11 +236,11 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {
220236 old_cumulative_blks : & mut Vec < Block > ,
221237 new_cumulative_blks : & mut Vec < Block > ,
222238 ) {
223- let mut number = block. header ( ) . number ( ) - 1 ;
239+ let mut number = block. header ( ) . number ( ) ;
224240
225241 // The old fork may longer than new fork
226- if number < tip_number {
227- for n in number..tip_number + 1 {
242+ if tip_number >= number {
243+ for n in number..= tip_number {
228244 let hash = self . shared . block_hash ( n) . unwrap ( ) ;
229245 let old_block = self . shared . block ( & hash) . unwrap ( ) ;
230246 self . shared . store ( ) . delete_block_hash ( batch, n) ;
@@ -253,7 +269,7 @@ impl<CI: ChainIndex + 'static> ChainService<CI> {
253269 }
254270
255271 let mut hash = block. header ( ) . parent_hash ( ) ;
256-
272+ number -= 1 ;
257273 loop {
258274 if let Some ( old_hash) = self . shared . block_hash ( number) {
259275 if old_hash == hash {
0 commit comments