phoenix_core/
transaction.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Transaction skeleton defining the minimum amount of data needed for a
//! phoenix transaction.

extern crate alloc;
use alloc::vec::Vec;

#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize, Serialize};

use dusk_bls12_381::BlsScalar;
use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};

use crate::{Note, OUTPUT_NOTES};

/// A phoenix transaction, referred to as tx-skeleton in the specs.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
    feature = "rkyv-impl",
    derive(Archive, Serialize, Deserialize),
    archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct TxSkeleton {
    /// The root of the transfer tree on top of which this transaction is
    /// based.
    pub root: BlsScalar,
    /// The nullifiers of the old notes this transaction spends.
    pub nullifiers: Vec<BlsScalar>,
    /// The new output notes of this transaction.
    pub outputs: [Note; OUTPUT_NOTES],
    /// Describes the maximum fee to be paid for this transaction.
    pub max_fee: u64,
    /// A deposit is used to transferring funds to a contract
    pub deposit: u64,
}

impl TxSkeleton {
    /// Return input bytes to a hash function for the transaction.
    #[must_use]
    pub fn to_hash_input_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::new();

        bytes.extend(self.root.to_bytes());

        for nullifier in &self.nullifiers {
            bytes.extend(nullifier.to_bytes());
        }
        for note in &self.outputs {
            bytes.extend(note.to_bytes());
        }

        bytes.extend(self.max_fee.to_bytes());
        bytes.extend(self.deposit.to_bytes());

        bytes
    }

    /// Serialize the transaction to a variable length byte buffer.
    #[allow(unused_must_use)]
    pub fn to_var_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::new();

        bytes.extend(self.root.to_bytes());

        let num_nullifiers = self.nullifiers.len() as u64;
        bytes.extend(num_nullifiers.to_bytes());
        self.nullifiers.iter().for_each(|nullifier| {
            bytes.extend(nullifier.to_bytes());
        });

        self.outputs.iter().for_each(|note| {
            bytes.extend(note.to_bytes());
        });

        bytes.extend(self.max_fee.to_bytes());
        bytes.extend(self.deposit.to_bytes());

        bytes
    }

    /// Deserialize the transaction from a bytes buffer.
    pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
        let mut buffer = buf;
        let root = BlsScalar::from_reader(&mut buffer)?;

        let num_nullifiers = u64::from_reader(&mut buffer)?;
        let mut nullifiers = Vec::with_capacity(num_nullifiers as usize);
        for _ in 0..num_nullifiers {
            nullifiers.push(BlsScalar::from_reader(&mut buffer)?);
        }

        let mut outputs = Vec::with_capacity(OUTPUT_NOTES);
        for _ in 0..OUTPUT_NOTES {
            outputs.push(Note::from_reader(&mut buffer)?);
        }
        let outputs: [Note; OUTPUT_NOTES] =
            outputs.try_into().map_err(|_| BytesError::InvalidData)?;

        let max_fee = u64::from_reader(&mut buffer)?;
        let deposit = u64::from_reader(&mut buffer)?;

        Ok(Self {
            root,
            nullifiers,
            outputs,
            max_fee,
            deposit,
        })
    }

    /// Returns the inputs to the transaction.
    pub fn nullifiers(&self) -> &[BlsScalar] {
        &self.nullifiers
    }

    /// Returns the outputs of the transaction.
    pub fn outputs(&self) -> &[Note] {
        &self.outputs
    }

    /// Returns the maximum fee of the transaction.
    pub fn max_fee(&self) -> u64 {
        self.max_fee
    }

    /// Returns the deposit of the transaction.
    pub fn deposit(&self) -> u64 {
        self.deposit
    }
}