Skip to main content

phoenix_core/
transaction.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
7//! Transaction skeleton defining the minimum amount of data needed for a
8//! phoenix transaction.
9
10extern crate alloc;
11use alloc::vec::Vec;
12
13#[cfg(feature = "rkyv-impl")]
14use rkyv::{Archive, Deserialize, Serialize};
15
16use dusk_bls12_381::BlsScalar;
17use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
18
19use crate::{Note, OUTPUT_NOTES};
20
21/// A phoenix transaction, referred to as tx-skeleton in the specs.
22#[derive(Debug, Clone, PartialEq, Eq)]
23#[cfg_attr(
24    feature = "rkyv-impl",
25    derive(Archive, Serialize, Deserialize),
26    archive_attr(derive(bytecheck::CheckBytes))
27)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct TxSkeleton {
30    /// The root of the transfer tree on top of which this transaction is
31    /// based.
32    pub root: BlsScalar,
33    /// The nullifiers of the old notes this transaction spends.
34    pub nullifiers: Vec<BlsScalar>,
35    /// The new output notes of this transaction.
36    pub outputs: [Note; OUTPUT_NOTES],
37    /// Describes the maximum fee to be paid for this transaction.
38    #[cfg_attr(
39        feature = "serde",
40        serde(with = "serde_with::As::<serde_with::DisplayFromStr>")
41    )]
42    pub max_fee: u64,
43    /// A deposit is used to transferring funds to a contract
44    #[cfg_attr(
45        feature = "serde",
46        serde(with = "serde_with::As::<serde_with::DisplayFromStr>")
47    )]
48    pub deposit: u64,
49}
50
51impl TxSkeleton {
52    /// Return input bytes to a hash function for the transaction.
53    #[must_use]
54    pub fn to_hash_input_bytes(&self) -> Vec<u8> {
55        let mut bytes = Vec::new();
56
57        bytes.extend(self.root.to_bytes());
58
59        for nullifier in &self.nullifiers {
60            bytes.extend(nullifier.to_bytes());
61        }
62        for note in &self.outputs {
63            bytes.extend(note.to_bytes());
64        }
65
66        bytes.extend(self.max_fee.to_bytes());
67        bytes.extend(self.deposit.to_bytes());
68
69        bytes
70    }
71
72    /// Serialize the transaction to a variable length byte buffer.
73    #[allow(unused_must_use)]
74    pub fn to_var_bytes(&self) -> Vec<u8> {
75        let mut bytes = Vec::new();
76
77        bytes.extend(self.root.to_bytes());
78
79        let num_nullifiers = self.nullifiers.len() as u64;
80        bytes.extend(num_nullifiers.to_bytes());
81        self.nullifiers.iter().for_each(|nullifier| {
82            bytes.extend(nullifier.to_bytes());
83        });
84
85        self.outputs.iter().for_each(|note| {
86            bytes.extend(note.to_bytes());
87        });
88
89        bytes.extend(self.max_fee.to_bytes());
90        bytes.extend(self.deposit.to_bytes());
91
92        bytes
93    }
94
95    /// Deserialize the transaction from a bytes buffer.
96    pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
97        let mut buffer = buf;
98        let root = BlsScalar::from_reader(&mut buffer)?;
99
100        let num_nullifiers = u64::from_reader(&mut buffer)?;
101        let mut nullifiers = Vec::with_capacity(num_nullifiers as usize);
102        for _ in 0..num_nullifiers {
103            nullifiers.push(BlsScalar::from_reader(&mut buffer)?);
104        }
105
106        let mut outputs = Vec::with_capacity(OUTPUT_NOTES);
107        for _ in 0..OUTPUT_NOTES {
108            outputs.push(Note::from_reader(&mut buffer)?);
109        }
110        let outputs: [Note; OUTPUT_NOTES] =
111            outputs.try_into().map_err(|_| BytesError::InvalidData)?;
112
113        let max_fee = u64::from_reader(&mut buffer)?;
114        let deposit = u64::from_reader(&mut buffer)?;
115
116        Ok(Self {
117            root,
118            nullifiers,
119            outputs,
120            max_fee,
121            deposit,
122        })
123    }
124
125    /// Returns the inputs to the transaction.
126    pub fn nullifiers(&self) -> &[BlsScalar] {
127        &self.nullifiers
128    }
129
130    /// Returns the outputs of the transaction.
131    pub fn outputs(&self) -> &[Note] {
132        &self.outputs
133    }
134
135    /// Returns the maximum fee of the transaction.
136    pub fn max_fee(&self) -> u64 {
137        self.max_fee
138    }
139
140    /// Returns the deposit of the transaction.
141    pub fn deposit(&self) -> u64 {
142        self.deposit
143    }
144}