@@ -5,7 +5,7 @@ use std::time::{Duration as TimeDuration, Instant};
55use borsh:: BorshSerialize ;
66use chrono:: Duration ;
77use chrono:: Utc ;
8- use log:: { debug, error, info} ;
8+ use log:: { debug, error, info, warn } ;
99use rand:: rngs:: StdRng ;
1010use rand:: seq:: SliceRandom ;
1111use rand:: SeedableRng ;
@@ -400,9 +400,9 @@ impl Chain {
400400 pub fn save_block ( & mut self , block : & Block ) -> Result < ( ) , Error > {
401401 let mut chain_store_update = ChainStoreUpdate :: new ( & mut self . store ) ;
402402
403- if ! block. check_validity ( ) {
403+ if let Err ( e ) = block. check_validity ( ) {
404404 byzantine_assert ! ( false ) ;
405- return Err ( ErrorKind :: Other ( "Invalid block" . into ( ) ) . into ( ) ) ;
405+ return Err ( e . into ( ) ) ;
406406 }
407407
408408 chain_store_update. save_block ( block. clone ( ) ) ;
@@ -421,6 +421,14 @@ impl Chain {
421421 } ) ;
422422 }
423423
424+ fn save_block_height_processed ( & mut self , block_height : BlockHeight ) -> Result < ( ) , Error > {
425+ let mut chain_store_update = ChainStoreUpdate :: new ( & mut self . store ) ;
426+ if !chain_store_update. is_height_processed ( block_height) ? {
427+ chain_store_update. save_block_height_processed ( block_height) ;
428+ }
429+ Ok ( ( ) )
430+ }
431+
424432 // GC CONTRACT
425433 // ===
426434 //
@@ -605,6 +613,13 @@ impl Chain {
605613 Ok ( ( ) )
606614 }
607615
616+ /// Do Basic validation of a block upon receiving it. Check that header is valid
617+ /// and block is well-formed (various roots match).
618+ pub fn validate_block ( & mut self , block : & Block ) -> Result < ( ) , Error > {
619+ self . process_block_header ( & block. header ( ) , |_| { } ) ?;
620+ block. check_validity ( ) . map_err ( |e| e. into ( ) )
621+ }
622+
608623 /// Process a block header received during "header first" propagation.
609624 pub fn process_block_header < F > (
610625 & mut self ,
@@ -1020,10 +1035,6 @@ impl Chain {
10201035 {
10211036 near_metrics:: inc_counter ( & metrics:: BLOCK_PROCESSED_TOTAL ) ;
10221037
1023- if block. chunks ( ) . len ( ) != self . runtime_adapter . num_shards ( ) as usize {
1024- return Err ( ErrorKind :: IncorrectNumberOfChunkHeaders . into ( ) ) ;
1025- }
1026-
10271038 let prev_head = self . store . head ( ) ?;
10281039 let mut chain_update = ChainUpdate :: new (
10291040 & mut self . store ,
@@ -1035,9 +1046,11 @@ impl Chain {
10351046 self . doomslug_threshold_mode ,
10361047 ) ;
10371048 let maybe_new_head = chain_update. process_block ( me, & block, & provenance, on_challenge) ;
1049+ let block_height = block. header ( ) . height ( ) ;
10381050
10391051 match maybe_new_head {
10401052 Ok ( ( head, needs_to_start_fetching_state) ) => {
1053+ chain_update. chain_store_update . save_block_height_processed ( block_height) ;
10411054 chain_update. commit ( ) ?;
10421055
10431056 if needs_to_start_fetching_state {
@@ -1079,62 +1092,64 @@ impl Chain {
10791092
10801093 Ok ( head)
10811094 }
1082- Err ( e) => match e. kind ( ) {
1083- ErrorKind :: Orphan => {
1084- let tail_height = self . store . tail ( ) ?;
1085- // we only add blocks that couldn't have been gc'ed to the orphan pool.
1086- if block. header ( ) . height ( ) >= tail_height {
1095+ Err ( e) => {
1096+ match e. kind ( ) {
1097+ ErrorKind :: Orphan => {
1098+ let tail_height = self . store . tail ( ) ?;
1099+ // we only add blocks that couldn't have been gc'ed to the orphan pool.
1100+ if block_height >= tail_height {
1101+ let block_hash = * block. hash ( ) ;
1102+ let orphan = Orphan { block, provenance, added : Instant :: now ( ) } ;
1103+
1104+ self . orphans . add ( orphan) ;
1105+
1106+ debug ! (
1107+ target: "chain" ,
1108+ "Process block: orphan: {:?}, # orphans {}{}" ,
1109+ block_hash,
1110+ self . orphans. len( ) ,
1111+ if self . orphans. len_evicted( ) > 0 {
1112+ format!( ", # evicted {}" , self . orphans. len_evicted( ) )
1113+ } else {
1114+ String :: new( )
1115+ } ,
1116+ ) ;
1117+ }
1118+ }
1119+ ErrorKind :: ChunksMissing ( missing_chunks) => {
10871120 let block_hash = * block. hash ( ) ;
1121+ block_misses_chunks ( missing_chunks. clone ( ) ) ;
10881122 let orphan = Orphan { block, provenance, added : Instant :: now ( ) } ;
10891123
1090- self . orphans . add ( orphan) ;
1124+ self . blocks_with_missing_chunks . add ( orphan) ;
10911125
10921126 debug ! (
10931127 target: "chain" ,
1094- "Process block: orphan: {:?}, # orphans {}{}" ,
1095- block_hash,
1096- self . orphans. len( ) ,
1097- if self . orphans. len_evicted( ) > 0 {
1098- format!( ", # evicted {}" , self . orphans. len_evicted( ) )
1099- } else {
1100- String :: new( )
1101- } ,
1128+ "Process block: missing chunks. Block hash: {:?}. Missing chunks: {:?}" ,
1129+ block_hash, missing_chunks,
11021130 ) ;
11031131 }
1104- Err ( e)
1105- }
1106- ErrorKind :: ChunksMissing ( missing_chunks) => {
1107- let block_hash = * block. hash ( ) ;
1108- block_misses_chunks ( missing_chunks. clone ( ) ) ;
1109- let orphan = Orphan { block, provenance, added : Instant :: now ( ) } ;
1110-
1111- self . blocks_with_missing_chunks . add ( orphan) ;
1112-
1113- debug ! (
1114- target: "chain" ,
1115- "Process block: missing chunks. Block hash: {:?}. Missing chunks: {:?}" ,
1116- block_hash, missing_chunks,
1117- ) ;
1118- Err ( e)
1119- }
1120- ErrorKind :: EpochOutOfBounds => {
1121- // Possibly block arrived before we finished processing all of the blocks for epoch before last.
1122- // Or someone is attacking with invalid chain.
1123- debug ! ( target: "chain" , "Received block {}/{} ignored, as epoch is unknown" , block. header( ) . height( ) , block. hash( ) ) ;
1124- Err ( e)
1132+ ErrorKind :: EpochOutOfBounds => {
1133+ // Possibly block arrived before we finished processing all of the blocks for epoch before last.
1134+ // Or someone is attacking with invalid chain.
1135+ debug ! ( target: "chain" , "Received block {}/{} ignored, as epoch is unknown" , block_height, block. hash( ) ) ;
1136+ }
1137+ ErrorKind :: Unfit ( ref msg) => {
1138+ debug ! (
1139+ target: "chain" ,
1140+ "Block {} at {} is unfit at this time: {}" ,
1141+ block. hash( ) ,
1142+ block_height,
1143+ msg
1144+ ) ;
1145+ }
1146+ _ => { }
11251147 }
1126- ErrorKind :: Unfit ( ref msg) => {
1127- debug ! (
1128- target: "chain" ,
1129- "Block {} at {} is unfit at this time: {}" ,
1130- block. hash( ) ,
1131- block. header( ) . height( ) ,
1132- msg
1133- ) ;
1134- Err ( ErrorKind :: Unfit ( msg. clone ( ) ) . into ( ) )
1148+ if let Err ( e) = self . save_block_height_processed ( block_height) {
1149+ warn ! ( target: "chain" , "Failed to save processed height {}: {}" , block_height, e) ;
11351150 }
1136- _ => Err ( e) ,
1137- } ,
1151+ Err ( e)
1152+ }
11381153 }
11391154 }
11401155
@@ -2823,6 +2838,10 @@ impl<'a> ChainUpdate<'a> {
28232838 {
28242839 debug ! ( target: "chain" , "Process block {} at {}, approvals: {}, me: {:?}" , block. hash( ) , block. header( ) . height( ) , block. header( ) . num_approvals( ) , me) ;
28252840
2841+ if block. chunks ( ) . len ( ) != self . runtime_adapter . num_shards ( ) as usize {
2842+ return Err ( ErrorKind :: IncorrectNumberOfChunkHeaders . into ( ) ) ;
2843+ }
2844+
28262845 // Check if we have already processed this block previously.
28272846 self . check_known ( block. header ( ) . hash ( ) ) ?;
28282847
@@ -2888,9 +2907,9 @@ impl<'a> ChainUpdate<'a> {
28882907 return Err ( ErrorKind :: InvalidRandomnessBeaconOutput . into ( ) ) ;
28892908 }
28902909
2891- if ! block. check_validity ( ) {
2910+ if let Err ( e ) = block. check_validity ( ) {
28922911 byzantine_assert ! ( false ) ;
2893- return Err ( ErrorKind :: Other ( "Invalid block" . into ( ) ) . into ( ) ) ;
2912+ return Err ( e . into ( ) ) ;
28942913 }
28952914
28962915 let protocol_version =
@@ -3140,8 +3159,6 @@ impl<'a> ChainUpdate<'a> {
31403159 return Err ( ErrorKind :: InvalidApprovals . into ( ) ) ;
31413160 } ;
31423161
3143- self . runtime_adapter . verify_block_signature ( header) ?;
3144-
31453162 let stakes = self
31463163 . runtime_adapter
31473164 . get_epoch_block_approvers_ordered ( header. prev_hash ( ) ) ?
0 commit comments