openzeppelin_monitor/models/blockchain/stellar/
block.rs

1//! Stellar block (ledger) data structures.
2//!
3//! Note: These structures are based on the Stellar RPC implementation:
4//! <https://github.com/stellar/stellar-rpc/blob/main/cmd/stellar-rpc/internal/methods/get_ledgers.go>
5
6use std::ops::Deref;
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11/// Information about a Stellar ledger (block)
12///
13/// This structure represents the response from the Stellar RPC endpoint
14/// and matches the format defined in the stellar-rpc repository.
15#[derive(Debug, Serialize, Deserialize, Clone, Default)]
16pub struct LedgerInfo {
17	/// Hash of the ledger
18	#[serde(rename = "hash")]
19	pub hash: String,
20
21	/// Sequence number of the ledger
22	#[serde(rename = "sequence")]
23	pub sequence: u32,
24
25	/// Timestamp when the ledger was closed
26	#[serde(rename = "ledgerCloseTime")]
27	pub ledger_close_time: String,
28
29	/// Base64-encoded XDR of the ledger header
30	#[serde(rename = "headerXdr")]
31	pub ledger_header: String,
32
33	/// Decoded JSON representation of the ledger header
34	#[serde(rename = "headerJson")]
35	#[serde(skip_serializing_if = "Option::is_none")]
36	pub ledger_header_json: Option<Value>,
37
38	/// Base64-encoded XDR of the ledger metadata
39	#[serde(rename = "metadataXdr")]
40	pub ledger_metadata: String,
41
42	/// Decoded JSON representation of the ledger metadata
43	#[serde(rename = "metadataJSON")]
44	#[serde(skip_serializing_if = "Option::is_none")]
45	pub ledger_metadata_json: Option<Value>,
46}
47
48/// Wrapper around LedgerInfo that implements additional functionality
49///
50/// This type provides a convenient interface for working with Stellar ledger data
51/// while maintaining compatibility with the RPC response format.
52#[derive(Debug, Serialize, Deserialize, Clone, Default)]
53pub struct Block(pub LedgerInfo);
54
55impl Block {
56	/// Get the block number (sequence)
57	pub fn number(&self) -> Option<u64> {
58		Some(self.0.sequence as u64)
59	}
60}
61
62impl From<LedgerInfo> for Block {
63	fn from(header: LedgerInfo) -> Self {
64		Self(header)
65	}
66}
67
68impl Deref for Block {
69	type Target = LedgerInfo;
70
71	fn deref(&self) -> &Self::Target {
72		&self.0
73	}
74}
75
76#[cfg(test)]
77mod tests {
78	use super::*;
79	use serde_json::json;
80
81	#[test]
82	fn test_block_creation_and_number() {
83		let ledger_info = LedgerInfo {
84			hash: "abc123".to_string(),
85			sequence: 12345,
86			ledger_close_time: "2024-03-20T10:00:00Z".to_string(),
87			ledger_header: "base64header".to_string(),
88			ledger_header_json: Some(json!({"version": 1})),
89			ledger_metadata: "base64metadata".to_string(),
90			ledger_metadata_json: Some(json!({"operations": []})),
91		};
92
93		let block = Block::from(ledger_info.clone());
94
95		// Test number() method
96		assert_eq!(block.number(), Some(12345u64));
97
98		// Test Deref implementation
99		assert_eq!(block.hash, "abc123");
100		assert_eq!(block.sequence, 12345);
101		assert_eq!(block.ledger_close_time, "2024-03-20T10:00:00Z");
102		assert_eq!(block.ledger_header, "base64header");
103		assert_eq!(block.ledger_metadata, "base64metadata");
104	}
105
106	#[test]
107	fn test_default_implementation() {
108		let block = Block::default();
109
110		assert_eq!(block.hash, "");
111		assert_eq!(block.sequence, 0);
112		assert_eq!(block.ledger_close_time, "");
113		assert_eq!(block.ledger_header, "");
114		assert_eq!(block.ledger_metadata, "");
115		assert!(block.ledger_header_json.is_none());
116		assert!(block.ledger_metadata_json.is_none());
117	}
118
119	#[test]
120	fn test_serde_serialization() {
121		let ledger_info = LedgerInfo {
122			hash: "abc123".to_string(),
123			sequence: 12345,
124			ledger_close_time: "2024-03-20T10:00:00Z".to_string(),
125			ledger_header: "base64header".to_string(),
126			ledger_header_json: Some(json!({"version": 1})),
127			ledger_metadata: "base64metadata".to_string(),
128			ledger_metadata_json: Some(json!({"operations": []})),
129		};
130
131		let block = Block(ledger_info);
132
133		// Test serialization
134		let serialized = serde_json::to_string(&block).unwrap();
135
136		// Test deserialization
137		let deserialized: Block = serde_json::from_str(&serialized).unwrap();
138
139		assert_eq!(deserialized.hash, "abc123");
140		assert_eq!(deserialized.sequence, 12345);
141		assert_eq!(deserialized.number(), Some(12345u64));
142	}
143}