22//!
33//! Facilitates validation for immutable ledger
44
5- use crate :: serialize:: EncodedBlock ;
5+ use crate :: serialize:: blake3;
6+ use anyhow:: Ok ;
67
7- /// Validate block
8- pub fn validate_block ( _current_block : EncodedBlock , _previous_block : EncodedBlock ) -> bool {
9- todo ! ( )
8+ use crate :: serialize:: { blake2b_512, decode_block, EncodedBlock , HashFunction } ;
9+
10+ /// Validate current block against previous block.
11+ pub fn validate_block (
12+ current_block : EncodedBlock , previous_block : EncodedBlock , hasher : HashFunction ,
13+ ) -> anyhow:: Result < ( ) > {
14+ let current_block = decode_block ( current_block) ?;
15+
16+ let hashed_previous_block = match hasher {
17+ HashFunction :: Blake3 => blake3 ( & previous_block) ?. to_vec ( ) ,
18+ HashFunction :: Blake2b => blake2b_512 ( & previous_block) ?. to_vec ( ) ,
19+ } ;
20+ let previous_block = decode_block ( previous_block) ?;
21+
22+ // chain_id MUST be the same as for the previous block (except for genesis).
23+ if current_block. 0 . 0 != previous_block. 0 . 0 {
24+ return Err ( anyhow:: anyhow!(
25+ "Module: Immutable ledger, Message: Chain_id MUST be NOT the same as for the previous block {:?} {:?}" ,
26+ current_block. 0 . 0 ,
27+ previous_block. 0 . 0
28+ ) ) ;
29+ } ;
30+
31+ // height MUST be incremented by 1 from the previous block height value (except for genesis and final block).
32+ // Genesis block MUST have 0 value. Final block MUST hash be incremented by 1 from the previous block height
33+ // and changed the sign to negative. E.g. previous block height is 9 and the Final block height is -10.
34+ if current_block. 0 . 1 . 0 != previous_block. 0 . 1 . 0 + 1 {
35+ return Err ( anyhow:: anyhow!(
36+ "Module: Immutable ledger, Message: height validation failed: {:?} {:?}" ,
37+ current_block. 0 . 1 . 0 ,
38+ previous_block. 0 . 1 . 0
39+ ) ) ;
40+ }
41+
42+ // timestamp MUST be greater or equals than the timestamp of the previous block (except for genesis)
43+ if current_block. 0 . 2 . 0 <= previous_block. 0 . 2 . 0 {
44+ return Err ( anyhow:: anyhow!(
45+ "Module: Immutable ledger, Message: timestamp validation failed: {:?} {:?}" ,
46+ current_block. 0 . 2 . 0 ,
47+ previous_block. 0 . 2 . 0
48+ ) ) ;
49+ }
50+
51+ // prev_block_id MUST be a hash of the previous block bytes (except for genesis).
52+ if current_block. 0 . 3 . 0 != hashed_previous_block {
53+ return Err ( anyhow:: anyhow!(
54+ "Module: Immutable ledger, Message: previous hash validation failed: {:?} {:?}" ,
55+ current_block. 0 . 3 . 0 ,
56+ previous_block. 0 . 3 . 0
57+ ) ) ;
58+ }
59+
60+ // ledger_type MUST be the same as for the previous block if present (except for genesis).
61+ if current_block. 0 . 4 . 0 != previous_block. 0 . 4 . 0 {
62+ return Err ( anyhow:: anyhow!(
63+ "Module: Immutable ledger, Message: ledger type validation failed: {:?} {:?}" ,
64+ current_block. 0 . 4 . 0 ,
65+ previous_block. 0 . 4 . 0
66+ ) ) ;
67+ }
68+
69+ // purpose_id MUST be the same as for the previous block if present (except for genesis).
70+ if current_block. 0 . 5 . 0 != previous_block. 0 . 5 . 0 {
71+ return Err ( anyhow:: anyhow!(
72+ "Module: Immutable ledger, Message: purpose id validation failed: {:?} {:?}" ,
73+ current_block. 0 . 5 . 0 ,
74+ previous_block. 0 . 5 . 0
75+ ) ) ;
76+ }
77+
78+ // validator MUST be the same as for the previous block if present (except for genesis)
79+ if current_block. 0 . 6 . 0 != previous_block. 0 . 6 . 0 {
80+ return Err ( anyhow:: anyhow!(
81+ "Module: Immutable ledger, Message: validator validation failed: {:?} {:?}" ,
82+ current_block. 0 . 6 . 0 ,
83+ previous_block. 0 . 6 . 0
84+ ) ) ;
85+ }
86+
87+ Ok ( ( ) )
1088}
1189
1290#[ cfg( test) ]
@@ -18,8 +96,8 @@ mod tests {
1896 use uuid:: Uuid ;
1997
2098 use crate :: serialize:: {
21- encode_block, encode_block_header, BlockTimeStamp , ChainId , EncodedBlockData , Height , Kid ,
22- LedgerType , Metadata , PreviousBlockHash , PurposeId , Validator , ValidatorKeys ,
99+ blake2b_512 , encode_block, encode_block_header, BlockTimeStamp , ChainId , EncodedBlockData ,
100+ Height , Kid , LedgerType , Metadata , PreviousBlockHash , PurposeId , Validator , ValidatorKeys ,
23101 } ;
24102
25103 use crate :: serialize:: HashFunction :: Blake2b ;
@@ -29,7 +107,7 @@ mod tests {
29107 #[ test]
30108 fn validate_block_test ( ) {
31109 //
32- // CURRENT BLOCK
110+ // PREVIOUS BLOCK
33111 //
34112 //
35113 let kid_a: [ u8 ; 16 ] = hex:: decode ( "00112233445566778899aabbccddeeff" )
@@ -82,7 +160,7 @@ mod tests {
82160
83161 block_data. bytes ( block_data_bytes) . unwrap ( ) ;
84162
85- let current_block = encode_block (
163+ let previous_block = encode_block (
86164 encoded_block_hdr. clone ( ) ,
87165 EncodedBlockData ( block_data_bytes. to_vec ( ) ) ,
88166 ValidatorKeys ( vec ! [ validator_secret_key_bytes, validator_secret_key_bytes] ) ,
@@ -91,60 +169,30 @@ mod tests {
91169 . unwrap ( ) ;
92170
93171 //
94- // PREVIOUS B
95- //
172+ // CURRENT BLOCK
96173 //
97- let kid_a: [ u8 ; 16 ] = hex:: decode ( "00112233445566778899aabbccddeeff" )
98- . unwrap ( )
99- . try_into ( )
100- . unwrap ( ) ;
101174
102- let kid_b: [ u8 ; 16 ] = hex:: decode ( "00112233445566778899aabbccddeeff" )
103- . unwrap ( )
104- . try_into ( )
105- . unwrap ( ) ;
106-
107- let chain_id = ChainId ( Ulid :: new ( ) ) ;
108- let block_height = Height ( 5 ) ;
109- let block_ts = BlockTimeStamp ( 1728474515 ) ;
110- let prev_block_height = PreviousBlockHash ( vec ! [ 0 ; 64 ] ) ;
111- let ledger_type = LedgerType ( Uuid :: new_v4 ( ) ) ;
112- let purpose_id = PurposeId ( Ulid :: new ( ) ) ;
175+ let block_height = Height ( 6 ) ;
176+ let block_ts = BlockTimeStamp ( 1728474518 ) ;
177+ let prev_block_hash = PreviousBlockHash ( blake2b_512 ( & previous_block) . unwrap ( ) . to_vec ( ) ) ;
113178 let validators = Validator ( vec ! [ Kid ( kid_a) , Kid ( kid_b) ] ) ;
114179 let metadata = Some ( Metadata ( vec ! [ 1 ; 128 ] ) ) ;
115180
116181 let encoded_block_hdr = encode_block_header (
117182 chain_id,
118183 block_height,
119184 block_ts,
120- prev_block_height . clone ( ) ,
185+ prev_block_hash ,
121186 ledger_type. clone ( ) ,
122187 purpose_id. clone ( ) ,
123188 validators. clone ( ) ,
124189 metadata. clone ( ) ,
125190 )
126191 . unwrap ( ) ;
127192
128- // validators
129- let validator_secret_key_bytes: [ u8 ; SECRET_KEY_LENGTH ] = [
130- 157 , 097 , 177 , 157 , 239 , 253 , 090 , 096 , 186 , 132 , 074 , 244 , 146 , 236 , 044 , 196 , 068 ,
131- 073 , 197 , 105 , 123 , 050 , 105 , 025 , 112 , 059 , 172 , 003 , 028 , 174 , 127 , 096 ,
132- ] ;
133-
134- let out: Vec < u8 > = Vec :: new ( ) ;
135- let mut block_data = minicbor:: Encoder :: new ( out) ;
136-
137- let block_data_bytes = & [
138- 157 , 097 , 177 , 157 , 239 , 253 , 090 , 096 , 186 , 132 , 074 , 244 , 146 , 236 , 044 , 196 , 157 ,
139- 239 , 253 , 090 , 096 , 186 , 132 , 074 , 244 , 146 , 236 , 044 , 196 , 157 , 239 , 253 , 090 , 096 ,
140- 186 , 132 , 074 , 244 , 146 , 236 , 044 , 196 , 157 , 239 , 253 , 090 , 096 , 186 , 132 , 074 , 244 ,
141- 146 , 236 , 044 , 196 , 157 , 239 , 253 , 090 , 096 , 186 , 132 , 074 , 244 , 146 , 236 , 044 , 196 ,
142- 157 ,
143- ] ;
144-
145193 block_data. bytes ( block_data_bytes) . unwrap ( ) ;
146194
147- let previous_block = encode_block (
195+ let current_block = encode_block (
148196 encoded_block_hdr. clone ( ) ,
149197 EncodedBlockData ( block_data_bytes. to_vec ( ) ) ,
150198 ValidatorKeys ( vec ! [ validator_secret_key_bytes, validator_secret_key_bytes] ) ,
@@ -156,6 +204,9 @@ mod tests {
156204 // VALIDATE BLOCK
157205 //
158206
159- validate_block ( current_block, previous_block) ;
207+ match validate_block ( current_block, previous_block, Blake2b ) {
208+ Ok ( _) => ( ) ,
209+ Err ( err) => panic ! ( "Block validation failed: {:?}" , err) ,
210+ } ;
160211 }
161212}
0 commit comments