Fix format used to store transactions in sled (#1238)
## Motivation While working on the block locator fix PR together with Henry we noticed that we'd accidentally serialized entire transactions in `tx_by_hash`, instead of serializing just the height of the block and the index of the transaction within the block, as described by the original RFC. ## Solution We've fixed it by adding a `TransactionLocation` new type, which handles the sled format traits. We've removed the sled format impls for `Transaction` to prevent inserting the wrong data in the future. Finally we've bumped the database format to reflect the change in the format on the disk and its incompatibility with previous versions.
This commit is contained in:
parent
adbd338d6d
commit
1b7c57371d
|
@ -14,4 +14,4 @@ pub const MIN_TRASPARENT_COINBASE_MATURITY: block::Height = block::Height(100);
|
|||
pub const MAX_BLOCK_REORG_HEIGHT: block::Height =
|
||||
block::Height(MIN_TRASPARENT_COINBASE_MATURITY.0 - 1);
|
||||
|
||||
pub const SLED_FORMAT_VERSION: u32 = 0;
|
||||
pub const SLED_FORMAT_VERSION: u32 = 1;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! The primary implementation of the `zebra_state::Service` built upon sled
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use std::{collections::HashMap, convert::TryInto, sync::Arc};
|
||||
|
||||
use tracing::trace;
|
||||
use zebra_chain::transparent;
|
||||
|
@ -15,6 +15,8 @@ mod sled_format;
|
|||
|
||||
use sled_format::{FromSled, IntoSled, SledDeserialize, SledSerialize};
|
||||
|
||||
use self::sled_format::TransactionLocation;
|
||||
|
||||
/// The finalized part of the chain state, stored in sled.
|
||||
///
|
||||
/// This structure has two categories of methods:
|
||||
|
@ -250,9 +252,15 @@ impl FinalizedState {
|
|||
}
|
||||
|
||||
// Index each transaction
|
||||
for transaction in block.transactions.iter() {
|
||||
for (transaction_index, transaction) in block.transactions.iter().enumerate() {
|
||||
let transaction_hash = transaction.hash();
|
||||
tx_by_hash.zs_insert(transaction_hash, transaction)?;
|
||||
let transaction_location = TransactionLocation {
|
||||
height,
|
||||
index: transaction_index
|
||||
.try_into()
|
||||
.expect("no more than 4 billion transactions per block"),
|
||||
};
|
||||
tx_by_hash.zs_insert(transaction_hash, transaction_location)?;
|
||||
|
||||
// Mark all transparent inputs as spent
|
||||
for input in transaction.inputs() {
|
||||
|
|
|
@ -6,13 +6,16 @@ use zebra_chain::{
|
|||
block::Block,
|
||||
sapling,
|
||||
serialization::{ZcashDeserialize, ZcashSerialize},
|
||||
sprout, transaction,
|
||||
transaction::Transaction,
|
||||
transparent,
|
||||
sprout, transaction, transparent,
|
||||
};
|
||||
|
||||
use crate::BoxError;
|
||||
|
||||
pub struct TransactionLocation {
|
||||
pub height: block::Height,
|
||||
pub index: u32,
|
||||
}
|
||||
|
||||
// Helper trait for defining the exact format used to interact with sled per
|
||||
// type.
|
||||
pub trait IntoSled {
|
||||
|
@ -54,16 +57,42 @@ impl FromSled for Arc<Block> {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSled for &Arc<Transaction> {
|
||||
type Bytes = Vec<u8>;
|
||||
impl IntoSled for TransactionLocation {
|
||||
type Bytes = [u8; 8];
|
||||
|
||||
fn as_bytes(&self) -> Self::Bytes {
|
||||
self.zcash_serialize_to_vec()
|
||||
.expect("serialization to vec doesn't fail")
|
||||
let height_bytes = self.height.0.to_be_bytes();
|
||||
let index_bytes = self.index.to_be_bytes();
|
||||
|
||||
let mut bytes = [0; 8];
|
||||
|
||||
bytes[0..4].copy_from_slice(&height_bytes);
|
||||
bytes[4..8].copy_from_slice(&index_bytes);
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
fn into_ivec(self) -> sled::IVec {
|
||||
self.as_bytes().into()
|
||||
self.as_bytes().as_ref().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSled for TransactionLocation {
|
||||
fn from_ivec(sled_bytes: sled::IVec) -> Result<Self, BoxError> {
|
||||
let height = {
|
||||
let mut bytes = [0; 4];
|
||||
bytes.copy_from_slice(&sled_bytes[0..4]);
|
||||
let height = u32::from_be_bytes(bytes);
|
||||
block::Height(height)
|
||||
};
|
||||
|
||||
let index = {
|
||||
let mut bytes = [0; 4];
|
||||
bytes.copy_from_slice(&sled_bytes[4..8]);
|
||||
u32::from_be_bytes(bytes)
|
||||
};
|
||||
|
||||
Ok(TransactionLocation { height, index })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue