saorsa_node/payment/
proof.rs1use ant_evm::ProofOfPayment;
7use evmlib::common::TxHash;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct PaymentProof {
16 pub proof_of_payment: ProofOfPayment,
18 pub tx_hashes: Vec<TxHash>,
21}
22
23pub fn deserialize_proof(
31 bytes: &[u8],
32) -> std::result::Result<(ProofOfPayment, Vec<TxHash>), rmp_serde::decode::Error> {
33 let proof = rmp_serde::from_slice::<PaymentProof>(bytes)?;
34 Ok((proof.proof_of_payment, proof.tx_hashes))
35}
36
37#[cfg(test)]
38#[allow(clippy::unwrap_used, clippy::expect_used)]
39mod tests {
40 use super::*;
41 use alloy::primitives::FixedBytes;
42 use ant_evm::RewardsAddress;
43 use ant_evm::{EncodedPeerId, PaymentQuote};
44 use evmlib::quoting_metrics::QuotingMetrics;
45 use libp2p::identity::Keypair;
46 use libp2p::PeerId;
47 use std::time::SystemTime;
48 use xor_name::XorName;
49
50 fn make_test_quote() -> PaymentQuote {
51 PaymentQuote {
52 content: XorName::random(&mut rand::thread_rng()),
53 timestamp: SystemTime::now(),
54 quoting_metrics: QuotingMetrics {
55 data_size: 1024,
56 data_type: 0,
57 close_records_stored: 0,
58 records_per_type: vec![],
59 max_records: 1000,
60 received_payment_count: 0,
61 live_time: 0,
62 network_density: None,
63 network_size: None,
64 },
65 rewards_address: RewardsAddress::new([1u8; 20]),
66 pub_key: vec![],
67 signature: vec![],
68 }
69 }
70
71 fn make_proof_of_payment() -> ProofOfPayment {
72 let keypair = Keypair::generate_ed25519();
73 let peer_id = PeerId::from_public_key(&keypair.public());
74 ProofOfPayment {
75 peer_quotes: vec![(EncodedPeerId::from(peer_id), make_test_quote())],
76 }
77 }
78
79 #[test]
80 fn test_payment_proof_serialization_roundtrip() {
81 let tx_hash = FixedBytes::from([0xABu8; 32]);
82 let proof = PaymentProof {
83 proof_of_payment: make_proof_of_payment(),
84 tx_hashes: vec![tx_hash],
85 };
86
87 let bytes = rmp_serde::to_vec(&proof).unwrap();
88 let (pop, hashes) = deserialize_proof(&bytes).unwrap();
89
90 assert_eq!(pop.peer_quotes.len(), 1);
91 assert_eq!(hashes.len(), 1);
92 assert_eq!(hashes.first().unwrap(), &tx_hash);
93 }
94
95 #[test]
96 fn test_payment_proof_with_empty_tx_hashes() {
97 let proof = PaymentProof {
98 proof_of_payment: make_proof_of_payment(),
99 tx_hashes: vec![],
100 };
101
102 let bytes = rmp_serde::to_vec(&proof).unwrap();
103 let (pop, hashes) = deserialize_proof(&bytes).unwrap();
104
105 assert_eq!(pop.peer_quotes.len(), 1);
106 assert!(hashes.is_empty());
107 }
108
109 #[test]
110 fn test_deserialize_proof_rejects_garbage() {
111 let garbage = vec![0xFF, 0x00, 0x01, 0x02];
112 let result = deserialize_proof(&garbage);
113 assert!(result.is_err());
114 }
115
116 #[test]
117 fn test_payment_proof_multiple_tx_hashes() {
118 let tx1 = FixedBytes::from([0x11u8; 32]);
119 let tx2 = FixedBytes::from([0x22u8; 32]);
120 let proof = PaymentProof {
121 proof_of_payment: make_proof_of_payment(),
122 tx_hashes: vec![tx1, tx2],
123 };
124
125 let bytes = rmp_serde::to_vec(&proof).unwrap();
126 let (_, hashes) = deserialize_proof(&bytes).unwrap();
127
128 assert_eq!(hashes.len(), 2);
129 assert_eq!(hashes.first().unwrap(), &tx1);
130 assert_eq!(hashes.get(1).unwrap(), &tx2);
131 }
132}