Skip to main content

dusk_node_data/
encoding.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use 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
28/// Decoded outer transaction envelope used while reconstructing a
29/// [`LedgerTransaction`].
30struct 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        // Read transactions count
125        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        // Read faults count
140        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        // Write version
161        w.write_all(&self.version.to_le_bytes())?;
162
163        // Write TxType
164        w.write_all(&self.r#type.to_le_bytes())?;
165
166        let data = self.protocol_bytes();
167
168        // Write inner transaction
169        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        // Iteration is 0-based
357        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        // sign_info at the end
439        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    /// Asserts if encoding/decoding of a serializable type runs properly.
537    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()); // block_height
662            bytes.extend_from_slice(&456_u64.to_le_bytes()); // gas_spent
663            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()); // version
729        tx_bytes.extend_from_slice(&1_u32.to_le_bytes()); // tx type
730        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()); // tx_len
755        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}