Skip to content

Commit

Permalink
Merge of #5994
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jan 23, 2023
2 parents 53b4466 + 6114a96 commit 5aad5cd
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 13 deletions.
2 changes: 1 addition & 1 deletion zebra-chain/src/transaction/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use super::{txid::TxIdBuilder, AuthDigest, Transaction};
///
/// [ZIP-244]: https://zips.z.cash/zip-0244
/// [Spec: Transaction Identifiers]: https://zips.z.cash/protocol/protocol.pdf#txnidentifiers
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub struct Hash(pub [u8; 32]);

Expand Down
39 changes: 38 additions & 1 deletion zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,9 +647,24 @@ where

// TODO: use a generic error constructor (#5548)
fn get_raw_mempool(&self) -> BoxFuture<Result<Vec<String>>> {
#[cfg(feature = "getblocktemplate-rpcs")]
use zebra_chain::block::MAX_BLOCK_BYTES;

#[cfg(feature = "getblocktemplate-rpcs")]
/// Determines whether the output of this RPC is sorted like zcashd
const SHOULD_USE_ZCASHD_ORDER: bool = true;

let mut mempool = self.mempool.clone();

async move {
#[cfg(feature = "getblocktemplate-rpcs")]
let request = if SHOULD_USE_ZCASHD_ORDER {
mempool::Request::FullTransactions
} else {
mempool::Request::TransactionIds
};

#[cfg(not(feature = "getblocktemplate-rpcs"))]
let request = mempool::Request::TransactionIds;

// `zcashd` doesn't check if it is synced to the tip here, so we don't either.
Expand All @@ -664,18 +679,40 @@ where
})?;

match response {
#[cfg(feature = "getblocktemplate-rpcs")]
mempool::Response::FullTransactions(mut transactions) => {
// Sort transactions in descending order by fee/size, using hash in serialized byte order as a tie-breaker
transactions.sort_by_cached_key(|tx| {
// zcashd uses modified fee here but Zebra doesn't currently
// support prioritizing transactions
std::cmp::Reverse((
i64::from(tx.miner_fee) as u128 * MAX_BLOCK_BYTES as u128
/ tx.transaction.size as u128,
// transaction hashes are compared in their serialized byte-order.
tx.transaction.id.mined_id(),
))
});

let tx_ids: Vec<String> = transactions
.iter()
.map(|unmined_tx| unmined_tx.transaction.id.mined_id().encode_hex())
.collect();

Ok(tx_ids)
}

mempool::Response::TransactionIds(unmined_transaction_ids) => {
let mut tx_ids: Vec<String> = unmined_transaction_ids
.iter()
.map(|id| id.mined_id().encode_hex())
.collect();

// Sort returned transaction IDs in numeric/string order.
// (zcashd's sort order appears arbitrary.)
tx_ids.sort();

Ok(tx_ids)
}

_ => unreachable!("unmatched response to a transactionids request"),
}
}
Expand Down
62 changes: 51 additions & 11 deletions zebra-rpc/src/methods/tests/prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use zebra_chain::{
NetworkUpgrade,
},
serialization::{ZcashDeserialize, ZcashSerialize},
transaction::{self, Transaction, UnminedTx, UnminedTxId},
transaction::{self, Transaction, UnminedTx, VerifiedUnminedTx},
transparent,
};
use zebra_node_services::mempool;
Expand Down Expand Up @@ -313,7 +313,7 @@ proptest! {
/// Make the mock mempool service return a list of transaction IDs, and check that the RPC call
/// returns those IDs as hexadecimal strings.
#[test]
fn mempool_transactions_are_sent_to_caller(transaction_ids in any::<HashSet<UnminedTxId>>()) {
fn mempool_transactions_are_sent_to_caller(transactions in any::<Vec<VerifiedUnminedTx>>()) {
let (runtime, _init_guard) = zebra_test::init_async();
let _guard = runtime.enter();

Expand All @@ -334,16 +334,56 @@ proptest! {
);

let call_task = tokio::spawn(rpc.get_raw_mempool());
let mut expected_response: Vec<String> = transaction_ids
.iter()
.map(|id| id.mined_id().encode_hex())
.collect();
expected_response.sort();

mempool
.expect_request(mempool::Request::TransactionIds)
.await?
.respond(mempool::Response::TransactionIds(transaction_ids));

#[cfg(not(feature = "getblocktemplate-rpcs"))]
let expected_response = {
let transaction_ids: HashSet<_> = transactions
.iter()
.map(|tx| tx.transaction.id)
.collect();

let mut expected_response: Vec<String> = transaction_ids
.iter()
.map(|id| id.mined_id().encode_hex())
.collect();
expected_response.sort();

mempool
.expect_request(mempool::Request::TransactionIds)
.await?
.respond(mempool::Response::TransactionIds(transaction_ids));

expected_response
};

// Note: this depends on `SHOULD_USE_ZCASHD_ORDER` being true.
#[cfg(feature = "getblocktemplate-rpcs")]
let expected_response = {
let mut expected_response = transactions.clone();
expected_response.sort_by_cached_key(|tx| {
// zcashd uses modified fee here but Zebra doesn't currently
// support prioritizing transactions
std::cmp::Reverse((
i64::from(tx.miner_fee) as u128 * zebra_chain::block::MAX_BLOCK_BYTES as u128
/ tx.transaction.size as u128,
// transaction hashes are compared in their serialized byte-order.
tx.transaction.id.mined_id(),
))
});

let expected_response = expected_response
.iter()
.map(|tx| tx.transaction.id.mined_id().encode_hex())
.collect();

mempool
.expect_request(mempool::Request::FullTransactions)
.await?
.respond(mempool::Response::FullTransactions(transactions));

expected_response
};

mempool.expect_no_requests().await?;
state.expect_no_requests().await?;
Expand Down
9 changes: 9 additions & 0 deletions zebra-rpc/src/methods/tests/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ async fn test_rpc_response_data_for_network(network: Network) {
// - a request to get all mempool transactions will be made by `getrawmempool` behind the scenes.
// - as we have the mempool mocked we need to expect a request and wait for a response,
// which will be an empty mempool in this case.
// Note: this depends on `SHOULD_USE_ZCASHD_ORDER` being true.
#[cfg(feature = "getblocktemplate-rpcs")]
let mempool_req = mempool
.expect_request_that(|request| matches!(request, mempool::Request::FullTransactions))
.map(|responder| {
responder.respond(mempool::Response::FullTransactions(vec![]));
});

#[cfg(not(feature = "getblocktemplate-rpcs"))]
let mempool_req = mempool
.expect_request_that(|request| matches!(request, mempool::Request::TransactionIds))
.map(|responder| {
Expand Down

0 comments on commit 5aad5cd

Please sign in to comment.