bee_block/payload/transaction/
mod.rs1mod essence;
7mod transaction_id;
8
9use crypto::hashes::{blake2b::Blake2b256, Digest};
10use packable::{error::UnpackError, packer::Packer, unpacker::Unpacker, Packable, PackableExt};
11
12pub(crate) use self::essence::{InputCount, OutputCount};
13pub use self::{
14 essence::{RegularTransactionEssence, RegularTransactionEssenceBuilder, TransactionEssence},
15 transaction_id::TransactionId,
16};
17use crate::{protocol::ProtocolParameters, unlock::Unlocks, Error};
18
19#[derive(Clone, Debug, Eq, PartialEq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct TransactionPayload {
23 essence: TransactionEssence,
24 unlocks: Unlocks,
25}
26
27impl TransactionPayload {
28 pub const KIND: u32 = 6;
30
31 pub fn new(essence: TransactionEssence, unlocks: Unlocks) -> Result<TransactionPayload, Error> {
33 verify_essence_unlocks(&essence, &unlocks)?;
34
35 Ok(TransactionPayload { essence, unlocks })
36 }
37
38 pub fn essence(&self) -> &TransactionEssence {
40 &self.essence
41 }
42
43 pub fn unlocks(&self) -> &Unlocks {
45 &self.unlocks
46 }
47
48 pub fn id(&self) -> TransactionId {
50 let mut hasher = Blake2b256::new();
51
52 hasher.update(Self::KIND.to_le_bytes());
53 hasher.update(self.pack_to_vec());
54
55 TransactionId::new(hasher.finalize().into())
56 }
57}
58
59impl Packable for TransactionPayload {
60 type UnpackError = Error;
61 type UnpackVisitor = ProtocolParameters;
62
63 fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
64 self.essence.pack(packer)?;
65 self.unlocks.pack(packer)?;
66
67 Ok(())
68 }
69
70 fn unpack<U: Unpacker, const VERIFY: bool>(
71 unpacker: &mut U,
72 visitor: &Self::UnpackVisitor,
73 ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
74 let essence = TransactionEssence::unpack::<_, VERIFY>(unpacker, visitor)?;
75 let unlocks = Unlocks::unpack::<_, VERIFY>(unpacker, &())?;
76
77 if VERIFY {
78 verify_essence_unlocks(&essence, &unlocks).map_err(UnpackError::Packable)?;
79 }
80
81 Ok(TransactionPayload { essence, unlocks })
82 }
83}
84
85fn verify_essence_unlocks(essence: &TransactionEssence, unlocks: &Unlocks) -> Result<(), Error> {
86 match essence {
87 TransactionEssence::Regular(ref essence) => {
88 if essence.inputs().len() != unlocks.len() {
89 return Err(Error::InputUnlockCountMismatch {
90 input_count: essence.inputs().len(),
91 unlock_count: unlocks.len(),
92 });
93 }
94 }
95 }
96
97 Ok(())
98}
99
100#[cfg(feature = "dto")]
101#[allow(missing_docs)]
102pub mod dto {
103 use serde::{Deserialize, Serialize};
104
105 pub use super::essence::dto::{RegularTransactionEssenceDto, TransactionEssenceDto};
106 use super::*;
107 use crate::{error::dto::DtoError, unlock::dto::UnlockDto};
108
109 #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
111 pub struct TransactionPayloadDto {
112 #[serde(rename = "type")]
113 pub kind: u32,
114 pub essence: TransactionEssenceDto,
115 pub unlocks: Vec<UnlockDto>,
116 }
117
118 impl From<&TransactionPayload> for TransactionPayloadDto {
119 fn from(value: &TransactionPayload) -> Self {
120 TransactionPayloadDto {
121 kind: TransactionPayload::KIND,
122 essence: value.essence().into(),
123 unlocks: value.unlocks().iter().map(Into::into).collect::<Vec<_>>(),
124 }
125 }
126 }
127
128 impl TransactionPayload {
129 pub fn try_from_dto(
130 value: &TransactionPayloadDto,
131 protocol_parameters: &ProtocolParameters,
132 ) -> Result<TransactionPayload, DtoError> {
133 let mut unlocks = Vec::new();
134
135 for b in &value.unlocks {
136 unlocks.push(b.try_into()?);
137 }
138
139 Ok(TransactionPayload::new(
140 TransactionEssence::try_from_dto(&value.essence, protocol_parameters)?,
141 Unlocks::new(unlocks)?,
142 )?)
143 }
144 }
145}