2021-08-17 22:52:42 -07:00
|
|
|
//! Unmined Zcash transaction identifiers and transactions.
|
|
|
|
//!
|
2022-06-02 08:07:35 -07:00
|
|
|
//! Transaction version 5 is uniquely identified by [`WtxId`] when unmined, and
|
|
|
|
//! [`struct@Hash`] in the blockchain. The effects of a v5 transaction
|
|
|
|
//! (spends and outputs) are uniquely identified by the same
|
|
|
|
//! [`struct@Hash`] in both cases.
|
2021-08-18 15:55:24 -07:00
|
|
|
//!
|
2022-06-02 08:07:35 -07:00
|
|
|
//! Transaction versions 1-4 are uniquely identified by legacy
|
|
|
|
//! [`struct@Hash`] transaction IDs, whether they have been mined or not.
|
|
|
|
//! So Zebra, and the Zcash network protocol, don't use witnessed transaction
|
|
|
|
//! IDs for them.
|
2021-08-17 22:52:42 -07:00
|
|
|
//!
|
2022-06-02 08:07:35 -07:00
|
|
|
//! Zebra's [`UnminedTxId`] and [`UnminedTx`] enums provide the correct unique
|
|
|
|
//! ID for unmined transactions. They can be used to handle transactions
|
|
|
|
//! regardless of version, and get the [`WtxId`] or [`struct@Hash`] when
|
|
|
|
//! required.
|
2021-08-17 22:52:42 -07:00
|
|
|
|
2021-09-01 17:06:20 -07:00
|
|
|
use std::{fmt, sync::Arc};
|
2021-08-17 22:52:42 -07:00
|
|
|
|
2021-10-17 18:24:37 -07:00
|
|
|
use crate::{
|
|
|
|
amount::{Amount, NonNegative},
|
|
|
|
serialization::ZcashSerialize,
|
|
|
|
transaction::{
|
|
|
|
AuthDigest, Hash,
|
|
|
|
Transaction::{self, *},
|
|
|
|
WtxId,
|
|
|
|
},
|
2021-08-17 22:52:42 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
use UnminedTxId::*;
|
|
|
|
|
2022-11-23 17:27:35 -08:00
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
|
|
|
use proptest_derive::Arbitrary;
|
|
|
|
|
2022-12-07 20:19:12 -08:00
|
|
|
// Documentation-only
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
use crate::block::MAX_BLOCK_BYTES;
|
|
|
|
|
2022-11-23 17:27:35 -08:00
|
|
|
mod zip317;
|
|
|
|
|
2021-10-26 17:21:19 -07:00
|
|
|
/// The minimum cost value for a transaction in the mempool.
|
|
|
|
///
|
|
|
|
/// Contributes to the randomized, weighted eviction of transactions from the
|
|
|
|
/// mempool when it reaches a max size, also based on the total cost.
|
|
|
|
///
|
|
|
|
/// > Each transaction has a cost, which is an integer defined as:
|
|
|
|
/// >
|
|
|
|
/// > max(serialized transaction size in bytes, 4000)
|
|
|
|
/// >
|
|
|
|
/// > The threshold 4000 for the cost function is chosen so that the size in bytes
|
|
|
|
/// > of a typical fully shielded Sapling transaction (with, say, 2 shielded outputs
|
|
|
|
/// > and up to 5 shielded inputs) will fall below the threshold. This has the effect
|
|
|
|
/// > of ensuring that such transactions are not evicted preferentially to typical
|
|
|
|
/// > transparent transactions because of their size.
|
|
|
|
///
|
|
|
|
/// [ZIP-401]: https://zips.z.cash/zip-0401
|
2023-04-13 01:42:17 -07:00
|
|
|
pub const MEMPOOL_TRANSACTION_COST_THRESHOLD: u64 = 4000;
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2022-11-23 17:27:35 -08:00
|
|
|
/// When a transaction pays a fee less than the conventional fee,
|
|
|
|
/// this low fee penalty is added to its cost for mempool eviction.
|
|
|
|
///
|
|
|
|
/// See [VerifiedUnminedTx::eviction_weight()] for details.
|
|
|
|
const MEMPOOL_TRANSACTION_LOW_FEE_PENALTY: u64 = 16_000;
|
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
/// A unique identifier for an unmined transaction, regardless of version.
|
|
|
|
///
|
|
|
|
/// "The transaction ID of a version 4 or earlier transaction is the SHA-256d hash
|
|
|
|
/// of the transaction encoding in the pre-v5 format described above.
|
|
|
|
///
|
|
|
|
/// The transaction ID of a version 5 transaction is as defined in [ZIP-244].
|
|
|
|
///
|
|
|
|
/// A v5 transaction also has a wtxid (used for example in the peer-to-peer protocol)
|
|
|
|
/// as defined in [ZIP-239]."
|
|
|
|
/// [Spec: Transaction Identifiers]
|
|
|
|
///
|
|
|
|
/// [ZIP-239]: https://zips.z.cash/zip-0239
|
|
|
|
/// [ZIP-244]: https://zips.z.cash/zip-0244
|
|
|
|
/// [Spec: Transaction Identifiers]: https://zips.z.cash/protocol/protocol.pdf#txnidentifiers
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
|
|
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
|
|
|
pub enum UnminedTxId {
|
2021-08-18 15:55:24 -07:00
|
|
|
/// A legacy unmined transaction identifier.
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
|
|
|
/// Used to uniquely identify unmined version 1-4 transactions.
|
2021-08-18 15:55:24 -07:00
|
|
|
/// (After v1-4 transactions are mined, they can be uniquely identified
|
2022-06-02 08:07:35 -07:00
|
|
|
/// using the same [`struct@Hash`].)
|
2021-08-18 15:55:24 -07:00
|
|
|
Legacy(Hash),
|
2021-08-17 22:52:42 -07:00
|
|
|
|
2021-08-18 15:55:24 -07:00
|
|
|
/// A witnessed unmined transaction identifier.
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
|
|
|
/// Used to uniquely identify unmined version 5 transactions.
|
2021-08-18 15:55:24 -07:00
|
|
|
/// (After v5 transactions are mined, they can be uniquely identified
|
2022-06-02 08:07:35 -07:00
|
|
|
/// using only the [`struct@Hash`] in their `WtxId.id`.)
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
|
|
|
/// For more details, see [`WtxId`].
|
2021-08-18 15:55:24 -07:00
|
|
|
Witnessed(WtxId),
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Transaction> for UnminedTxId {
|
|
|
|
fn from(transaction: Transaction) -> Self {
|
|
|
|
// use the ref implementation, to avoid cloning the transaction
|
|
|
|
UnminedTxId::from(&transaction)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&Transaction> for UnminedTxId {
|
|
|
|
fn from(transaction: &Transaction) -> Self {
|
|
|
|
match transaction {
|
2021-08-18 15:55:24 -07:00
|
|
|
V1 { .. } | V2 { .. } | V3 { .. } | V4 { .. } => Legacy(transaction.into()),
|
|
|
|
V5 { .. } => Witnessed(transaction.into()),
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-25 14:02:47 -07:00
|
|
|
impl From<Arc<Transaction>> for UnminedTxId {
|
|
|
|
fn from(transaction: Arc<Transaction>) -> Self {
|
|
|
|
transaction.as_ref().into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
impl From<WtxId> for UnminedTxId {
|
|
|
|
fn from(wtx_id: WtxId) -> Self {
|
2021-08-18 15:55:24 -07:00
|
|
|
Witnessed(wtx_id)
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&WtxId> for UnminedTxId {
|
|
|
|
fn from(wtx_id: &WtxId) -> Self {
|
|
|
|
(*wtx_id).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-01 17:06:20 -07:00
|
|
|
impl fmt::Display for UnminedTxId {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Legacy(hash) => hash.fmt(f),
|
|
|
|
Witnessed(id) => id.fmt(f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
impl UnminedTxId {
|
2022-06-02 08:07:35 -07:00
|
|
|
/// Create a new [`UnminedTxId`] using a v1-v4 legacy transaction ID.
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
|
|
|
/// # Correctness
|
|
|
|
///
|
|
|
|
/// This method must only be used for v1-v4 transaction IDs.
|
2022-06-02 08:07:35 -07:00
|
|
|
/// [`struct@Hash`] does not uniquely identify unmined v5
|
|
|
|
/// transactions.
|
2021-08-17 22:52:42 -07:00
|
|
|
pub fn from_legacy_id(legacy_tx_id: Hash) -> UnminedTxId {
|
2021-08-18 15:55:24 -07:00
|
|
|
Legacy(legacy_tx_id)
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
|
2021-08-18 15:55:24 -07:00
|
|
|
/// Return the unique ID that will be used if this transaction gets mined into a block.
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
|
|
|
/// # Correctness
|
|
|
|
///
|
2021-08-18 15:55:24 -07:00
|
|
|
/// For v1-v4 transactions, this method returns an ID which changes
|
|
|
|
/// if this transaction's effects (spends and outputs) change, or
|
|
|
|
/// if its authorizing data changes (signatures, proofs, and scripts).
|
2021-08-17 22:52:42 -07:00
|
|
|
///
|
2021-08-18 15:55:24 -07:00
|
|
|
/// But for v5 transactions, this ID uniquely identifies the transaction's effects.
|
|
|
|
pub fn mined_id(&self) -> Hash {
|
2021-08-17 22:52:42 -07:00
|
|
|
match self {
|
2021-08-18 15:55:24 -07:00
|
|
|
Legacy(legacy_id) => *legacy_id,
|
|
|
|
Witnessed(wtx_id) => wtx_id.id,
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 17:35:50 -07:00
|
|
|
/// Returns a mutable reference to the unique ID
|
|
|
|
/// that will be used if this transaction gets mined into a block.
|
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// See [`Self::mined_id`] for details.
|
2021-10-11 17:35:50 -07:00
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
|
|
|
pub fn mined_id_mut(&mut self) -> &mut Hash {
|
|
|
|
match self {
|
|
|
|
Legacy(legacy_id) => legacy_id,
|
|
|
|
Witnessed(wtx_id) => &mut wtx_id.id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
/// Return the digest of this transaction's authorizing data,
|
|
|
|
/// (signatures, proofs, and scripts), if it is a v5 transaction.
|
|
|
|
pub fn auth_digest(&self) -> Option<AuthDigest> {
|
|
|
|
match self {
|
2021-08-18 15:55:24 -07:00
|
|
|
Legacy(_) => None,
|
|
|
|
Witnessed(wtx_id) => Some(wtx_id.auth_digest),
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
2021-10-11 17:35:50 -07:00
|
|
|
|
|
|
|
/// Returns a mutable reference to the digest of this transaction's authorizing data,
|
|
|
|
/// (signatures, proofs, and scripts), if it is a v5 transaction.
|
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
|
|
|
pub fn auth_digest_mut(&mut self) -> Option<&mut AuthDigest> {
|
|
|
|
match self {
|
|
|
|
Legacy(_) => None,
|
|
|
|
Witnessed(wtx_id) => Some(&mut wtx_id.auth_digest),
|
|
|
|
}
|
|
|
|
}
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An unmined transaction, and its pre-calculated unique identifying ID.
|
2021-10-17 18:24:37 -07:00
|
|
|
///
|
|
|
|
/// This transaction has been structurally verified.
|
|
|
|
/// (But it might still need semantic or contextual verification.)
|
2021-08-17 22:52:42 -07:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
pub struct UnminedTx {
|
|
|
|
/// The unmined transaction itself.
|
|
|
|
pub transaction: Arc<Transaction>,
|
2021-10-06 15:40:11 -07:00
|
|
|
|
2022-11-02 20:25:01 -07:00
|
|
|
/// A unique identifier for this unmined transaction.
|
|
|
|
pub id: UnminedTxId,
|
|
|
|
|
2021-10-06 15:40:11 -07:00
|
|
|
/// The size in bytes of the serialized transaction data
|
|
|
|
pub size: usize,
|
2022-11-23 17:27:35 -08:00
|
|
|
|
|
|
|
/// The conventional fee for this transaction, as defined by [ZIP-317].
|
|
|
|
///
|
|
|
|
/// [ZIP-317]: https://zips.z.cash/zip-0317#fee-calculation
|
|
|
|
pub conventional_fee: Amount<NonNegative>,
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
|
2021-10-17 18:24:37 -07:00
|
|
|
impl fmt::Display for UnminedTx {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("UnminedTx")
|
2022-12-12 15:19:45 -08:00
|
|
|
.field("transaction", &self.transaction.to_string())
|
2021-10-17 18:24:37 -07:00
|
|
|
.field("serialized_size", &self.size)
|
2022-11-23 17:27:35 -08:00
|
|
|
.field("conventional_fee", &self.conventional_fee)
|
2021-10-17 18:24:37 -07:00
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
// Each of these conversions is implemented slightly differently,
|
|
|
|
// to avoid cloning the transaction where possible.
|
|
|
|
|
|
|
|
impl From<Transaction> for UnminedTx {
|
|
|
|
fn from(transaction: Transaction) -> Self {
|
2022-11-23 17:27:35 -08:00
|
|
|
let size = transaction.zcash_serialized_size();
|
|
|
|
let conventional_fee = zip317::conventional_fee(&transaction);
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2022-07-04 18:04:47 -07:00
|
|
|
// The borrow is actually needed to avoid taking ownership
|
|
|
|
#[allow(clippy::needless_borrow)]
|
2021-08-17 22:52:42 -07:00
|
|
|
Self {
|
|
|
|
id: (&transaction).into(),
|
2021-10-26 17:21:19 -07:00
|
|
|
size,
|
2022-11-23 17:27:35 -08:00
|
|
|
conventional_fee,
|
2021-08-17 22:52:42 -07:00
|
|
|
transaction: Arc::new(transaction),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&Transaction> for UnminedTx {
|
|
|
|
fn from(transaction: &Transaction) -> Self {
|
2022-11-23 17:27:35 -08:00
|
|
|
let size = transaction.zcash_serialized_size();
|
|
|
|
let conventional_fee = zip317::conventional_fee(transaction);
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
Self {
|
|
|
|
id: transaction.into(),
|
2021-10-26 17:21:19 -07:00
|
|
|
size,
|
2022-11-23 17:27:35 -08:00
|
|
|
conventional_fee,
|
|
|
|
transaction: Arc::new(transaction.clone()),
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Arc<Transaction>> for UnminedTx {
|
|
|
|
fn from(transaction: Arc<Transaction>) -> Self {
|
2022-11-23 17:27:35 -08:00
|
|
|
let size = transaction.zcash_serialized_size();
|
|
|
|
let conventional_fee = zip317::conventional_fee(&transaction);
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
Self {
|
|
|
|
id: transaction.as_ref().into(),
|
2021-10-26 17:21:19 -07:00
|
|
|
size,
|
2022-11-23 17:27:35 -08:00
|
|
|
conventional_fee,
|
|
|
|
transaction,
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&Arc<Transaction>> for UnminedTx {
|
|
|
|
fn from(transaction: &Arc<Transaction>) -> Self {
|
2022-11-23 17:27:35 -08:00
|
|
|
let size = transaction.zcash_serialized_size();
|
|
|
|
let conventional_fee = zip317::conventional_fee(transaction);
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2021-08-17 22:52:42 -07:00
|
|
|
Self {
|
|
|
|
id: transaction.as_ref().into(),
|
2021-10-26 17:21:19 -07:00
|
|
|
size,
|
2022-11-23 17:27:35 -08:00
|
|
|
conventional_fee,
|
|
|
|
transaction: transaction.clone(),
|
2021-08-17 22:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-17 18:24:37 -07:00
|
|
|
|
|
|
|
/// A verified unmined transaction, and the corresponding transaction fee.
|
|
|
|
///
|
|
|
|
/// This transaction has been fully verified, in the context of the mempool.
|
2022-12-01 13:57:22 -08:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2021-10-17 18:24:37 -07:00
|
|
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
|
|
|
pub struct VerifiedUnminedTx {
|
|
|
|
/// The unmined transaction.
|
|
|
|
pub transaction: UnminedTx,
|
|
|
|
|
|
|
|
/// The transaction fee for this unmined transaction.
|
|
|
|
pub miner_fee: Amount<NonNegative>,
|
2022-11-03 10:03:41 -07:00
|
|
|
|
|
|
|
/// The number of legacy signature operations in this transaction's
|
|
|
|
/// transparent inputs and outputs.
|
|
|
|
pub legacy_sigop_count: u64,
|
2022-12-01 13:57:22 -08:00
|
|
|
|
2022-12-07 20:19:12 -08:00
|
|
|
/// The number of unpaid actions for `transaction`,
|
|
|
|
/// as defined by [ZIP-317] for block production.
|
|
|
|
///
|
|
|
|
/// The number of actions is limited by [`MAX_BLOCK_BYTES`], so it fits in a u32.
|
|
|
|
///
|
|
|
|
/// [ZIP-317]: https://zips.z.cash/zip-0317#block-production
|
|
|
|
pub unpaid_actions: u32,
|
|
|
|
|
|
|
|
/// The fee weight ratio for `transaction`, as defined by [ZIP-317] for block production.
|
2022-12-01 13:57:22 -08:00
|
|
|
///
|
|
|
|
/// This is not consensus-critical, so we use `f32` for efficient calculations
|
|
|
|
/// when the mempool holds a large number of transactions.
|
|
|
|
///
|
|
|
|
/// [ZIP-317]: https://zips.z.cash/zip-0317#block-production
|
2022-12-07 20:19:12 -08:00
|
|
|
pub fee_weight_ratio: f32,
|
2021-10-17 18:24:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for VerifiedUnminedTx {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("VerifiedUnminedTx")
|
2022-12-12 15:19:45 -08:00
|
|
|
.field("transaction", &self.transaction.to_string())
|
2021-10-17 18:24:37 -07:00
|
|
|
.field("miner_fee", &self.miner_fee)
|
2022-11-03 10:03:41 -07:00
|
|
|
.field("legacy_sigop_count", &self.legacy_sigop_count)
|
2022-12-07 20:19:12 -08:00
|
|
|
.field("unpaid_actions", &self.unpaid_actions)
|
|
|
|
.field("fee_weight_ratio", &self.fee_weight_ratio)
|
2021-10-17 18:24:37 -07:00
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VerifiedUnminedTx {
|
2022-12-01 13:57:22 -08:00
|
|
|
/// Create a new verified unmined transaction from an unmined transaction,
|
|
|
|
/// its miner fee, and its legacy sigop count.
|
2022-11-03 10:03:41 -07:00
|
|
|
pub fn new(
|
|
|
|
transaction: UnminedTx,
|
|
|
|
miner_fee: Amount<NonNegative>,
|
|
|
|
legacy_sigop_count: u64,
|
|
|
|
) -> Self {
|
2022-12-07 20:19:12 -08:00
|
|
|
let fee_weight_ratio = zip317::conventional_fee_weight_ratio(&transaction, miner_fee);
|
|
|
|
let unpaid_actions = zip317::unpaid_actions(&transaction, miner_fee);
|
2022-12-01 13:57:22 -08:00
|
|
|
|
2021-10-17 18:24:37 -07:00
|
|
|
Self {
|
|
|
|
transaction,
|
|
|
|
miner_fee,
|
2022-11-03 10:03:41 -07:00
|
|
|
legacy_sigop_count,
|
2022-12-07 20:19:12 -08:00
|
|
|
fee_weight_ratio,
|
|
|
|
unpaid_actions,
|
2021-10-17 18:24:37 -07:00
|
|
|
}
|
|
|
|
}
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2022-12-01 13:57:22 -08:00
|
|
|
/// Returns `true` if the transaction pays at least the [ZIP-317] conventional fee.
|
|
|
|
///
|
|
|
|
/// [ZIP-317]: https://zips.z.cash/zip-0317#mempool-size-limiting
|
|
|
|
pub fn pays_conventional_fee(&self) -> bool {
|
|
|
|
self.miner_fee >= self.transaction.conventional_fee
|
|
|
|
}
|
|
|
|
|
2021-10-26 17:21:19 -07:00
|
|
|
/// The cost in bytes of the transaction, as defined in [ZIP-401].
|
|
|
|
///
|
|
|
|
/// A reflection of the work done by the network in processing them (proof
|
|
|
|
/// and signature verification; networking overheads; size of in-memory data
|
|
|
|
/// structures).
|
|
|
|
///
|
|
|
|
/// > Each transaction has a cost, which is an integer defined as:
|
|
|
|
/// >
|
|
|
|
/// > max(serialized transaction size in bytes, 4000)
|
|
|
|
///
|
|
|
|
/// [ZIP-401]: https://zips.z.cash/zip-0401
|
|
|
|
pub fn cost(&self) -> u64 {
|
|
|
|
std::cmp::max(
|
2022-11-23 17:27:35 -08:00
|
|
|
u64::try_from(self.transaction.size).expect("fits in u64"),
|
2021-10-26 17:21:19 -07:00
|
|
|
MEMPOOL_TRANSACTION_COST_THRESHOLD,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The computed _eviction weight_ of a verified unmined transaction as part
|
2022-11-23 17:27:35 -08:00
|
|
|
/// of the mempool set, as defined in [ZIP-317] and [ZIP-401].
|
2021-10-26 17:21:19 -07:00
|
|
|
///
|
2022-11-23 17:27:35 -08:00
|
|
|
/// Standard rule:
|
2021-10-26 17:21:19 -07:00
|
|
|
///
|
|
|
|
/// > Each transaction also has an eviction weight, which is cost +
|
|
|
|
/// > low_fee_penalty, where low_fee_penalty is 16000 if the transaction pays
|
2022-11-23 17:27:35 -08:00
|
|
|
/// > a fee less than the conventional fee, otherwise 0.
|
2021-10-26 17:21:19 -07:00
|
|
|
///
|
2022-11-23 17:27:35 -08:00
|
|
|
/// > zcashd and zebrad limit the size of the mempool as described in [ZIP-401].
|
|
|
|
/// > This specifies a low fee penalty that is added to the "eviction weight" if the transaction
|
|
|
|
/// > pays a fee less than the conventional transaction fee. This threshold is
|
|
|
|
/// > modified to use the new conventional fee formula.
|
|
|
|
///
|
|
|
|
/// [ZIP-317]: https://zips.z.cash/zip-0317#mempool-size-limiting
|
2021-10-26 17:21:19 -07:00
|
|
|
/// [ZIP-401]: https://zips.z.cash/zip-0401
|
2022-11-23 17:27:35 -08:00
|
|
|
pub fn eviction_weight(&self) -> u64 {
|
|
|
|
let mut cost = self.cost();
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2022-12-01 13:57:22 -08:00
|
|
|
if !self.pays_conventional_fee() {
|
2022-11-23 17:27:35 -08:00
|
|
|
cost += MEMPOOL_TRANSACTION_LOW_FEE_PENALTY
|
|
|
|
}
|
2021-10-26 17:21:19 -07:00
|
|
|
|
2022-11-23 17:27:35 -08:00
|
|
|
cost
|
2021-10-26 17:21:19 -07:00
|
|
|
}
|
2021-10-17 18:24:37 -07:00
|
|
|
}
|