2022-04-27 16:06:11 -07:00
|
|
|
//! Test sending transactions using a lightwalletd instance connected to a zebrad instance.
|
|
|
|
//!
|
2022-11-09 19:40:21 -08:00
|
|
|
//! This test requires a cached chain state that is partially synchronized close to the
|
|
|
|
//! network chain tip height. It will finish the sync and update the cached chain state.
|
2022-04-27 16:06:11 -07:00
|
|
|
//!
|
2022-11-09 19:40:21 -08:00
|
|
|
//! After finishing the sync, it will get the first 20 blocks in the non-finalized state
|
|
|
|
//! (past the MAX_BLOCK_REORG_HEIGHT) via getblock rpc calls, shuts down the zebrad instance
|
|
|
|
//! so that the retrieved blocks aren't finalized into the cached state, and get the finalized
|
|
|
|
//! tip height of the updated cached state.
|
|
|
|
//!
|
|
|
|
//! The transactions to use to send are obtained from those blocks that are above the finalized
|
|
|
|
//! tip height of the updated cached state.
|
2022-04-27 16:06:11 -07:00
|
|
|
//!
|
|
|
|
//! The zebrad instance connected to lightwalletd uses the cached state and does not connect to any
|
|
|
|
//! external peers, which prevents it from downloading the blocks from where the test transactions
|
|
|
|
//! were obtained. This is to ensure that zebra does not reject the transactions because they have
|
|
|
|
//! already been seen in a block.
|
|
|
|
|
2022-11-09 19:40:21 -08:00
|
|
|
use std::{cmp::min, sync::Arc};
|
2022-04-27 16:06:11 -07:00
|
|
|
|
2022-11-09 19:40:21 -08:00
|
|
|
use color_eyre::eyre::Result;
|
2022-04-27 16:06:11 -07:00
|
|
|
|
|
|
|
use zebra_chain::{
|
2022-10-05 21:12:27 -07:00
|
|
|
parameters::Network::{self, *},
|
2022-09-06 06:32:33 -07:00
|
|
|
serialization::ZcashSerialize,
|
|
|
|
transaction::{self, Transaction},
|
2022-04-27 16:06:11 -07:00
|
|
|
};
|
2022-07-31 20:48:19 -07:00
|
|
|
use zebra_rpc::queue::CHANNEL_AND_QUEUE_CAPACITY;
|
|
|
|
use zebrad::components::mempool::downloads::MAX_INBOUND_CONCURRENCY;
|
2022-04-27 16:06:11 -07:00
|
|
|
|
|
|
|
use crate::common::{
|
2022-11-09 19:40:21 -08:00
|
|
|
cached_state::get_future_blocks,
|
2022-10-05 21:12:27 -07:00
|
|
|
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
|
2022-04-27 16:06:11 -07:00
|
|
|
lightwalletd::{
|
2022-10-05 21:12:27 -07:00
|
|
|
can_spawn_lightwalletd_for_rpc, spawn_lightwalletd_for_rpc,
|
|
|
|
sync::wait_for_zebrad_and_lightwalletd_sync,
|
|
|
|
wallet_grpc::{self, connect_to_lightwalletd, Empty, Exclude},
|
2022-04-27 16:06:11 -07:00
|
|
|
},
|
2022-11-09 19:40:21 -08:00
|
|
|
test_type::TestType::{self, *},
|
2022-04-27 16:06:11 -07:00
|
|
|
};
|
|
|
|
|
2022-09-06 06:32:33 -07:00
|
|
|
/// The maximum number of transactions we want to send in the test.
|
|
|
|
/// This avoids filling the mempool queue and generating errors.
|
|
|
|
///
|
|
|
|
/// TODO: replace with a const when `min()` stabilises as a const function:
|
|
|
|
/// https://github.com/rust-lang/rust/issues/92391
|
|
|
|
fn max_sent_transactions() -> usize {
|
2023-05-22 05:05:40 -07:00
|
|
|
min(CHANNEL_AND_QUEUE_CAPACITY, MAX_INBOUND_CONCURRENCY) / 2
|
2022-09-06 06:32:33 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 19:40:21 -08:00
|
|
|
/// Number of blocks past the finalized to load transactions from.
|
|
|
|
const MAX_NUM_FUTURE_BLOCKS: u32 = 50;
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
/// The test entry point.
|
|
|
|
pub async fn run() -> Result<()> {
|
2022-08-04 08:44:44 -07:00
|
|
|
let _init_guard = zebra_test::init();
|
2022-04-27 16:06:11 -07:00
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
// We want a zebra state dir and a lightwalletd data dir in place,
|
|
|
|
// so `UpdateCachedState` can be used as our test type
|
|
|
|
let test_type = UpdateCachedState;
|
|
|
|
let test_name = "send_transaction_test";
|
|
|
|
let network = Mainnet;
|
2022-07-31 23:21:08 -07:00
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
// Skip the test unless the user specifically asked for it
|
2022-10-05 21:12:27 -07:00
|
|
|
if !can_spawn_zebrad_for_rpc(test_name, test_type) {
|
2022-04-27 16:06:11 -07:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
if test_type.launches_lightwalletd() && !can_spawn_lightwalletd_for_rpc(test_name, test_type) {
|
|
|
|
tracing::info!("skipping test due to missing lightwalletd network or cached state");
|
|
|
|
return Ok(());
|
|
|
|
}
|
2022-05-04 18:08:27 -07:00
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
let zebrad_state_path = test_type.zebrad_state_path(test_name);
|
2022-07-28 14:06:18 -07:00
|
|
|
let zebrad_state_path = match zebrad_state_path {
|
|
|
|
Some(zebrad_state_path) => zebrad_state_path,
|
|
|
|
None => return Ok(()),
|
|
|
|
};
|
2022-05-04 18:08:27 -07:00
|
|
|
|
2022-06-01 04:36:59 -07:00
|
|
|
tracing::info!(
|
|
|
|
?network,
|
|
|
|
?test_type,
|
|
|
|
?zebrad_state_path,
|
|
|
|
"running gRPC send transaction test using lightwalletd & zebrad",
|
|
|
|
);
|
|
|
|
|
2022-07-31 20:48:19 -07:00
|
|
|
let mut transactions =
|
2022-11-09 19:40:21 -08:00
|
|
|
load_transactions_from_future_blocks(network, test_type, test_name).await?;
|
2022-06-01 04:36:59 -07:00
|
|
|
|
|
|
|
tracing::info!(
|
|
|
|
transaction_count = ?transactions.len(),
|
2022-07-28 14:06:18 -07:00
|
|
|
partial_sync_path = ?zebrad_state_path,
|
2022-10-05 21:12:27 -07:00
|
|
|
"got transactions to send, spawning isolated zebrad...",
|
2022-06-01 04:36:59 -07:00
|
|
|
);
|
2022-04-27 16:06:11 -07:00
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
// We run these gRPC tests without a network connection.
|
|
|
|
let use_internet_connection = false;
|
|
|
|
|
|
|
|
// Start zebrad with no peers, we want to send transactions without blocks coming in. If `wallet_grpc_test`
|
|
|
|
// runs before this test (as it does in `lightwalletd_test_suite`), then we are the most up to date with tip we can.
|
|
|
|
let (mut zebrad, zebra_rpc_address) = if let Some(zebrad_and_address) =
|
|
|
|
spawn_zebrad_for_rpc(network, test_name, test_type, use_internet_connection)?
|
|
|
|
{
|
|
|
|
zebrad_and_address
|
|
|
|
} else {
|
|
|
|
// Skip the test, we don't have the required cached state
|
|
|
|
return Ok(());
|
|
|
|
};
|
|
|
|
|
|
|
|
let zebra_rpc_address = zebra_rpc_address.expect("lightwalletd test must have RPC port");
|
2022-04-27 16:06:11 -07:00
|
|
|
|
2022-06-01 04:36:59 -07:00
|
|
|
tracing::info!(
|
2022-10-05 21:12:27 -07:00
|
|
|
?test_type,
|
2022-06-01 04:36:59 -07:00
|
|
|
?zebra_rpc_address,
|
2022-10-05 21:12:27 -07:00
|
|
|
"spawned isolated zebrad with shorter chain, waiting for zebrad to open its RPC port..."
|
2022-06-01 04:36:59 -07:00
|
|
|
);
|
2022-10-27 06:25:18 -07:00
|
|
|
zebrad.expect_stdout_line_matches(&format!("Opened RPC endpoint at {zebra_rpc_address}"))?;
|
2022-06-01 04:36:59 -07:00
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
tracing::info!(
|
|
|
|
?zebra_rpc_address,
|
|
|
|
"zebrad opened its RPC port, spawning lightwalletd...",
|
|
|
|
);
|
|
|
|
|
|
|
|
let (lightwalletd, lightwalletd_rpc_port) =
|
|
|
|
spawn_lightwalletd_for_rpc(network, test_name, test_type, zebra_rpc_address)?
|
|
|
|
.expect("already checked cached state and network requirements");
|
2022-04-27 16:06:11 -07:00
|
|
|
|
2022-06-01 04:36:59 -07:00
|
|
|
tracing::info!(
|
|
|
|
?lightwalletd_rpc_port,
|
2022-10-05 21:12:27 -07:00
|
|
|
"spawned lightwalletd connected to zebrad, waiting for them both to sync...",
|
2022-09-06 06:32:33 -07:00
|
|
|
);
|
|
|
|
|
2022-10-05 21:12:27 -07:00
|
|
|
let (_lightwalletd, _zebrad) = wait_for_zebrad_and_lightwalletd_sync(
|
|
|
|
lightwalletd,
|
|
|
|
lightwalletd_rpc_port,
|
|
|
|
zebrad,
|
|
|
|
zebra_rpc_address,
|
|
|
|
test_type,
|
|
|
|
// We want to send transactions to the mempool, but we aren't syncing with the network
|
|
|
|
true,
|
|
|
|
use_internet_connection,
|
|
|
|
)?;
|
2022-09-06 06:32:33 -07:00
|
|
|
|
|
|
|
tracing::info!(
|
|
|
|
?lightwalletd_rpc_port,
|
|
|
|
"connecting gRPC client to lightwalletd...",
|
2022-06-01 04:36:59 -07:00
|
|
|
);
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
let mut rpc_client = connect_to_lightwalletd(lightwalletd_rpc_port).await?;
|
|
|
|
|
2022-07-31 20:48:19 -07:00
|
|
|
// To avoid filling the mempool queue, limit the transactions to be sent to the RPC and mempool queue limits
|
2022-09-06 06:32:33 -07:00
|
|
|
transactions.truncate(max_sent_transactions());
|
|
|
|
|
|
|
|
let transaction_hashes: Vec<transaction::Hash> =
|
|
|
|
transactions.iter().map(|tx| tx.hash()).collect();
|
2022-07-31 20:48:19 -07:00
|
|
|
|
2022-06-01 04:36:59 -07:00
|
|
|
tracing::info!(
|
|
|
|
transaction_count = ?transactions.len(),
|
2022-09-06 06:32:33 -07:00
|
|
|
?transaction_hashes,
|
2022-06-01 04:36:59 -07:00
|
|
|
"connected gRPC client to lightwalletd, sending transactions...",
|
|
|
|
);
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
for transaction in transactions {
|
2022-09-06 06:32:33 -07:00
|
|
|
let transaction_hash = transaction.hash();
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
let expected_response = wallet_grpc::SendResponse {
|
|
|
|
error_code: 0,
|
2022-10-27 06:25:18 -07:00
|
|
|
error_message: format!("\"{transaction_hash}\""),
|
2022-04-27 16:06:11 -07:00
|
|
|
};
|
|
|
|
|
2022-09-06 06:32:33 -07:00
|
|
|
tracing::info!(?transaction_hash, "sending transaction...");
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
let request = prepare_send_transaction_request(transaction);
|
|
|
|
|
|
|
|
let response = rpc_client.send_transaction(request).await?.into_inner();
|
|
|
|
|
|
|
|
assert_eq!(response, expected_response);
|
|
|
|
}
|
|
|
|
|
change(state): Write non-finalized blocks to the state in a separate thread, to avoid network and RPC hangs (#5257)
* Add a new block commit task and channels, that don't do anything yet
* Add last_block_hash_sent to the state service, to avoid database accesses
* Update last_block_hash_sent regardless of commit errors
* Rename a field to StateService.max_queued_finalized_height
* Commit finalized blocks to the state in a separate task
* Check for panics in the block write task
* Wait for the block commit task in tests, and check for errors
* Always run a proptest that sleeps once
* Add extra debugging to state shutdowns
* Work around a RocksDB shutdown bug
* Close the finalized block channel when we're finished with it
* Only reset state queue once per error
* Update some TODOs
* Add a module doc comment
* Drop channels and check for closed channels in the block commit task
* Close state channels and tasks on drop
* Remove some duplicate fields across StateService and ReadStateService
* Try tweaking the shutdown steps
* Update and clarify some comments
* Clarify another comment
* Don't try to cancel RocksDB background work on drop
* Fix up some comments
* Remove some duplicate code
* Remove redundant workarounds for shutdown issues
* Remode a redundant channel close in the block commit task
* Remove a mistaken `!force` shutdown condition
* Remove duplicate force-shutdown code and explain it better
* Improve RPC error logging
* Wait for chain tip updates in the RPC tests
* Wait 2 seconds for chain tip updates before skipping them
* Remove an unnecessary block_in_place()
* Fix some test error messages that were changed by earlier fixes
* Expand some comments, fix typos
Co-authored-by: Marek <mail@marek.onl>
* Actually drop children of failed blocks
* Explain why we drop descendants of failed blocks
* Clarify a comment
* Wait for chain tip updates in a failing test on macOS
* Clean duplicate finalized blocks when the non-finalized state activates
* Send an error when receiving a duplicate finalized block
* Update checkpoint block behaviour, document its consensus rule
* Wait for chain tip changes in inbound_block_height_lookahead_limit test
* Wait for the genesis block to commit in the fake peer set mempool tests
* Disable unreliable mempool verification check in the send transaction test
* Appease rustfmt
* Use clear_finalized_block_queue() everywhere that blocks are dropped
* Document how Finalized and NonFinalized clones are different
* sends non-finalized blocks to the block write task
* passes ZebraDb to commit_new_chain, commit_block, and no_duplicates_in_finalized_chain instead of FinalizedState
* Update zebra-state/src/service/write.rs
Co-authored-by: teor <teor@riseup.net>
* updates comments, renames send_process_queued, other minor cleanup
* update assert_block_can_be_validated comment
* removes `mem` field from StateService
* removes `disk` field from StateService and updates block_iter to use `ZebraDb` instead of the finalized state
* updates tests that use the disk to use read_service.db instead
* moves best_tip to a read fn and returns finalized & non-finalized states from setup instead of the state service
* changes `contextual_validity` to get the network from the finalized_state instead of another param
* swaps out StateService with FinalizedState and NonFinalizedState in tests
* adds NotReadyToBeCommitted error and returns it from validate_and_commit when a blocks parent hash is not in any chain
* removes NonFinalizedWriteCmd and calls, moves update_latest_channels above rsp_tx.send
* makes parent_errors_map an indexmap
* clears non-finalized block queue when the receiver is dropped and when the StateService is being dropped
* sends non-finalized blocks to the block write task
* passes ZebraDb to commit_new_chain, commit_block, and no_duplicates_in_finalized_chain instead of FinalizedState
* updates comments, renames send_process_queued, other minor cleanup
* Update zebra-state/src/service/write.rs
Co-authored-by: teor <teor@riseup.net>
* update assert_block_can_be_validated comment
* removes `mem` field from StateService
* removes `disk` field from StateService and updates block_iter to use `ZebraDb` instead of the finalized state
* updates tests that use the disk to use read_service.db instead
* moves best_tip to a read fn and returns finalized & non-finalized states from setup instead of the state service
* changes `contextual_validity` to get the network from the finalized_state instead of another param
* swaps out StateService with FinalizedState and NonFinalizedState in tests
* adds NotReadyToBeCommitted error and returns it from validate_and_commit when a blocks parent hash is not in any chain
* removes NonFinalizedWriteCmd and calls, moves update_latest_channels above rsp_tx.send
* makes parent_errors_map an indexmap
* clears non-finalized block queue when the receiver is dropped and when the StateService is being dropped
* removes duplicate field definitions on StateService that were a result of a bad merge
* update NotReadyToBeCommitted error message
* Appear rustfmt
* Fix doc links
* Rename a function to initial_contextual_validity()
* Do error tasks on Err, and success tasks on Ok
* Simplify parent_error_map truncation
* Rewrite best_tip() to use tip()
* Rename latest_mem() to latest_non_finalized_state()
```sh
fastmod latest_mem latest_non_finalized_state zebra*
cargo fmt --all
```
* Simplify latest_non_finalized_state() using a new WatchReceiver API
* Expand some error messages
* Send the result after updating the channels, and document why
* wait for chain_tip_update before cancelling download in mempool_cancel_mined
* adds `sent_non_finalized_block_hashes` field to StateService
* adds batched sent_hash insertions and checks sent hashes in queue_and_commit_non_finalized before adding a block to the queue
* check that the `curr_buf` in SentHashes is not empty before pushing it to the `sent_bufs`
* Apply suggestions from code review
Co-authored-by: teor <teor@riseup.net>
* Fix rustfmt
* Check for finalized block heights using zs_contains()
* adds known_utxos field to SentHashes
* updates comment on SentHashes.add method
* Apply suggestions from code review
Co-authored-by: teor <teor@riseup.net>
* return early when there's a duplicate hash in QueuedBlocks.queue instead of panicking
* Make finalized UTXOs near the final checkpoint available for full block verification
* Replace a checkpoint height literal with the actual config
* Update mainnet and testnet checkpoints - 7 October 2022
* Fix some state service init arguments
* Allow more lookahead in the downloader, but less lookahead in the syncer
* Add the latest config to the tests, and fix the latest config check
* Increase the number of finalized blocks checked for non-finalized block UTXO spends
* fix(log): reduce verbose logs for block commits (#5348)
* Remove some verbose block write channel logs
* Only warn about tracing endpoint if the address is actually set
* Use CloneError instead of formatting a non-cloneable error
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* Increase block verify timeout
* Work around a known block timeout bug by using a shorter timeout
Co-authored-by: teor <teor@riseup.net>
Co-authored-by: Marek <mail@marek.onl>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-10-11 12:25:45 -07:00
|
|
|
// The timing of verification logs are unreliable, so we've disabled this check for now.
|
2022-09-28 09:09:56 -07:00
|
|
|
//
|
|
|
|
// TODO: when lightwalletd starts returning transactions again:
|
|
|
|
// re-enable this check, find a better way to check, or delete this commented-out check
|
|
|
|
//
|
|
|
|
//tracing::info!("waiting for mempool to verify some transactions...");
|
|
|
|
//zebrad.expect_stdout_line_matches("sending mempool transaction broadcast")?;
|
2022-09-06 06:32:33 -07:00
|
|
|
|
|
|
|
tracing::info!("calling GetMempoolTx gRPC to fetch transactions...");
|
|
|
|
let mut transactions_stream = rpc_client
|
|
|
|
.get_mempool_tx(Exclude { txid: vec![] })
|
|
|
|
.await?
|
|
|
|
.into_inner();
|
|
|
|
|
|
|
|
// We'd like to check that lightwalletd queries the mempool, but it looks like it doesn't do it after each GetMempoolTx request.
|
|
|
|
//zebrad.expect_stdout_line_matches("answered mempool request req=TransactionIds")?;
|
|
|
|
|
|
|
|
// GetMempoolTx: make sure at least one of the transactions were inserted into the mempool.
|
|
|
|
let mut counter = 0;
|
|
|
|
while let Some(tx) = transactions_stream.message().await? {
|
|
|
|
let hash: [u8; 32] = tx.hash.clone().try_into().expect("hash is correct length");
|
|
|
|
let hash = transaction::Hash::from_bytes_in_display_order(&hash);
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
transaction_hashes.contains(&hash),
|
|
|
|
"unexpected transaction {hash:?}\n\
|
|
|
|
in isolated mempool: {tx:?}",
|
|
|
|
);
|
|
|
|
|
|
|
|
counter += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This RPC has temporarily been disabled in `lightwalletd`:
|
|
|
|
// https://github.com/adityapk00/lightwalletd/blob/b563f765f620e38f482954cd8ff3cc6d17cf2fa7/frontend/service.go#L529-L531
|
|
|
|
//
|
|
|
|
// TODO: re-enable it when lightwalletd starts returning transactions again.
|
|
|
|
//assert!(counter >= 1, "all transactions from future blocks failed to send to an isolated mempool");
|
|
|
|
assert_eq!(
|
|
|
|
counter, 0,
|
|
|
|
"developers: update this test for lightwalletd sending transactions"
|
|
|
|
);
|
|
|
|
|
|
|
|
// GetMempoolTx: make sure at least one of the transactions were inserted into the mempool.
|
|
|
|
tracing::info!("calling GetMempoolStream gRPC to fetch transactions...");
|
|
|
|
let mut transaction_stream = rpc_client.get_mempool_stream(Empty {}).await?.into_inner();
|
|
|
|
|
|
|
|
let mut counter = 0;
|
|
|
|
while let Some(_tx) = transaction_stream.message().await? {
|
|
|
|
// TODO: check tx.data or tx.height here?
|
|
|
|
|
|
|
|
counter += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This RPC has temporarily been disabled in `lightwalletd`:
|
|
|
|
// https://github.com/adityapk00/lightwalletd/blob/b563f765f620e38f482954cd8ff3cc6d17cf2fa7/frontend/service.go#L515-L517
|
|
|
|
//
|
|
|
|
// TODO: re-enable it when lightwalletd starts streaming transactions again.
|
|
|
|
//assert!(counter >= 1, "all transactions from future blocks failed to send to an isolated mempool");
|
|
|
|
assert_eq!(
|
|
|
|
counter, 0,
|
|
|
|
"developers: update this test for lightwalletd sending transactions"
|
|
|
|
);
|
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-11-09 19:40:21 -08:00
|
|
|
/// Loads transactions from a few block(s) after the chain tip of the cached state.
|
2022-04-27 16:06:11 -07:00
|
|
|
///
|
2022-11-09 19:40:21 -08:00
|
|
|
/// Returns a list of non-coinbase transactions from blocks that have not been finalized to disk
|
|
|
|
/// in the `ZEBRA_CACHED_STATE_DIR`.
|
2022-04-27 16:06:11 -07:00
|
|
|
///
|
2022-11-09 19:40:21 -08:00
|
|
|
/// ## Panics
|
2022-04-27 16:06:11 -07:00
|
|
|
///
|
2022-11-09 19:40:21 -08:00
|
|
|
/// If the provided `test_type` doesn't need an rpc server and cached state
|
2022-08-28 10:08:43 -07:00
|
|
|
#[tracing::instrument]
|
2022-11-09 19:40:21 -08:00
|
|
|
async fn load_transactions_from_future_blocks(
|
2022-04-27 16:06:11 -07:00
|
|
|
network: Network,
|
2022-11-09 19:40:21 -08:00
|
|
|
test_type: TestType,
|
|
|
|
test_name: &str,
|
2022-04-27 16:06:11 -07:00
|
|
|
) -> Result<Vec<Arc<Transaction>>> {
|
2022-11-09 19:40:21 -08:00
|
|
|
let transactions = get_future_blocks(network, test_type, test_name, MAX_NUM_FUTURE_BLOCKS)
|
|
|
|
.await?
|
|
|
|
.into_iter()
|
|
|
|
.flat_map(|block| block.transactions)
|
|
|
|
.filter(|transaction| !transaction.is_coinbase())
|
|
|
|
.take(max_sent_transactions())
|
|
|
|
.collect();
|
2022-09-06 06:32:33 -07:00
|
|
|
|
2022-04-27 16:06:11 -07:00
|
|
|
Ok(transactions)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Prepare a request to send to lightwalletd that contains a transaction to be sent.
|
|
|
|
fn prepare_send_transaction_request(transaction: Arc<Transaction>) -> wallet_grpc::RawTransaction {
|
|
|
|
let transaction_bytes = transaction.zcash_serialize_to_vec().unwrap();
|
|
|
|
|
|
|
|
wallet_grpc::RawTransaction {
|
|
|
|
data: transaction_bytes,
|
|
|
|
height: -1,
|
|
|
|
}
|
|
|
|
}
|