1use std::io::{self, Read, Write};
8
9use crate::bls::PublicKeyBytes;
10use crate::ledger::{
11 Attestation, Block, Fault, Header, IterationsInfo, Label,
12 LedgerTransaction, Signature, SpentTransaction, StepVotes,
13};
14use crate::message::payload::{
15 QuorumType, Ratification, RatificationResult, ValidationQuorum,
16 ValidationResult, Vote,
17};
18use crate::message::{
19 ConsensusHeader, MESSAGE_MAX_FAILED_ITERATIONS, SignInfo,
20};
21use crate::{
22 MAX_NUMBER_OF_FAULTS, MAX_NUMBER_OF_TRANSACTIONS, MAX_SPENT_TX_ERROR_BYTES,
23 Serializable,
24};
25
26const MAX_TX_LENGTH_BYTES: usize = 2 * 1024 * 1024;
27
28struct RawTransaction {
31 version: u32,
32 tx_type: u32,
33 protocol_tx: Vec<u8>,
34}
35
36fn read_raw_transaction<R: Read>(r: &mut R) -> io::Result<RawTransaction> {
37 Ok(RawTransaction {
38 version: LedgerTransaction::read_u32_le(r)?,
39 tx_type: LedgerTransaction::read_u32_le(r)?,
40 protocol_tx: LedgerTransaction::read_var_le_bytes32(
41 r,
42 MAX_TX_LENGTH_BYTES,
43 )?,
44 })
45}
46
47fn decode_transaction(
48 raw: RawTransaction,
49 decode_inner: impl FnOnce(&[u8]) -> Result<LedgerTransaction, dusk_bytes::Error>,
50) -> io::Result<LedgerTransaction> {
51 let mut tx = decode_inner(&raw.protocol_tx[..])
52 .map_err(|_| io::Error::from(io::ErrorKind::InvalidData))?;
53 tx.version = raw.version;
54 tx.r#type = raw.tx_type;
55 Ok(tx)
56}
57
58fn read_protocol_transaction<R: Read>(
59 r: &mut R,
60 decode_inner: impl FnOnce(&[u8]) -> Result<LedgerTransaction, dusk_bytes::Error>,
61) -> io::Result<LedgerTransaction> {
62 decode_transaction(read_raw_transaction(r)?, decode_inner)
63}
64
65fn read_spent_transaction_fields<R: Read>(
66 r: &mut R,
67) -> io::Result<(RawTransaction, u64, u64, Option<String>)> {
68 let raw = read_raw_transaction(r)?;
69 let block_height = SpentTransaction::read_u64_le(r)?;
70 let gas_spent = SpentTransaction::read_u64_le(r)?;
71 let error_len = SpentTransaction::read_u32_le(r)?;
72 if error_len as usize > MAX_SPENT_TX_ERROR_BYTES {
73 return Err(io::Error::new(
74 io::ErrorKind::InvalidData,
75 format!(
76 "SpentTransaction error string too large: {error_len} > {MAX_SPENT_TX_ERROR_BYTES}"
77 ),
78 ));
79 }
80
81 let err = if error_len > 0 {
82 let mut buf = vec![0u8; error_len as usize];
83 r.read_exact(&mut buf[..])?;
84
85 Some(String::from_utf8(buf).map_err(|_| {
86 io::Error::new(
87 io::ErrorKind::InvalidData,
88 "invalid utf-8 in SpentTransaction error string",
89 )
90 })?)
91 } else {
92 None
93 };
94
95 Ok((raw, block_height, gas_spent, err))
96}
97
98impl Serializable for Block {
99 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
100 self.header().write(w)?;
101
102 let txs_len = self.txs().len() as u32;
103 w.write_all(&txs_len.to_le_bytes())?;
104
105 for t in self.txs().iter() {
106 t.write(w)?;
107 }
108
109 let faults_len = self.faults().len() as u32;
110 w.write_all(&faults_len.to_le_bytes())?;
111
112 for f in self.faults().iter() {
113 f.write(w)?;
114 }
115 Ok(())
116 }
117
118 fn read<R: Read>(r: &mut R) -> io::Result<Self>
119 where
120 Self: Sized,
121 {
122 let header = Header::read(r)?;
123
124 let tx_len = Self::read_u32_le(r)?;
126 if tx_len as usize > MAX_NUMBER_OF_TRANSACTIONS {
127 return Err(io::Error::new(
128 io::ErrorKind::InvalidData,
129 format!(
130 "too many block transactions: {tx_len} > {MAX_NUMBER_OF_TRANSACTIONS}"
131 ),
132 ));
133 }
134
135 let txs = (0..tx_len)
136 .map(|_| LedgerTransaction::read(r))
137 .collect::<Result<Vec<_>, _>>()?;
138
139 let faults_len = Self::read_u32_le(r)?;
141 if faults_len as usize > MAX_NUMBER_OF_FAULTS {
142 return Err(io::Error::new(
143 io::ErrorKind::InvalidData,
144 format!(
145 "too many block faults: {faults_len} > {MAX_NUMBER_OF_FAULTS}"
146 ),
147 ));
148 }
149
150 let faults = (0..faults_len)
151 .map(|_| Fault::read(r))
152 .collect::<Result<Vec<_>, _>>()?;
153
154 Block::new(header, txs, faults)
155 }
156}
157
158impl Serializable for LedgerTransaction {
159 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
160 w.write_all(&self.version.to_le_bytes())?;
162
163 w.write_all(&self.r#type.to_le_bytes())?;
165
166 let data = self.protocol_bytes();
167
168 Self::write_var_le_bytes32(w, &data)?;
170
171 Ok(())
172 }
173
174 fn read<R: Read>(r: &mut R) -> io::Result<Self>
175 where
176 Self: Sized,
177 {
178 read_protocol_transaction(r, LedgerTransaction::decode_any)
179 }
180}
181
182impl Serializable for SpentTransaction {
183 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
184 self.inner.write(w)?;
185 w.write_all(&self.block_height.to_le_bytes())?;
186 w.write_all(&self.gas_spent.to_le_bytes())?;
187
188 match &self.err {
189 Some(e) => {
190 let b = e.as_bytes();
191 w.write_all(&(b.len() as u32).to_le_bytes())?;
192 w.write_all(b)?;
193 }
194 None => {
195 w.write_all(&0_u32.to_le_bytes())?;
196 }
197 }
198
199 Ok(())
200 }
201
202 fn read<R: Read>(r: &mut R) -> io::Result<Self>
203 where
204 Self: Sized,
205 {
206 let (raw, block_height, gas_spent, err) =
207 read_spent_transaction_fields(r)?;
208 let inner = decode_transaction(raw, |bytes| {
209 LedgerTransaction::decode_for_ledger(bytes, block_height)
210 })?;
211
212 Ok(Self {
213 inner,
214 block_height,
215 gas_spent,
216 err,
217 })
218 }
219}
220
221impl Serializable for Header {
222 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
223 self.marshal_hashable(w)?;
224 self.att.write(w)?;
225 w.write_all(&self.hash)?;
226 w.write_all(self.signature.inner())?;
227
228 Ok(())
229 }
230
231 fn read<R: Read>(r: &mut R) -> io::Result<Self>
232 where
233 Self: Sized,
234 {
235 let mut header = Self::unmarshal_hashable(r)?;
236 header.att = Attestation::read(r)?;
237 header.hash = Self::read_bytes(r)?;
238 header.signature = Signature::from(Self::read_bytes(r)?);
239 Ok(header)
240 }
241}
242
243impl Serializable for Attestation {
244 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
245 self.result.write(w)?;
246 self.validation.write(w)?;
247 self.ratification.write(w)?;
248
249 Ok(())
250 }
251
252 fn read<R: Read>(r: &mut R) -> io::Result<Self>
253 where
254 Self: Sized,
255 {
256 let result = RatificationResult::read(r)?;
257 let validation = StepVotes::read(r)?;
258 let ratification = StepVotes::read(r)?;
259
260 Ok(Attestation {
261 result,
262 validation,
263 ratification,
264 })
265 }
266}
267
268impl Serializable for StepVotes {
269 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
270 w.write_all(&self.bitset.to_le_bytes())?;
271 w.write_all(self.aggregate_signature.inner())?;
272
273 Ok(())
274 }
275
276 fn read<R: Read>(r: &mut R) -> io::Result<Self>
277 where
278 Self: Sized,
279 {
280 let bitset = Self::read_u64_le(r)?;
281 let aggregate_signature = Self::read_bytes(r)?;
282
283 Ok(StepVotes {
284 bitset,
285 aggregate_signature: aggregate_signature.into(),
286 })
287 }
288}
289
290impl Serializable for RatificationResult {
291 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
292 match self {
293 RatificationResult::Fail(v) => {
294 w.write_all(&[0])?;
295 v.write(w)?;
296 }
297
298 RatificationResult::Success(v) => {
299 w.write_all(&[1])?;
300 v.write(w)?;
301 }
302 }
303
304 Ok(())
305 }
306
307 fn read<R: Read>(r: &mut R) -> io::Result<Self>
308 where
309 Self: Sized,
310 {
311 let result = match Self::read_u8(r)? {
312 0 => {
313 let vote = Vote::read(r)?;
314 Self::Fail(vote)
315 }
316 1 => {
317 let vote = Vote::read(r)?;
318 Self::Success(vote)
319 }
320 _ => Err(io::Error::new(
321 io::ErrorKind::InvalidData,
322 "Invalid RatificationResult",
323 ))?,
324 };
325 Ok(result)
326 }
327}
328
329impl Serializable for IterationsInfo {
330 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
331 let count = self.att_list.len() as u8;
332 w.write_all(&count.to_le_bytes())?;
333
334 for iter in &self.att_list {
335 match iter {
336 Some((att, pk)) => {
337 w.write_all(&[1])?;
338 att.write(w)?;
339 w.write_all(pk.inner())?;
340 }
341 None => w.write_all(&[0])?,
342 }
343 }
344
345 Ok(())
346 }
347
348 fn read<R: Read>(r: &mut R) -> io::Result<Self>
349 where
350 Self: Sized,
351 {
352 let mut att_list = vec![];
353
354 let count = Self::read_u8(r)?;
355
356 if count > MESSAGE_MAX_FAILED_ITERATIONS {
358 return Err(io::Error::new(
359 io::ErrorKind::InvalidData,
360 format!("Invalid iterations_info count {count})"),
361 ));
362 }
363
364 for _ in 0..count {
365 let opt = Self::read_u8(r)?;
366
367 let att = match opt {
368 0 => None,
369 1 => {
370 let att = Attestation::read(r)?;
371 let pk = Self::read_bytes(r)?;
372 Some((att, PublicKeyBytes(pk)))
373 }
374 _ => {
375 return Err(io::Error::new(
376 io::ErrorKind::InvalidData,
377 "Invalid option",
378 ));
379 }
380 };
381 att_list.push(att)
382 }
383
384 Ok(IterationsInfo { att_list })
385 }
386}
387
388impl Serializable for Label {
389 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
390 match self {
391 Label::Accepted(v) => {
392 w.write_all(&0u8.to_le_bytes())?;
393 w.write_all(&v.to_le_bytes())?;
394 }
395 Label::Attested(v) => {
396 w.write_all(&1u8.to_le_bytes())?;
397 w.write_all(&v.to_le_bytes())?;
398 }
399 Label::Confirmed(v) => {
400 w.write_all(&2u8.to_le_bytes())?;
401 w.write_all(&v.to_le_bytes())?;
402 }
403 Label::Final(v) => {
404 w.write_all(&3u8.to_le_bytes())?;
405 w.write_all(&v.to_le_bytes())?;
406 }
407 }
408
409 Ok(())
410 }
411
412 fn read<R: Read>(r: &mut R) -> io::Result<Self>
413 where
414 Self: Sized,
415 {
416 let label = Self::read_u8(r)?;
417 let label = match label {
418 0 => Label::Accepted(Self::read_u64_le(r)?),
419 1 => Label::Attested(Self::read_u64_le(r)?),
420 2 => Label::Confirmed(Self::read_u64_le(r)?),
421 3 => Label::Final(Self::read_u64_le(r)?),
422 _ => Err(io::Error::new(
423 io::ErrorKind::InvalidData,
424 "Invalid label",
425 ))?,
426 };
427
428 Ok(label)
429 }
430}
431
432impl Serializable for Ratification {
433 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
434 self.header.write(w)?;
435 self.vote.write(w)?;
436 w.write_all(&self.timestamp.to_le_bytes())?;
437 self.validation_result.write(w)?;
438 self.sign_info.write(w)?;
440
441 Ok(())
442 }
443
444 fn read<R: Read>(r: &mut R) -> io::Result<Self>
445 where
446 Self: Sized,
447 {
448 let header = ConsensusHeader::read(r)?;
449 let vote = Vote::read(r)?;
450 let timestamp = Self::read_u64_le(r)?;
451 let validation_result = ValidationResult::read(r)?;
452 let sign_info = SignInfo::read(r)?;
453
454 Ok(Ratification {
455 header,
456 vote,
457 sign_info,
458 timestamp,
459 validation_result,
460 })
461 }
462}
463
464impl Serializable for ValidationResult {
465 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
466 self.step_votes.write(w)?;
467 self.vote.write(w)?;
468 self.quorum.write(w)?;
469
470 Ok(())
471 }
472
473 fn read<R: Read>(r: &mut R) -> io::Result<Self>
474 where
475 Self: Sized,
476 {
477 let step_votes: StepVotes = StepVotes::read(r)?;
478 let vote = Vote::read(r)?;
479 let quorum = QuorumType::read(r)?;
480
481 Ok(ValidationResult::new(step_votes, vote, quorum))
482 }
483}
484
485impl Serializable for ValidationQuorum {
486 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
487 self.header.write(w)?;
488 self.result.write(w)?;
489
490 Ok(())
491 }
492
493 fn read<R: Read>(r: &mut R) -> io::Result<Self>
494 where
495 Self: Sized,
496 {
497 let header = ConsensusHeader::read(r)?;
498 let result = ValidationResult::read(r)?;
499
500 Ok(ValidationQuorum { header, result })
501 }
502}
503
504impl Serializable for QuorumType {
505 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
506 let val: u8 = *self as u8;
507 w.write_all(&val.to_le_bytes())
508 }
509
510 fn read<R: Read>(r: &mut R) -> io::Result<Self>
511 where
512 Self: Sized,
513 {
514 Ok(Self::read_u8(r)?.into())
515 }
516}
517
518#[cfg(test)]
519mod tests {
520 use std::io;
521
522 use dusk_core::transfer::TransactionFormat;
523 use fake::{Dummy, Fake, Faker};
524
525 use super::*;
526 use crate::hard_fork::{
527 set_aegis_activation_height, set_boreas_activation_height,
528 };
529 use crate::message::payload::{Candidate, Validation};
530
531 const HISTORICAL_PRE_AEGIS_TX_HEX: &str = include_str!(concat!(
532 env!("CARGO_MANIFEST_DIR"),
533 "/../test-fixtures/pre_aegis_3422299.tx.hex"
534 ));
535
536 fn assert_serializable<S: Dummy<Faker> + Eq + Serializable>() {
538 let obj: S = Faker.fake();
539 let mut buf = vec![];
540 obj.write(&mut buf).expect("should be writable");
541
542 assert!(obj.eq(&S::read(&mut &buf[..]).expect("should be readable")));
543 }
544
545 #[test]
546 fn test_encoding_iterations_info() {
547 assert_serializable::<IterationsInfo>();
548 }
549
550 #[test]
551 fn test_encoding_ratification() {
552 assert_serializable::<Ratification>();
553 }
554
555 #[test]
556 fn test_encoding_validation() {
557 assert_serializable::<Validation>();
558 }
559
560 #[test]
561 fn test_encoding_candidate() {
562 assert_serializable::<Candidate>();
563 }
564
565 #[test]
566 fn test_encoding_att() {
567 assert_serializable::<Attestation>();
568 }
569
570 #[test]
571 fn test_encoding_transaction() {
572 assert_serializable::<LedgerTransaction>();
573 }
574
575 fn assert_transaction_roundtrip(
576 tx: LedgerTransaction,
577 ) -> LedgerTransaction {
578 let mut buf = vec![];
579 tx.write(&mut buf).expect("should be writable");
580
581 let decoded =
582 LedgerTransaction::read(&mut &buf[..]).expect("should decode");
583 assert_eq!(decoded, tx);
584 decoded
585 }
586
587 #[test]
588 fn test_encoding_transaction_boreas() {
589 let tx: LedgerTransaction =
590 LedgerTransaction::from_protocol_with_format(
591 Faker.fake::<LedgerTransaction>().protocol().clone(),
592 TransactionFormat::Boreas,
593 );
594 let decoded = assert_transaction_roundtrip(tx);
595 assert_eq!(decoded.format(), TransactionFormat::Boreas);
596 }
597
598 #[test]
599 fn test_encoding_block_with_pre_aegis_transaction() {
600 let header: Header = Faker.fake();
601 let tx = LedgerTransaction::decode_any(
602 &hex::decode(HISTORICAL_PRE_AEGIS_TX_HEX.trim())
603 .expect("fixture hex should decode"),
604 )
605 .expect("historical tx should decode");
606 let block = Block::new(header, vec![tx], vec![])
607 .expect("block construction should succeed");
608
609 let mut buf = vec![];
610 block
611 .write(&mut buf)
612 .expect("block encoding should succeed");
613
614 let decoded = Block::read(&mut &buf[..])
615 .expect("block decoding should preserve legacy transactions");
616 assert_eq!(decoded.txs().len(), 1);
617 assert_eq!(decoded.txs()[0].format(), TransactionFormat::PreAegis);
618 assert_eq!(decoded.txs()[0].id(), block.txs()[0].id());
619 }
620
621 #[test]
622 fn test_encoding_spent_transaction() {
623 assert_serializable::<SpentTransaction>();
624 }
625
626 #[test]
627 fn test_encoding_spent_transaction_boreas() {
628 set_aegis_activation_height(10);
629 set_boreas_activation_height(200);
630
631 let tx: LedgerTransaction =
632 LedgerTransaction::from_protocol_with_format(
633 Faker.fake::<LedgerTransaction>().protocol().clone(),
634 TransactionFormat::Boreas,
635 );
636 let spent_tx = SpentTransaction {
637 inner: tx,
638 block_height: 200,
639 gas_spent: 3,
640 err: None,
641 };
642
643 let mut buf = vec![];
644 spent_tx.write(&mut buf).expect("should be writable");
645 let decoded =
646 SpentTransaction::read(&mut &buf[..]).expect("should decode");
647 assert_eq!(decoded, spent_tx);
648 assert_eq!(decoded.inner.format(), TransactionFormat::Boreas);
649 }
650
651 #[test]
652 fn test_spent_transaction_rejects_malformed_error_string() {
653 fn decode_err(
654 tx: &LedgerTransaction,
655 error_len: u32,
656 error_bytes: &[u8],
657 ) -> io::Result<SpentTransaction> {
658 let mut bytes = vec![];
659 tx.write(&mut bytes)
660 .expect("transaction encoding should succeed");
661 bytes.extend_from_slice(&123_u64.to_le_bytes()); bytes.extend_from_slice(&456_u64.to_le_bytes()); bytes.extend_from_slice(&error_len.to_le_bytes());
664 bytes.extend_from_slice(error_bytes);
665 SpentTransaction::read(&mut &bytes[..])
666 }
667
668 let tx: LedgerTransaction = Faker.fake();
669
670 let err = decode_err(&tx, 2, &[0xFF, 0xFF])
671 .expect_err("invalid utf-8 error bytes must be rejected");
672 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
673
674 let err = decode_err(&tx, (MAX_SPENT_TX_ERROR_BYTES as u32) + 1, &[])
675 .expect_err("oversized error string must be rejected");
676 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
677 }
678
679 #[test]
680 fn test_spent_transaction_none_error_encoding_has_no_trailing_bytes() {
681 let mut spent_tx: SpentTransaction = Faker.fake();
682 spent_tx.err = None;
683
684 let mut bytes = vec![];
685 spent_tx
686 .write(&mut bytes)
687 .expect("spent transaction encoding should succeed");
688
689 let mut slice = &bytes[..];
690 let decoded = SpentTransaction::read(&mut slice)
691 .expect("spent transaction decoding should succeed");
692 assert!(decoded.err.is_none());
693 assert!(slice.is_empty(), "deserializer left trailing bytes");
694 }
695
696 #[test]
697 fn test_encoding_header() {
698 assert_serializable::<ConsensusHeader>();
699 }
700
701 #[test]
702 fn test_encoding_block() {
703 assert_serializable::<Block>();
704 }
705
706 #[test]
707 fn test_encoding_ratification_result() {
708 assert_serializable::<RatificationResult>();
709 }
710
711 #[test]
712 fn test_encoding_fault() {
713 assert_serializable::<Fault>();
714 }
715
716 #[test]
717 fn test_rejects_oversized_lengths() {
718 fn assert_invalid_data<T>(result: io::Result<T>, reason: &str) {
719 match result {
720 Ok(_) => panic!("{reason}"),
721 Err(err) => {
722 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
723 }
724 }
725 }
726
727 let mut tx_bytes = vec![];
728 tx_bytes.extend_from_slice(&1_u32.to_le_bytes()); tx_bytes.extend_from_slice(&1_u32.to_le_bytes()); tx_bytes.extend_from_slice(
731 &((MAX_TX_LENGTH_BYTES as u32) + 1).to_le_bytes(),
732 );
733 assert_invalid_data(
734 LedgerTransaction::read(&mut &tx_bytes[..]),
735 "oversized length-prefixed tx payload must be rejected",
736 );
737
738 let mut block_txs_bytes = vec![];
739 Header::default()
740 .write(&mut block_txs_bytes)
741 .expect("header encoding should succeed");
742 block_txs_bytes.extend_from_slice(
743 &((MAX_NUMBER_OF_TRANSACTIONS as u32) + 1).to_le_bytes(),
744 );
745 assert_invalid_data(
746 Block::read(&mut &block_txs_bytes[..]),
747 "block with too many transactions must be rejected",
748 );
749
750 let mut block_faults_bytes = vec![];
751 Header::default()
752 .write(&mut block_faults_bytes)
753 .expect("header encoding should succeed");
754 block_faults_bytes.extend_from_slice(&0_u32.to_le_bytes()); block_faults_bytes.extend_from_slice(
756 &((MAX_NUMBER_OF_FAULTS as u32) + 1).to_le_bytes(),
757 );
758 assert_invalid_data(
759 Block::read(&mut &block_faults_bytes[..]),
760 "block with too many faults must be rejected",
761 );
762 }
763}