1use crate::{BlockNumber, Capacity, Cycle, Timestamp, TransactionView, Uint64};
2use ckb_types::H256;
3use ckb_types::core::tx_pool::{
4 AncestorsScoreSortKey as CoreAncestorsScoreSortKey,
5 PoolTransactionEntry as CorePoolTransactionEntry, PoolTxDetailInfo as CorePoolTxDetailInfo,
6 Reject, TxEntryInfo, TxPoolEntryInfo, TxPoolIds as CoreTxPoolIds, TxPoolInfo as CoreTxPoolInfo,
7};
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
14pub struct TxPoolInfo {
15 pub tip_hash: H256,
20 pub tip_number: BlockNumber,
22 pub pending: Uint64,
26 pub proposed: Uint64,
31 pub orphan: Uint64,
36 pub total_tx_size: Uint64,
38 pub total_tx_cycles: Uint64,
40 pub min_fee_rate: Uint64,
44 pub min_rbf_rate: Uint64,
51 pub last_txs_updated_at: Timestamp,
53 pub tx_size_limit: Uint64,
59 pub max_tx_pool_size: Uint64,
61
62 pub verify_queue_size: Uint64,
64}
65
66impl From<CoreTxPoolInfo> for TxPoolInfo {
67 fn from(tx_pool_info: CoreTxPoolInfo) -> Self {
68 TxPoolInfo {
69 tip_hash: tx_pool_info.tip_hash.into(),
70 tip_number: tx_pool_info.tip_number.into(),
71 pending: (tx_pool_info.pending_size as u64).into(),
72 proposed: (tx_pool_info.proposed_size as u64).into(),
73 orphan: (tx_pool_info.orphan_size as u64).into(),
74 total_tx_size: (tx_pool_info.total_tx_size as u64).into(),
75 total_tx_cycles: tx_pool_info.total_tx_cycles.into(),
76 min_fee_rate: tx_pool_info.min_fee_rate.as_u64().into(),
77 min_rbf_rate: tx_pool_info.min_rbf_rate.as_u64().into(),
78 last_txs_updated_at: tx_pool_info.last_txs_updated_at.into(),
79 tx_size_limit: tx_pool_info.tx_size_limit.into(),
80 max_tx_pool_size: tx_pool_info.max_tx_pool_size.into(),
81 verify_queue_size: (tx_pool_info.verify_queue_size as u64).into(),
82 }
83 }
84}
85
86#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]
88pub struct PoolTransactionEntry {
89 pub transaction: TransactionView,
91 pub cycles: Cycle,
93 pub size: Uint64,
95 pub fee: Capacity,
97 pub timestamp: Uint64,
99}
100
101impl From<CorePoolTransactionEntry> for PoolTransactionEntry {
102 fn from(entry: CorePoolTransactionEntry) -> Self {
103 PoolTransactionEntry {
104 transaction: entry.transaction.into(),
105 cycles: entry.cycles.into(),
106 size: (entry.size as u64).into(),
107 fee: entry.fee.into(),
108 timestamp: entry.timestamp.into(),
109 }
110 }
111}
112
113#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
115#[serde(rename_all = "snake_case")]
116pub enum OutputsValidator {
117 Passthrough,
119 WellKnownScriptsOnly,
121}
122
123impl OutputsValidator {
124 pub fn json_display(&self) -> String {
126 let v = serde_json::to_value(self).expect("OutputsValidator to JSON should never fail");
127 v.as_str().unwrap_or_default().to_string()
128 }
129}
130
131#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
133pub struct TxPoolIds {
134 pub pending: Vec<H256>,
136 pub proposed: Vec<H256>,
138}
139
140impl From<CoreTxPoolIds> for TxPoolIds {
141 fn from(ids: CoreTxPoolIds) -> Self {
142 let CoreTxPoolIds { pending, proposed } = ids;
143 TxPoolIds {
144 pending: pending.iter().map(Into::into).collect(),
145 proposed: proposed.iter().map(Into::into).collect(),
146 }
147 }
148}
149
150#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
152pub struct TxPoolEntry {
153 pub cycles: Uint64,
155 pub size: Uint64,
157 pub fee: Capacity,
159 pub ancestors_size: Uint64,
161 pub ancestors_cycles: Uint64,
163 pub ancestors_count: Uint64,
165 pub timestamp: Uint64,
167}
168
169impl From<TxEntryInfo> for TxPoolEntry {
170 fn from(info: TxEntryInfo) -> Self {
171 TxPoolEntry {
172 cycles: info.cycles.into(),
173 size: info.size.into(),
174 fee: info.fee.into(),
175 ancestors_size: info.ancestors_size.into(),
176 ancestors_cycles: info.ancestors_cycles.into(),
177 ancestors_count: info.ancestors_count.into(),
178 timestamp: info.timestamp.into(),
179 }
180 }
181}
182
183#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
185pub struct TxPoolEntries {
186 pub pending: HashMap<H256, TxPoolEntry>,
188 pub proposed: HashMap<H256, TxPoolEntry>,
190 pub conflicted: Vec<H256>,
192}
193
194impl From<TxPoolEntryInfo> for TxPoolEntries {
195 fn from(info: TxPoolEntryInfo) -> Self {
196 let TxPoolEntryInfo {
197 pending,
198 proposed,
199 conflicted,
200 } = info;
201
202 TxPoolEntries {
203 pending: pending
204 .into_iter()
205 .map(|(hash, entry)| (hash.into(), entry.into()))
206 .collect(),
207 proposed: proposed
208 .into_iter()
209 .map(|(hash, entry)| (hash.into(), entry.into()))
210 .collect(),
211 conflicted: conflicted.iter().map(Into::into).collect(),
212 }
213 }
214}
215
216#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
223#[serde(untagged)]
224pub enum RawTxPool {
225 Ids(TxPoolIds),
227 Verbose(TxPoolEntries),
229}
230
231#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
233pub struct AncestorsScoreSortKey {
234 pub fee: Uint64,
236 pub weight: Uint64,
238 pub ancestors_fee: Uint64,
240 pub ancestors_weight: Uint64,
242}
243
244impl From<CoreAncestorsScoreSortKey> for AncestorsScoreSortKey {
245 fn from(value: CoreAncestorsScoreSortKey) -> Self {
246 Self {
247 fee: value.fee.into(),
248 weight: value.weight.into(),
249 ancestors_fee: value.ancestors_fee.into(),
250 ancestors_weight: value.ancestors_weight.into(),
251 }
252 }
253}
254
255#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
257pub struct PoolTxDetailInfo {
258 pub timestamp: Uint64,
260 pub entry_status: String,
262 pub rank_in_pending: Uint64,
264 pub pending_count: Uint64,
266 pub proposed_count: Uint64,
268 pub descendants_count: Uint64,
270 pub ancestors_count: Uint64,
272 pub score_sortkey: AncestorsScoreSortKey,
274}
275
276impl From<CorePoolTxDetailInfo> for PoolTxDetailInfo {
277 fn from(info: CorePoolTxDetailInfo) -> Self {
278 Self {
279 timestamp: info.timestamp.into(),
280 entry_status: info.entry_status,
281 rank_in_pending: (info.rank_in_pending as u64).into(),
282 pending_count: (info.pending_count as u64).into(),
283 proposed_count: (info.proposed_count as u64).into(),
284 descendants_count: (info.descendants_count as u64).into(),
285 ancestors_count: (info.ancestors_count as u64).into(),
286 score_sortkey: info.score_sortkey.into(),
287 }
288 }
289}
290
291#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
295#[serde(tag = "type", content = "description")]
296pub enum PoolTransactionReject {
297 LowFeeRate(String),
299
300 ExceededMaximumAncestorsCount(String),
302
303 ExceededTransactionSizeLimit(String),
305
306 Full(String),
308
309 Duplicated(String),
311
312 Malformed(String),
314
315 DeclaredWrongCycles(String),
317
318 Resolve(String),
320
321 Verification(String),
323
324 Expiry(String),
326
327 RBFRejected(String),
329
330 Invalidated(String),
332}
333
334impl From<Reject> for PoolTransactionReject {
335 fn from(reject: Reject) -> Self {
336 match reject {
337 Reject::LowFeeRate(..) => Self::LowFeeRate(format!("{reject}")),
338 Reject::ExceededMaximumAncestorsCount => {
339 Self::ExceededMaximumAncestorsCount(format!("{reject}"))
340 }
341 Reject::ExceededTransactionSizeLimit(..) => {
342 Self::ExceededTransactionSizeLimit(format!("{reject}"))
343 }
344 Reject::Full(..) => Self::Full(format!("{reject}")),
345 Reject::Duplicated(_) => Self::Duplicated(format!("{reject}")),
346 Reject::Malformed(_, _) => Self::Malformed(format!("{reject}")),
347 Reject::DeclaredWrongCycles(..) => Self::DeclaredWrongCycles(format!("{reject}")),
348 Reject::Resolve(_) => Self::Resolve(format!("{reject}")),
349 Reject::Verification(_) => Self::Verification(format!("{reject}")),
350 Reject::Expiry(_) => Self::Expiry(format!("{reject}")),
351 Reject::RBFRejected(_) => Self::RBFRejected(format!("{reject}")),
352 Reject::Invalidated(_) => Self::Invalidated(format!("{reject}")),
353 }
354 }
355}
356
357#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
359pub struct EntryCompleted {
360 pub cycles: Cycle,
362 pub fee: Capacity,
364}
365
366impl From<ckb_types::core::EntryCompleted> for EntryCompleted {
367 fn from(value: ckb_types::core::EntryCompleted) -> Self {
368 Self {
369 cycles: value.cycles.into(),
370 fee: value.fee.into(),
371 }
372 }
373}