1use alloc::vec::Vec;
11
12use bytecheck::CheckBytes;
13use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
14use rkyv::{Archive, Deserialize, Serialize};
15#[cfg(feature = "serde")]
16use serde_with::{As, DisplayFromStr};
17
18use crate::signatures::bls::{
19 PublicKey as AccountPublicKey, SecretKey as AccountSecretKey,
20 Signature as AccountSignature,
21};
22use crate::transfer::data::{
23 BlobData, ContractBytecode, ContractCall, ContractDeploy, MAX_MEMO_SIZE,
24 TransactionData,
25};
26use crate::{BlsScalar, Error};
27
28#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
30#[archive_attr(derive(CheckBytes))]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct AccountData {
33 #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
35 pub nonce: u64,
36 #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
38 pub balance: u64,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
43#[archive_attr(derive(CheckBytes))]
44pub struct Transaction {
45 payload: Payload,
46 signature: AccountSignature,
47}
48
49impl Transaction {
50 #[allow(clippy::too_many_arguments)]
56 pub fn new(
57 sender_sk: &AccountSecretKey,
58 receiver: Option<AccountPublicKey>,
59 value: u64,
60 deposit: u64,
61 gas_limit: u64,
62 gas_price: u64,
63 nonce: u64,
64 chain_id: u8,
65 data: Option<impl Into<TransactionData>>,
66 ) -> Result<Self, Error> {
67 let refund_address = AccountPublicKey::from(sender_sk);
68
69 Self::new_with_refund(
70 sender_sk,
71 &refund_address,
72 receiver,
73 value,
74 deposit,
75 gas_limit,
76 gas_price,
77 nonce,
78 chain_id,
79 data,
80 )
81 }
82
83 #[allow(clippy::too_many_arguments)]
90 pub fn new_with_refund(
91 sender_sk: &AccountSecretKey,
92 refund_pk: &AccountPublicKey,
93 receiver: Option<AccountPublicKey>,
94 value: u64,
95 deposit: u64,
96 gas_limit: u64,
97 gas_price: u64,
98 nonce: u64,
99 chain_id: u8,
100 data: Option<impl Into<TransactionData>>,
101 ) -> Result<Self, Error> {
102 let data = data.map(Into::into);
103 let sender = AccountPublicKey::from(sender_sk);
104 let receiver = receiver.unwrap_or(sender);
105
106 let fee = Fee {
107 gas_limit,
108 gas_price,
109 refund_address: *refund_pk,
110 };
111
112 let payload = Payload {
113 chain_id,
114 sender,
115 receiver,
116 value,
117 deposit,
118 fee,
119 nonce,
120 data,
121 };
122
123 Self::sign_payload(sender_sk, payload)
124 }
125
126 pub fn sign_payload(
137 sender_sk: &AccountSecretKey,
138 payload: Payload,
139 ) -> Result<Self, Error> {
140 if let Some(TransactionData::Memo(memo)) = payload.data.as_ref() {
141 if memo.len() > MAX_MEMO_SIZE {
142 return Err(Error::MemoTooLarge(memo.len()));
143 }
144 }
145
146 let digest = payload.signature_message();
147 let signature = sender_sk.sign(&digest);
148
149 Ok(Self { payload, signature })
150 }
151
152 #[must_use]
154 pub fn signature(&self) -> &AccountSignature {
155 &self.signature
156 }
157
158 #[must_use]
160 pub fn sender(&self) -> &AccountPublicKey {
161 &self.payload.sender
162 }
163
164 #[must_use]
166 pub fn refund_address(&self) -> &AccountPublicKey {
167 &self.payload.fee.refund_address
168 }
169
170 #[must_use]
173 pub fn receiver(&self) -> Option<&AccountPublicKey> {
174 if self.payload.sender == self.payload.receiver {
175 None
176 } else {
177 Some(&self.payload.receiver)
178 }
179 }
180
181 #[must_use]
183 pub fn value(&self) -> u64 {
184 self.payload.value
185 }
186
187 #[must_use]
189 pub fn deposit(&self) -> u64 {
190 self.payload.deposit
191 }
192
193 #[must_use]
195 pub fn gas_limit(&self) -> u64 {
196 self.payload.fee.gas_limit
197 }
198
199 #[must_use]
201 pub fn gas_price(&self) -> u64 {
202 self.payload.fee.gas_price
203 }
204
205 #[must_use]
207 pub fn nonce(&self) -> u64 {
208 self.payload.nonce
209 }
210
211 #[must_use]
213 pub fn chain_id(&self) -> u8 {
214 self.payload.chain_id
215 }
216
217 #[must_use]
219 pub fn call(&self) -> Option<&ContractCall> {
220 #[allow(clippy::match_wildcard_for_single_variants)]
221 match self.data()? {
222 TransactionData::Call(c) => Some(c),
223 _ => None,
224 }
225 }
226
227 #[must_use]
229 pub fn deploy(&self) -> Option<&ContractDeploy> {
230 #[allow(clippy::match_wildcard_for_single_variants)]
231 match self.data()? {
232 TransactionData::Deploy(d) => Some(d),
233 _ => None,
234 }
235 }
236
237 #[must_use]
239 pub fn memo(&self) -> Option<&[u8]> {
240 match self.data()? {
241 TransactionData::Memo(memo) => Some(memo),
242 _ => None,
243 }
244 }
245
246 #[must_use]
248 pub fn blob(&self) -> Option<&Vec<BlobData>> {
249 #[allow(clippy::match_wildcard_for_single_variants)]
250 match self.data()? {
251 TransactionData::Blob(d) => Some(d),
252 _ => None,
253 }
254 }
255
256 #[must_use]
258 pub fn blob_mut(&mut self) -> Option<&mut Vec<BlobData>> {
259 #[allow(clippy::match_wildcard_for_single_variants)]
260 match self.data_mut()? {
261 TransactionData::Blob(d) => Some(d),
262 _ => None,
263 }
264 }
265
266 #[must_use]
268 pub fn data(&self) -> Option<&TransactionData> {
269 self.payload.data.as_ref()
270 }
271
272 #[must_use]
274 pub(crate) fn data_mut(&mut self) -> Option<&mut TransactionData> {
275 self.payload.data.as_mut()
276 }
277
278 #[must_use]
282 pub fn strip_off_bytecode(&self) -> Option<Self> {
283 let deploy = self.deploy()?;
284
285 let stripped_deploy = TransactionData::Deploy(ContractDeploy {
286 owner: deploy.owner.clone(),
287 init_args: deploy.init_args.clone(),
288 bytecode: ContractBytecode {
289 hash: deploy.bytecode.hash,
290 bytes: Vec::new(),
291 },
292 nonce: deploy.nonce,
293 });
294
295 let mut stripped_transaction = self.clone();
296 stripped_transaction.payload.data = Some(stripped_deploy);
297
298 Some(stripped_transaction)
299 }
300
301 #[must_use]
307 pub fn blob_to_memo(&self) -> Option<Self> {
308 let data = self.data()?;
309
310 if let TransactionData::Blob(_) = data {
311 let hash = data.signature_message();
312 let memo = TransactionData::Memo(hash);
313 let mut converted_tx = self.clone();
314 converted_tx.payload.data = Some(memo);
315 Some(converted_tx)
316 } else {
317 None
318 }
319 }
320
321 #[must_use]
323 pub fn to_var_bytes(&self) -> Vec<u8> {
324 let mut bytes = Vec::new();
325
326 let payload_bytes = self.payload.to_var_bytes();
327 bytes.extend((payload_bytes.len() as u64).to_bytes());
328 bytes.extend(payload_bytes);
329
330 bytes.extend(self.signature.to_bytes());
331
332 bytes
333 }
334
335 pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
340 let mut buf = buf;
341
342 let payload_len = usize::try_from(u64::from_reader(&mut buf)?)
343 .map_err(|_| BytesError::InvalidData)?;
344
345 if buf.len() < payload_len {
346 return Err(BytesError::InvalidData);
347 }
348 let (payload_buf, new_buf) = buf.split_at(payload_len);
349
350 let payload = Payload::from_slice(payload_buf)?;
351 buf = new_buf;
352
353 let signature = AccountSignature::from_bytes(
354 buf.try_into().map_err(|_| BytesError::InvalidData)?,
355 )
356 .map_err(|_| BytesError::InvalidData)?;
357
358 Ok(Self { payload, signature })
359 }
360
361 #[must_use]
366 pub fn to_hash_input_bytes(&self) -> Vec<u8> {
367 let mut bytes = self.payload.signature_message();
368 bytes.extend(self.signature.to_bytes());
369 bytes
370 }
371
372 #[must_use]
375 pub fn signature_message(&self) -> Vec<u8> {
376 self.payload.signature_message()
377 }
378
379 #[must_use]
381 pub fn hash(&self) -> BlsScalar {
382 BlsScalar::hash_to_scalar(&self.to_hash_input_bytes())
383 }
384}
385
386#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
388#[archive_attr(derive(CheckBytes))]
389pub struct Payload {
390 pub chain_id: u8,
392 pub sender: AccountPublicKey,
394 pub receiver: AccountPublicKey,
396 pub value: u64,
398 pub deposit: u64,
400 pub fee: Fee,
402 pub nonce: u64,
408 pub data: Option<TransactionData>,
410}
411
412impl Payload {
413 #[must_use]
415 pub fn to_var_bytes(&self) -> Vec<u8> {
416 let mut bytes = Vec::from([self.chain_id]);
417
418 bytes.extend(self.sender.to_bytes());
419 if self.sender == self.receiver {
422 bytes.push(0);
423 } else {
424 bytes.push(1);
425 bytes.extend(self.receiver.to_bytes());
426 }
427
428 bytes.extend(self.value.to_bytes());
429 bytes.extend(self.deposit.to_bytes());
430
431 bytes.extend(self.fee.gas_limit.to_bytes());
433 bytes.extend(self.fee.gas_price.to_bytes());
434 if self.sender == self.fee.refund_address {
437 bytes.push(0);
438 } else {
439 bytes.push(1);
440 bytes.extend(self.fee.refund_address.to_bytes());
441 }
442
443 bytes.extend(self.nonce.to_bytes());
444
445 bytes.extend(TransactionData::option_to_var_bytes(self.data.as_ref()));
447
448 bytes
449 }
450
451 pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
456 let mut buf = buf;
457
458 let chain_id = u8::from_reader(&mut buf)?;
459 let sender = AccountPublicKey::from_reader(&mut buf)?;
460 let receiver = match u8::from_reader(&mut buf)? {
461 0 => sender,
462 1 => AccountPublicKey::from_reader(&mut buf)?,
463 _ => {
464 return Err(BytesError::InvalidData);
465 }
466 };
467 let value = u64::from_reader(&mut buf)?;
468 let deposit = u64::from_reader(&mut buf)?;
469
470 let gas_limit = u64::from_reader(&mut buf)?;
472 let gas_price = u64::from_reader(&mut buf)?;
473 let refund_address = match u8::from_reader(&mut buf)? {
474 0 => sender,
475 1 => AccountPublicKey::from_reader(&mut buf)?,
476 _ => {
477 return Err(BytesError::InvalidData);
478 }
479 };
480 let fee = Fee {
481 gas_limit,
482 gas_price,
483 refund_address,
484 };
485
486 let nonce = u64::from_reader(&mut buf)?;
487
488 let data = TransactionData::from_slice(buf)?;
490
491 Ok(Self {
492 chain_id,
493 sender,
494 receiver,
495 value,
496 deposit,
497 fee,
498 nonce,
499 data,
500 })
501 }
502
503 #[must_use]
508 pub fn signature_message(&self) -> Vec<u8> {
509 let mut bytes = Vec::from([self.chain_id]);
510
511 bytes.extend(self.sender.to_bytes());
512 if self.receiver != self.sender {
513 bytes.extend(self.receiver.to_bytes());
514 }
515 bytes.extend(self.value.to_bytes());
516 bytes.extend(self.deposit.to_bytes());
517 bytes.extend(self.fee.gas_limit.to_bytes());
518 bytes.extend(self.fee.gas_price.to_bytes());
519 if self.fee.refund_address != self.sender {
520 bytes.extend(self.fee.refund_address.to_bytes());
521 }
522 bytes.extend(self.nonce.to_bytes());
523
524 if let Some(data) = &self.data {
525 bytes.extend(data.signature_message());
526 }
527
528 bytes
529 }
530}
531
532#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
534#[archive_attr(derive(CheckBytes))]
535pub struct Fee {
536 pub gas_limit: u64,
538 pub gas_price: u64,
540 pub refund_address: AccountPublicKey,
542}