Skip to content

Commit 609a99b

Browse files
committed
feat(block validation): ledger
1 parent 41de047 commit 609a99b

File tree

1 file changed

+96
-45
lines changed

1 file changed

+96
-45
lines changed

rust/immutable-ledger/src/validate.rs

Lines changed: 96 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,89 @@
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

Comments
 (0)