use crate::{BlockNumber, Capacity, Cycle, Timestamp, TransactionView, Uint64};
use ckb_types::core::service::PoolTransactionEntry as CorePoolTransactionEntry;
use ckb_types::core::tx_pool::{
AncestorsScoreSortKey as CoreAncestorsScoreSortKey, PoolTxDetailInfo as CorePoolTxDetailInfo,
Reject, TxEntryInfo, TxPoolEntryInfo, TxPoolIds as CoreTxPoolIds, TxPoolInfo as CoreTxPoolInfo,
};
use ckb_types::prelude::Unpack;
use ckb_types::H256;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
pub struct TxPoolInfo {
pub tip_hash: H256,
pub tip_number: BlockNumber,
pub pending: Uint64,
pub proposed: Uint64,
pub orphan: Uint64,
pub total_tx_size: Uint64,
pub total_tx_cycles: Uint64,
pub min_fee_rate: Uint64,
pub min_rbf_rate: Uint64,
pub last_txs_updated_at: Timestamp,
pub tx_size_limit: Uint64,
pub max_tx_pool_size: Uint64,
pub verify_queue_size: Uint64,
}
impl From<CoreTxPoolInfo> for TxPoolInfo {
fn from(tx_pool_info: CoreTxPoolInfo) -> Self {
TxPoolInfo {
tip_hash: tx_pool_info.tip_hash.unpack(),
tip_number: tx_pool_info.tip_number.into(),
pending: (tx_pool_info.pending_size as u64).into(),
proposed: (tx_pool_info.proposed_size as u64).into(),
orphan: (tx_pool_info.orphan_size as u64).into(),
total_tx_size: (tx_pool_info.total_tx_size as u64).into(),
total_tx_cycles: tx_pool_info.total_tx_cycles.into(),
min_fee_rate: tx_pool_info.min_fee_rate.as_u64().into(),
min_rbf_rate: tx_pool_info.min_rbf_rate.as_u64().into(),
last_txs_updated_at: tx_pool_info.last_txs_updated_at.into(),
tx_size_limit: tx_pool_info.tx_size_limit.into(),
max_tx_pool_size: tx_pool_info.max_tx_pool_size.into(),
verify_queue_size: (tx_pool_info.verify_queue_size as u64).into(),
}
}
}
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]
pub struct PoolTransactionEntry {
pub transaction: TransactionView,
pub cycles: Cycle,
pub size: Uint64,
pub fee: Capacity,
pub timestamp: Uint64,
}
impl From<CorePoolTransactionEntry> for PoolTransactionEntry {
fn from(entry: CorePoolTransactionEntry) -> Self {
PoolTransactionEntry {
transaction: entry.transaction.into(),
cycles: entry.cycles.into(),
size: (entry.size as u64).into(),
fee: entry.fee.into(),
timestamp: entry.timestamp.into(),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OutputsValidator {
Passthrough,
WellKnownScriptsOnly,
}
impl OutputsValidator {
pub fn json_display(&self) -> String {
let v = serde_json::to_value(self).expect("OutputsValidator to JSON should never fail");
v.as_str().unwrap_or_default().to_string()
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
pub struct TxPoolIds {
pub pending: Vec<H256>,
pub proposed: Vec<H256>,
}
impl From<CoreTxPoolIds> for TxPoolIds {
fn from(ids: CoreTxPoolIds) -> Self {
let CoreTxPoolIds { pending, proposed } = ids;
TxPoolIds {
pending: pending.iter().map(Unpack::unpack).collect(),
proposed: proposed.iter().map(Unpack::unpack).collect(),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
pub struct TxPoolEntry {
pub cycles: Uint64,
pub size: Uint64,
pub fee: Capacity,
pub ancestors_size: Uint64,
pub ancestors_cycles: Uint64,
pub ancestors_count: Uint64,
pub timestamp: Uint64,
}
impl From<TxEntryInfo> for TxPoolEntry {
fn from(info: TxEntryInfo) -> Self {
TxPoolEntry {
cycles: info.cycles.into(),
size: info.size.into(),
fee: info.fee.into(),
ancestors_size: info.ancestors_size.into(),
ancestors_cycles: info.ancestors_cycles.into(),
ancestors_count: info.ancestors_count.into(),
timestamp: info.timestamp.into(),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
pub struct TxPoolEntries {
pub pending: HashMap<H256, TxPoolEntry>,
pub proposed: HashMap<H256, TxPoolEntry>,
pub conflicted: Vec<H256>,
}
impl From<TxPoolEntryInfo> for TxPoolEntries {
fn from(info: TxPoolEntryInfo) -> Self {
let TxPoolEntryInfo {
pending,
proposed,
conflicted,
} = info;
TxPoolEntries {
pending: pending
.into_iter()
.map(|(hash, entry)| (hash.unpack(), entry.into()))
.collect(),
proposed: proposed
.into_iter()
.map(|(hash, entry)| (hash.unpack(), entry.into()))
.collect(),
conflicted: conflicted.iter().map(Unpack::unpack).collect(),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
#[serde(untagged)]
pub enum RawTxPool {
Ids(TxPoolIds),
Verbose(TxPoolEntries),
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
pub struct AncestorsScoreSortKey {
pub fee: Uint64,
pub weight: Uint64,
pub ancestors_fee: Uint64,
pub ancestors_weight: Uint64,
}
impl From<CoreAncestorsScoreSortKey> for AncestorsScoreSortKey {
fn from(value: CoreAncestorsScoreSortKey) -> Self {
Self {
fee: value.fee.into(),
weight: value.weight.into(),
ancestors_fee: value.ancestors_fee.into(),
ancestors_weight: value.ancestors_weight.into(),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug, JsonSchema)]
pub struct PoolTxDetailInfo {
pub timestamp: Uint64,
pub entry_status: String,
pub rank_in_pending: Uint64,
pub pending_count: Uint64,
pub proposed_count: Uint64,
pub descendants_count: Uint64,
pub ancestors_count: Uint64,
pub score_sortkey: AncestorsScoreSortKey,
}
impl From<CorePoolTxDetailInfo> for PoolTxDetailInfo {
fn from(info: CorePoolTxDetailInfo) -> Self {
Self {
timestamp: info.timestamp.into(),
entry_status: info.entry_status,
rank_in_pending: (info.rank_in_pending as u64).into(),
pending_count: (info.pending_count as u64).into(),
proposed_count: (info.proposed_count as u64).into(),
descendants_count: (info.descendants_count as u64).into(),
ancestors_count: (info.ancestors_count as u64).into(),
score_sortkey: info.score_sortkey.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", content = "description")]
pub enum PoolTransactionReject {
LowFeeRate(String),
ExceededMaximumAncestorsCount(String),
ExceededTransactionSizeLimit(String),
Full(String),
Duplicated(String),
Malformed(String),
DeclaredWrongCycles(String),
Resolve(String),
Verification(String),
Expiry(String),
RBFRejected(String),
Invalidated(String),
}
impl From<Reject> for PoolTransactionReject {
fn from(reject: Reject) -> Self {
match reject {
Reject::LowFeeRate(..) => Self::LowFeeRate(format!("{reject}")),
Reject::ExceededMaximumAncestorsCount => {
Self::ExceededMaximumAncestorsCount(format!("{reject}"))
}
Reject::ExceededTransactionSizeLimit(..) => {
Self::ExceededTransactionSizeLimit(format!("{reject}"))
}
Reject::Full(..) => Self::Full(format!("{reject}")),
Reject::Duplicated(_) => Self::Duplicated(format!("{reject}")),
Reject::Malformed(_, _) => Self::Malformed(format!("{reject}")),
Reject::DeclaredWrongCycles(..) => Self::DeclaredWrongCycles(format!("{reject}")),
Reject::Resolve(_) => Self::Resolve(format!("{reject}")),
Reject::Verification(_) => Self::Verification(format!("{reject}")),
Reject::Expiry(_) => Self::Expiry(format!("{reject}")),
Reject::RBFRejected(_) => Self::RBFRejected(format!("{reject}")),
Reject::Invalidated(_) => Self::Invalidated(format!("{reject}")),
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)]
pub struct EntryCompleted {
pub cycles: Cycle,
pub fee: Capacity,
}
impl From<ckb_types::core::EntryCompleted> for EntryCompleted {
fn from(value: ckb_types::core::EntryCompleted) -> Self {
Self {
cycles: value.cycles.into(),
fee: value.fee.into(),
}
}
}