Skip to content

Commit ece6e6a

Browse files
committed
feat(block validation): ledger
1 parent 3f5ace8 commit ece6e6a

File tree

3 files changed

+112
-88
lines changed

3 files changed

+112
-88
lines changed

rust/immutable-ledger/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
//!
33
//! Facilitates block serialization and validation for immutable ledger
44
//!
5-
//! Spec: <https://input-output-hk.github.io/catalyst-voices/architecture/08_concepts/immutable_ledger/ledger>/
6-
//!
5+
//! Spec: `<https://input-output-hk.github.io/catalyst-voices/architecture/08_concepts/immutable_ledger/ledger>`
76
87
/// Block validation logic
98
pub mod validate;

rust/immutable-ledger/src/serialize.rs

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
//!
33
//! Facilitates block serialization for immutable ledger
44
5+
use core::result::Result::Ok as ResultOk;
6+
57
use anyhow::Ok;
68
use blake2b_simd::{self, Params};
7-
use core::result::Result::Ok as ResultOk;
89
use ed25519_dalek::{ed25519::signature::SignerMut, Signature, SigningKey, SECRET_KEY_LENGTH};
9-
1010
use ulid::Ulid;
1111
use uuid::Uuid;
1212

@@ -35,11 +35,13 @@ pub struct BlockTimeStamp(pub i64);
3535
pub struct PreviousBlockHash(pub Vec<u8>);
3636

3737
/// unique identifier of the ledger type.
38-
/// In general, this is the way to strictly bound and specify `block_data` of the ledger for the specific `ledger_type`.
38+
/// In general, this is the way to strictly bound and specify `block_data` of the ledger
39+
/// for the specific `ledger_type`.
3940
#[derive(Debug, Clone, PartialEq)]
4041
pub struct LedgerType(pub Uuid);
4142

42-
/// unique identifier of the purpose, each Ledger instance will have a strict time boundaries, so each of them will run for different purposes.
43+
/// unique identifier of the purpose, each Ledger instance will have a strict time
44+
/// boundaries, so each of them will run for different purposes.
4345
#[derive(Debug, Clone, PartialEq)]
4446
pub struct PurposeId(pub Ulid);
4547

@@ -71,7 +73,8 @@ pub struct EncodedGenesisBlockContents(pub Vec<u8>);
7173
#[derive(Debug, Clone, PartialEq)]
7274
pub struct Signatures(Vec<Signature>);
7375

74-
/// Validator's keys defined in the corresponding certificates referenced by the validator.
76+
/// Validator's keys defined in the corresponding certificates referenced by the
77+
/// validator.
7578
pub struct ValidatorKeys(pub Vec<[u8; SECRET_KEY_LENGTH]>);
7679

7780
/// Decoded block
@@ -112,16 +115,20 @@ pub type EncodedGenesisBlock = Vec<u8>;
112115
/// Choice of hash function:
113116
/// must be the same as the hash of the previous block.
114117
pub enum HashFunction {
115-
/// BLAKE3 is based on an optimized instance of the established hash function BLAKE2 and on the original Bao tree mode
118+
/// BLAKE3 is based on an optimized instance of the established hash function BLAKE2
119+
/// and on the original Bao tree mode
116120
Blake3,
117121
/// BLAKE2b-512 produces digest side of 512 bits.
118122
Blake2b,
119123
}
120124

121125
/// Encode standard block
126+
/// ## Errors
127+
///
128+
/// Returns an error if block encoding fails
122129
pub fn encode_block(
123-
block_hdr_cbor: Vec<u8>, block_data: EncodedBlockData, validator_keys: ValidatorKeys,
124-
hasher: HashFunction,
130+
block_hdr_cbor: Vec<u8>, block_data: &EncodedBlockData, validator_keys: &ValidatorKeys,
131+
hasher: &HashFunction,
125132
) -> anyhow::Result<EncodedBlock> {
126133
let hashed_block_header = match hasher {
127134
HashFunction::Blake3 => blake3(&block_hdr_cbor)?.to_vec(),
@@ -161,12 +168,15 @@ pub fn encode_block(
161168
Ok(encoded_block)
162169
}
163170

164-
/// Decoded standard block
165-
pub fn decode_block(encoded_block: Vec<u8>) -> anyhow::Result<DecodedBlock> {
171+
/// Decodes standard block
172+
/// ## Errors
173+
///
174+
/// Returns an error if block decoding fails
175+
pub fn decode_block(encoded_block: &[u8]) -> anyhow::Result<DecodedBlock> {
166176
// Decoded block hdr
167-
let block_hdr: DecodedBlockHeader = decode_block_header(encoded_block.clone())?;
177+
let block_hdr: DecodedBlockHeader = decode_block_header(encoded_block)?;
168178

169-
let mut cbor_decoder = minicbor::Decoder::new(&encoded_block);
179+
let mut cbor_decoder = minicbor::Decoder::new(encoded_block);
170180
// Decode remaining block, set position after block hdr data.
171181
cbor_decoder.set_position(block_hdr.8 .0);
172182

@@ -207,9 +217,13 @@ pub(crate) fn blake2b_512(value: &[u8]) -> anyhow::Result<[u8; 64]> {
207217
}
208218

209219
/// Encode block header
220+
/// ## Errors
221+
///
222+
/// Returns an error if block header encoding fails.
223+
#[allow(clippy::too_many_arguments)]
210224
pub fn encode_block_header(
211-
chain_id: ChainId, height: Height, ts: BlockTimeStamp, prev_block_hash: PreviousBlockHash,
212-
ledger_type: LedgerType, pid: PurposeId, validator: Validator, metadata: Option<Metadata>,
225+
chain_id: ChainId, height: Height, ts: BlockTimeStamp, prev_block_hash: &PreviousBlockHash,
226+
ledger_type: &LedgerType, pid: &PurposeId, validator: &Validator, metadata: Option<Metadata>,
213227
) -> anyhow::Result<Vec<u8>> {
214228
let out: Vec<u8> = Vec::new();
215229
let mut encoder = minicbor::Encoder::new(out);
@@ -235,9 +249,12 @@ pub fn encode_block_header(
235249
}
236250

237251
/// Decode block header
238-
pub fn decode_block_header(block: Vec<u8>) -> anyhow::Result<DecodedBlockHeader> {
252+
/// ## Errors
253+
///
254+
/// Returns an error if decoding block header fails.
255+
pub fn decode_block_header(block: &[u8]) -> anyhow::Result<DecodedBlockHeader> {
239256
// Decode cbor to bytes
240-
let mut cbor_decoder = minicbor::Decoder::new(&block);
257+
let mut cbor_decoder = minicbor::Decoder::new(block);
241258

242259
// Raw chain_id
243260
let chain_id = ChainId(Ulid::from_bytes(
@@ -325,11 +342,14 @@ pub fn decode_block_header(block: Vec<u8>) -> anyhow::Result<DecodedBlockHeader>
325342
}
326343

327344
/// Encode genesis block
345+
/// ## Errors
346+
///
347+
/// Returns an error if genesis block encoding fails.
328348
pub fn encode_genesis(
329-
chain_id: ChainId, ts: BlockTimeStamp, ledger_type: LedgerType, pid: PurposeId,
330-
validator: Validator, hasher: HashFunction,
349+
chain_id: ChainId, ts: BlockTimeStamp, ledger_type: &LedgerType, pid: &PurposeId,
350+
validator: &Validator, hasher: &HashFunction,
331351
) -> anyhow::Result<Vec<u8>> {
332-
// Genesis block MUST have 0 value
352+
/// Genesis block MUST have 0 value
333353
const BLOCK_HEIGHT: u32 = 0;
334354

335355
let out: Vec<u8> = Vec::new();
@@ -359,13 +379,17 @@ pub fn encode_genesis(
359379
};
360380

361381
// prev_block_id for the Genesis block MUST be a hash of the genesis_to_prev_hash bytes
362-
// last 64 bytes (depending on given hash function) of encoding are the hash of the genesis contents
382+
// last 64 bytes (depending on given hash function) of encoding are the hash of the
383+
// genesis contents
363384
encoder.bytes(genesis_prev_hash.as_slice())?;
364385

365386
Ok(encoder.writer().clone())
366387
}
367388

368389
/// Decode genesis
390+
/// ## Errors
391+
///
392+
/// Returns an error if block decoding for genesis fails.
369393
pub fn decode_genesis_block(genesis_block: Vec<u8>) -> anyhow::Result<DecodedBlockGenesis> {
370394
let binding = genesis_block.clone();
371395
let mut cbor_decoder = minicbor::Decoder::new(&binding);
@@ -467,19 +491,15 @@ pub fn decode_genesis_block(genesis_block: Vec<u8>) -> anyhow::Result<DecodedBlo
467491
#[cfg(test)]
468492
mod tests {
469493
use ed25519_dalek::{SigningKey, SECRET_KEY_LENGTH};
470-
471494
use ulid::Ulid;
472495
use uuid::Uuid;
473496

497+
use super::{decode_genesis_block, encode_genesis};
474498
use crate::serialize::{
475499
blake2b_512, decode_block, decode_block_header, encode_block, encode_block_header,
476-
BlockTimeStamp, ChainId, EncodedBlockData, Height, Kid, LedgerType, Metadata,
477-
PreviousBlockHash, PurposeId, Validator, ValidatorKeys,
500+
BlockTimeStamp, ChainId, EncodedBlockData, HashFunction::Blake2b, Height, Kid, LedgerType,
501+
Metadata, PreviousBlockHash, PurposeId, Validator, ValidatorKeys,
478502
};
479-
480-
use crate::serialize::HashFunction::Blake2b;
481-
482-
use super::{decode_genesis_block, encode_genesis};
483503
#[test]
484504
fn block_header_encode_decode() {
485505
let kid_a: [u8; 16] = hex::decode("00112233445566778899aabbccddeeff")
@@ -505,15 +525,15 @@ mod tests {
505525
chain_id,
506526
block_height,
507527
block_ts,
508-
prev_block_height.clone(),
509-
ledger_type.clone(),
510-
purpose_id.clone(),
511-
validators.clone(),
528+
&prev_block_height.clone(),
529+
&ledger_type.clone(),
530+
&purpose_id.clone(),
531+
&validators.clone(),
512532
metadata.clone(),
513533
)
514534
.unwrap();
515535

516-
let decoded_hdr = decode_block_header(encoded_block_hdr).unwrap();
536+
let decoded_hdr = decode_block_header(&encoded_block_hdr).unwrap();
517537
assert_eq!(decoded_hdr.0, chain_id);
518538
assert_eq!(decoded_hdr.1, block_height);
519539
assert_eq!(decoded_hdr.2, block_ts);
@@ -549,10 +569,10 @@ mod tests {
549569
chain_id,
550570
block_height,
551571
block_ts,
552-
prev_block_height.clone(),
553-
ledger_type.clone(),
554-
purpose_id.clone(),
555-
validators.clone(),
572+
&prev_block_height.clone(),
573+
&ledger_type.clone(),
574+
&purpose_id.clone(),
575+
&validators.clone(),
556576
metadata.clone(),
557577
)
558578
.unwrap();
@@ -578,13 +598,13 @@ mod tests {
578598

579599
let encoded_block = encode_block(
580600
encoded_block_hdr.clone(),
581-
EncodedBlockData(block_data_bytes.to_vec()),
582-
ValidatorKeys(vec![validator_secret_key_bytes, validator_secret_key_bytes]),
583-
Blake2b,
601+
&EncodedBlockData(block_data_bytes.to_vec()),
602+
&ValidatorKeys(vec![validator_secret_key_bytes, validator_secret_key_bytes]),
603+
&Blake2b,
584604
)
585605
.unwrap();
586606

587-
let decoded = decode_block(encoded_block).unwrap();
607+
let decoded = decode_block(&encoded_block).unwrap();
588608
assert_eq!(decoded.0 .0, chain_id);
589609
assert_eq!(decoded.0 .1, block_height);
590610
assert_eq!(decoded.0 .2, block_ts);
@@ -630,10 +650,10 @@ mod tests {
630650
let encoded_block_genesis = encode_genesis(
631651
chain_id,
632652
block_ts,
633-
ledger_type.clone(),
634-
purpose_id.clone(),
635-
validators.clone(),
636-
Blake2b,
653+
&ledger_type.clone(),
654+
&purpose_id.clone(),
655+
&validators.clone(),
656+
&Blake2b,
637657
)
638658
.unwrap();
639659

0 commit comments

Comments
 (0)