1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
use alloc::borrow::Cow;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::models::Amount;
/// Server information
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Info<'a> {
/// If true, this server is amendment blocked
pub amendment_blocked: Option<bool>,
/// The version number of the running rippled server
pub build_version: Cow<'a, str>,
/// Information about the most recently closed ledger that has not been
/// validated
pub closed_ledger: Option<LedgerInfo<'a>>,
/// Range expression indicating the sequence numbers of the ledger versions
/// in the database
pub complete_ledgers: Cow<'a, str>,
/// Performance metrics for RPC calls and JobQueue
pub counters: Option<Value>,
/// Items currently being run in the job queue
pub current_activity: Option<Value>,
/// Server hostname or RFC-1751 word based on node public key
pub hostid: Option<Cow<'a, str>>,
/// Amount of time spent waiting for I/O operations, in milliseconds
pub io_latency_ms: u32,
/// Number of times server had over 250 transactions waiting
pub jq_trans_overflow: Option<Cow<'a, str>>,
/// Information about the last ledger close
pub last_close: LastClose,
/// Detailed information about the current load state
pub load: Option<Load<'a>>,
/// Current transaction cost multiplier
pub load_factor: u32,
/// Transaction cost multiplier based on local load
pub load_factor_local: Option<u32>,
/// Transaction cost multiplier from network load
pub load_factor_net: Option<u32>,
/// Transaction cost multiplier from cluster load
pub load_factor_cluster: Option<u32>,
/// Transaction cost multiplier for open ledger
pub load_factor_fee_escalation: Option<u32>,
/// Transaction cost multiplier for queue
pub load_factor_fee_queue: Option<u32>,
/// Transaction cost multiplier excluding open ledger
pub load_factor_server: Option<u32>,
/// Network id for ledger
pub network_id: Option<u32>,
/// Number of connected peer servers
pub peers: u32,
/// List of ports listening for API commands
pub ports: Option<Cow<'a, [Value]>>,
/// Public key for peer-to-peer communications
pub pubkey_node: Cow<'a, str>,
/// Public key for ledger validations
pub pubkey_validator: Option<Cow<'a, str>>,
/// Reporting mode configuration information
pub reporting: Option<Reporting<'a>>,
/// Current server state
pub server_state: Cow<'a, str>,
/// Microseconds in current state
pub server_state_duration_us: Option<Cow<'a, str>>,
/// Server state accounting information
pub state_accounting: Option<Value>,
/// Current UTC time according to server
pub time: Option<Cow<'a, str>>,
/// Seconds server has been operational
pub uptime: Option<u64>,
/// Information about the most recent validated ledger
pub validated_ledger: Option<LedgerInfo<'a>>,
/// Minimum required trusted validations
pub validation_quorum: u32,
/// Validator list expiration time
pub validator_list_expires: Option<u32>,
/// Validator list information
pub validator_list: Option<ValidatorList<'a>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct ValidatorList<'a> {
pub count: u32,
pub expiration: u32,
pub status: Cow<'a, str>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct LastClose {
/// Time to reach consensus in seconds
pub converge_time_s: u64,
/// Number of trusted validators considered
pub proposers: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Load<'a> {
/// Information about job types and time spent
pub job_types: Cow<'a, [Value]>,
/// Number of threads in main job pool
pub threads: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Reporting<'a> {
/// List of P2P-mode servers
pub etl_sources: Cow<'a, [Value]>,
/// Whether server is writing to external database
pub is_writer: bool,
/// Last publish time
pub last_publish_time: Cow<'a, str>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct LedgerInfo<'a> {
/// Time since ledger close in seconds
pub age: Option<u32>,
/// Base fee in XRP (Not drops for some reason?)
pub base_fee_xrp: Option<Amount<'a>>,
/// Unique ledger hash
pub hash: Cow<'a, str>,
/// Minimum XRP reserve for accounts (Not drops for some reason?)
pub reserve_base_xrp: Option<Amount<'a>>,
/// Additional XRP reserve per owned object (Not drops for some reason?)
pub reserve_inc_xrp: Option<Amount<'a>>,
/// Ledger sequence number
pub seq: u32,
}
/// Response format for the server_info command, which returns various
/// information about the rippled server's current state and configuration.
///
/// See Server Info:
/// `<https://xrpl.org/server_info.html#server_info>`
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct ServerInfo<'a> {
pub info: Info<'a>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_server_info_deserialize() {
let json = r#"{
"info": {
"build_version": "1.12.0",
"complete_ledgers": "32570-82521761",
"hostid": "LEST",
"io_latency_ms": 1,
"jq_trans_overflow": "0",
"last_close": {
"converge_time_s": 3,
"proposers": 35
},
"load_factor": 1,
"network_id": 10,
"peers": 22,
"ports": [
{
"port": "7777",
"protocol": ["ws"]
},
{
"port": "8080",
"protocol": ["ws"]
},
{
"port": "80",
"protocol": ["http"]
},
{
"port": "51235",
"protocol": ["peer"]
}
],
"pubkey_node": "n9KQK8yvTDcZdGyhu2EGdDnFPEBSsY5wEGpU5GgpygTgLFsjQyPt",
"server_state": "full",
"server_state_duration_us": "91758491912",
"time": "2023-Sep-13 22:12:31.377492 UTC",
"uptime": 91948,
"validated_ledger": {
"age": 1,
"base_fee_xrp": 0.00001,
"hash": "6872A6612DCEBCFC717FEBC66EB8CC2A4D5EEB2B0F15FC3DCD060049FCA47F31",
"reserve_base_xrp": 10,
"reserve_inc_xrp": 2,
"seq": 82521761
},
"validation_quorum": 28
},
"status": "success"
}"#;
let result: ServerInfo = serde_json::from_str(json).unwrap();
assert_eq!(result.info.build_version, "1.12.0");
assert_eq!(result.info.complete_ledgers, "32570-82521761");
assert_eq!(result.info.hostid, Some("LEST".into()));
assert_eq!(result.info.io_latency_ms, 1);
assert_eq!(result.info.jq_trans_overflow, Some("0".into()));
assert_eq!(result.info.last_close.converge_time_s, 3);
assert_eq!(result.info.last_close.proposers, 35);
assert_eq!(result.info.load_factor, 1);
assert_eq!(result.info.network_id, Some(10));
assert_eq!(result.info.peers, 22);
assert_eq!(
result.info.pubkey_node,
"n9KQK8yvTDcZdGyhu2EGdDnFPEBSsY5wEGpU5GgpygTgLFsjQyPt"
);
assert_eq!(result.info.server_state, "full");
assert_eq!(
result.info.server_state_duration_us,
Some("91758491912".into())
);
assert_eq!(
result.info.time,
Some("2023-Sep-13 22:12:31.377492 UTC".into())
);
assert_eq!(result.info.uptime, Some(91948));
let validated_ledger = result.info.validated_ledger.unwrap();
assert_eq!(validated_ledger.age, Some(1));
assert_eq!(
validated_ledger.base_fee_xrp,
Some(Amount::XRPAmount(0.00001.into()))
);
assert_eq!(
validated_ledger.hash,
"6872A6612DCEBCFC717FEBC66EB8CC2A4D5EEB2B0F15FC3DCD060049FCA47F31"
);
assert_eq!(
validated_ledger.reserve_base_xrp,
Some(Amount::XRPAmount(10.into()))
);
assert_eq!(
validated_ledger.reserve_inc_xrp,
Some(Amount::XRPAmount(2.into()))
);
assert_eq!(validated_ledger.seq, 82521761);
assert_eq!(result.info.validation_quorum, 28);
}
}