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