dusk_node_data/events/
transactions.rs1use std::collections::HashMap;
8
9use dusk_core::transfer::RefundAddress;
10
11use super::*;
12use crate::ledger::{Hash, LedgerTransaction, SpentTransaction};
13
14#[derive(Clone, Debug)]
51pub enum TransactionEvent<'t> {
52 Deferred(Hash, &'static str),
53 Dropped(Hash, &'static str),
54 Removed(Hash),
55 Included(&'t LedgerTransaction),
56 Executed(&'t SpentTransaction),
57}
58
59impl EventSource for TransactionEvent<'_> {
60 const COMPONENT: &'static str = "transactions";
61
62 fn topic(&self) -> &'static str {
63 match self {
64 Self::Deferred(_, _) => "deferred",
65 Self::Dropped(_, _) => "dropped",
66 Self::Removed(_) => "removed",
67 Self::Executed(_) => "executed",
68 Self::Included(_) => "included",
69 }
70 }
71 fn data(&self) -> Option<serde_json::Value> {
72 match self {
73 Self::Deferred(_, reason) | Self::Dropped(_, reason) => {
74 Some(serde_json::json!({ "reason": reason }))
75 }
76 Self::Removed(_) => None,
77 Self::Executed(t) => serde_json::to_value(t).ok(),
78 Self::Included(t) => serde_json::to_value(t).ok(),
79 }
80 }
81 fn entity(&self) -> String {
82 let hash = match self {
83 Self::Deferred(hash, _)
84 | Self::Dropped(hash, _)
85 | Self::Removed(hash) => *hash,
86 Self::Executed(tx) => tx.inner.id(),
87 Self::Included(tx) => tx.id(),
88 };
89 hex::encode(hash)
90 }
91}
92use base64::Engine;
93use base64::engine::general_purpose::STANDARD as BASE64_ENGINE;
94use dusk_bytes::Serializable;
95use dusk_core::transfer::Transaction as ProtocolTransaction;
96use serde::ser::{Serialize, SerializeStruct, Serializer};
97
98impl Serialize for LedgerTransaction {
99 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
100 where
101 S: Serializer,
102 {
103 let mut state = serializer.serialize_struct("Transaction", 1)?;
104 match self.protocol() {
105 ProtocolTransaction::Phoenix(p) => {
106 state.serialize_field("type", "phoenix")?;
107
108 let root = p.root().to_bytes();
109 state.serialize_field("root", &hex::encode(root))?;
110
111 let nullifiers: Vec<_> = p
112 .nullifiers()
113 .iter()
114 .map(|n| hex::encode(n.to_bytes()))
115 .collect();
116 state.serialize_field("nullifiers", &nullifiers)?;
117 }
118 ProtocolTransaction::Moonlight(m) => {
119 state.serialize_field("type", "moonlight")?;
120
121 let sender = m.sender();
122 let sender = bs58::encode(sender.to_bytes()).into_string();
123 state.serialize_field("sender", &sender)?;
124
125 let receiver = m.receiver().map(|receiver| {
126 bs58::encode(receiver.to_bytes()).into_string()
127 });
128 state.serialize_field("receiver", &receiver)?;
129
130 state.serialize_field("value", &m.value())?;
131
132 state.serialize_field("nonce", &m.nonce())?;
133 }
134 }
135
136 let tx = self.protocol();
137
138 state.serialize_field("deposit", &tx.deposit())?;
139
140 let notes: Vec<Note<'_>> =
141 tx.outputs().iter().map(Note::from).collect();
142
143 if !notes.is_empty() {
144 state.serialize_field("outputs", ¬es)?;
145 }
146
147 let fee = {
148 let mut fee = HashMap::new();
149 fee.insert("gas_limit", tx.gas_limit().to_string());
150 fee.insert("gas_price", tx.gas_price().to_string());
151
152 let encoded_address = match tx.refund_address() {
153 RefundAddress::Phoenix(address) => {
154 bs58::encode(address.to_bytes()).into_string()
155 }
156 RefundAddress::Moonlight(address) => {
157 bs58::encode(address.to_bytes()).into_string()
158 }
159 };
160 fee.insert("refund_address", encoded_address);
161 if let ProtocolTransaction::Phoenix(tx) = tx {
162 fee.insert(
163 "phoenix sender",
164 hex::encode(tx.sender().to_bytes()),
165 );
166 }
167
168 fee
169 };
170
171 state.serialize_field("fee", &fee)?;
172
173 let call = tx.call().map(|c| {
174 let mut call = HashMap::new();
175 call.insert("contract", hex::encode(c.contract));
176 call.insert("fn_name", c.fn_name.to_string());
177 call.insert("fn_args", BASE64_ENGINE.encode(&c.fn_args));
178 call
179 });
180 state.serialize_field("call", &call)?;
181
182 state.serialize_field("is_deploy", &tx.deploy().is_some())?;
183 state.serialize_field("memo", &tx.memo().map(hex::encode))?;
184 state.end()
185 }
186}
187
188struct Note<'a>(&'a dusk_core::transfer::phoenix::Note);
189
190impl<'a> From<&'a dusk_core::transfer::phoenix::Note> for Note<'a> {
191 fn from(value: &'a dusk_core::transfer::phoenix::Note) -> Self {
192 Self(value)
193 }
194}
195
196impl Serialize for Note<'_> {
197 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198 where
199 S: Serializer,
200 {
201 let mut state = serializer.serialize_struct("Note", 5)?;
202 let n = self.0;
203
204 state.serialize_field("type", &(n.note_type() as u8))?;
205
206 let commitment = [
207 hex::encode(n.value_commitment().get_u().to_bytes()),
208 hex::encode(n.value_commitment().get_v().to_bytes()),
209 ];
210 state.serialize_field("value_commitment", &commitment)?;
211
212 let stealth_address = n.stealth_address().to_bytes();
213 state.serialize_field(
214 "stealth_address",
215 &bs58::encode(stealth_address).into_string(),
216 )?;
217
218 state.serialize_field("value_enc", &hex::encode(n.value_enc()))?;
219 state.serialize_field("sender", &hex::encode(n.sender().to_bytes()))?;
220 state.end()
221 }
222}