Merge pull request #870 from zcash/fix-get_transaction
zcash_client_sqlite: Fix `WalletDb::get_transaction` for unmined txs
This commit is contained in:
commit
4cb36d3d9d
|
@ -28,6 +28,9 @@ and this library adheres to Rust's notion of
|
||||||
- Fixed an off-by-one error in the `BlockSource` implementation for the SQLite-backed
|
- Fixed an off-by-one error in the `BlockSource` implementation for the SQLite-backed
|
||||||
`BlockDb` block database which could result in blocks being skipped at the start of
|
`BlockDb` block database which could result in blocks being skipped at the start of
|
||||||
scan ranges.
|
scan ranges.
|
||||||
|
- `WalletDb::get_transaction` no longer returns an error when called on a transaction
|
||||||
|
that has not yet been mined, unless the transaction's consensus branch ID cannot be
|
||||||
|
determined by other means.
|
||||||
|
|
||||||
## [0.7.1] - 2023-05-17
|
## [0.7.1] - 2023-05-17
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::io::{self, Cursor};
|
use std::io::{self, Cursor};
|
||||||
use zcash_client_backend::data_api::ShieldedProtocol;
|
use zcash_client_backend::data_api::ShieldedProtocol;
|
||||||
|
use zcash_primitives::transaction::TransactionData;
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
|
@ -491,18 +492,65 @@ pub(crate) fn get_transaction<P: Parameters>(
|
||||||
params: &P,
|
params: &P,
|
||||||
id_tx: i64,
|
id_tx: i64,
|
||||||
) -> Result<Transaction, SqliteClientError> {
|
) -> Result<Transaction, SqliteClientError> {
|
||||||
let (tx_bytes, block_height): (Vec<_>, BlockHeight) = conn.query_row(
|
let (tx_bytes, block_height, expiry_height): (
|
||||||
"SELECT raw, block FROM transactions
|
Vec<_>,
|
||||||
|
Option<BlockHeight>,
|
||||||
|
Option<BlockHeight>,
|
||||||
|
) = conn.query_row(
|
||||||
|
"SELECT raw, block, expiry_height FROM transactions
|
||||||
WHERE id_tx = ?",
|
WHERE id_tx = ?",
|
||||||
[id_tx],
|
[id_tx],
|
||||||
|row| {
|
|row| {
|
||||||
let h: u32 = row.get(1)?;
|
let h: Option<u32> = row.get(1)?;
|
||||||
Ok((row.get(0)?, BlockHeight::from(h)))
|
let expiry: Option<u32> = row.get(2)?;
|
||||||
|
Ok((
|
||||||
|
row.get(0)?,
|
||||||
|
h.map(BlockHeight::from),
|
||||||
|
expiry.map(BlockHeight::from),
|
||||||
|
))
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Transaction::read(&tx_bytes[..], BranchId::for_height(params, block_height))
|
// We need to provide a consensus branch ID so that pre-v5 `Transaction` structs
|
||||||
|
// (which don't commit directly to one) can store it internally.
|
||||||
|
// - If the transaction is mined, we use the block height to get the correct one.
|
||||||
|
// - If the transaction is unmined and has a cached non-zero expiry height, we use
|
||||||
|
// that (relying on the invariant that a transaction can't be mined across a network
|
||||||
|
// upgrade boundary, so the expiry height must be in the same epoch).
|
||||||
|
// - Otherwise, we use a placeholder for the initial transaction parse (as the
|
||||||
|
// consensus branch ID is not used there), and then either use its non-zero expiry
|
||||||
|
// height or return an error.
|
||||||
|
if let Some(height) =
|
||||||
|
block_height.or_else(|| expiry_height.filter(|h| h > &BlockHeight::from(0)))
|
||||||
|
{
|
||||||
|
Transaction::read(&tx_bytes[..], BranchId::for_height(params, height))
|
||||||
.map_err(SqliteClientError::from)
|
.map_err(SqliteClientError::from)
|
||||||
|
} else {
|
||||||
|
let tx_data = Transaction::read(&tx_bytes[..], BranchId::Sprout)
|
||||||
|
.map_err(SqliteClientError::from)?
|
||||||
|
.into_data();
|
||||||
|
|
||||||
|
let expiry_height = tx_data.expiry_height();
|
||||||
|
if expiry_height > BlockHeight::from(0) {
|
||||||
|
TransactionData::from_parts(
|
||||||
|
tx_data.version(),
|
||||||
|
BranchId::for_height(params, expiry_height),
|
||||||
|
tx_data.lock_time(),
|
||||||
|
expiry_height,
|
||||||
|
tx_data.transparent_bundle().cloned(),
|
||||||
|
tx_data.sprout_bundle().cloned(),
|
||||||
|
tx_data.sapling_bundle().cloned(),
|
||||||
|
tx_data.orchard_bundle().cloned(),
|
||||||
|
)
|
||||||
|
.freeze()
|
||||||
|
.map_err(SqliteClientError::from)
|
||||||
|
} else {
|
||||||
|
Err(SqliteClientError::CorruptedData(
|
||||||
|
"Consensus branch ID not known, cannot parse this transaction until it is mined"
|
||||||
|
.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the memo for a sent note.
|
/// Returns the memo for a sent note.
|
||||||
|
|
Loading…
Reference in New Issue