diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7b50047bc79..d53cdbc8b00 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -39,7 +39,6 @@ /docker/ @ZcashFoundation/devops-reviewers cloudbuild.yaml @ZcashFoundation/devops-reviewers codecov.yml @ZcashFoundation/devops-reviewers -.dockerignore @ZcashFoundation/devops-reviewers firebase.json @ZcashFoundation/devops-reviewers katex-header.html @ZcashFoundation/devops-reviewers diff --git a/.github/workflows/test-full-sync.yml b/.github/workflows/test-full-sync.yml index 455765b0f68..8c301c8cbb8 100644 --- a/.github/workflows/test-full-sync.yml +++ b/.github/workflows/test-full-sync.yml @@ -227,6 +227,16 @@ jobs: --ssh-flag="-o ServerAliveInterval=5" \ --command="docker logs --follow ${{ env.CONTAINER_NAME }}" + EXIT_CODE=$(\ + gcloud compute ssh \ + full-sync-${{ env.GITHUB_REF_SLUG_URL }}-${{ env.GITHUB_SHA_SHORT }} \ + --zone ${{ env.ZONE }} \ + --quiet \ + --ssh-flag="-o ServerAliveInterval=5" \ + --command="docker wait ${{ env.CONTAINER_NAME }}") + + exit ${EXIT_CODE} + - name: Get sync height from logs run: | SYNC_HEIGHT="" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 492f5f8df21..baf23a3f4ca 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -235,7 +235,7 @@ jobs: # this job will take a few hours, because it will do a full rebuild. - name: Get specific changed files id: changed-files-specific - uses: tj-actions/changed-files@v18.6 + uses: tj-actions/changed-files@v18.7 with: files: | zebra-state/**/constants.rs @@ -318,7 +318,7 @@ jobs: echo "::set-output name=zebra_container::$CONTAINER_NAME" sleep 60 - - name: Regenerate stateful disks logs + - name: Regenerate stateful disks id: sync-to-checkpoint if: ${{ steps.create-instance.outcome == 'success' }} run: | @@ -328,6 +328,16 @@ jobs: --quiet \ --ssh-flag="-o ServerAliveInterval=5" \ --command="docker logs --follow ${{ env.ZEBRA_CONTAINER }}" + + EXIT_CODE=$(\ + gcloud compute ssh \ + regenerate-disk-${{ env.GITHUB_REF_SLUG_URL }}-${{ env.GITHUB_SHA_SHORT }} \ + --zone ${{ env.ZONE }} \ + --quiet \ + --ssh-flag="-o ServerAliveInterval=5" \ + --command="docker wait ${{ env.ZEBRA_CONTAINER }}") + + exit ${EXIT_CODE} env: ZEBRA_CONTAINER: ${{ steps.get-container-name.outputs.zebra_container }} @@ -449,7 +459,7 @@ jobs: echo "::set-output name=zebra_container::$CONTAINER_NAME" sleep 60 - - name: Sync past mandatory checkpoint logs + - name: Sync past mandatory checkpoint id: sync-past-checkpoint run: | gcloud compute ssh \ @@ -458,6 +468,16 @@ jobs: --quiet \ --ssh-flag="-o ServerAliveInterval=5" \ --command="docker logs --follow ${{ env.ZEBRA_CONTAINER }}" + + EXIT_CODE=$(\ + gcloud compute ssh \ + sync-checkpoint-${{ env.GITHUB_REF_SLUG_URL }}-${{ env.GITHUB_SHA_SHORT }} \ + --zone ${{ env.ZONE }} \ + --quiet \ + --ssh-flag="-o ServerAliveInterval=5" \ + --command="docker wait ${{ env.ZEBRA_CONTAINER }}") + + exit ${EXIT_CODE} env: ZEBRA_CONTAINER: ${{ steps.get-container-name.outputs.zebra_container }} diff --git a/Cargo.lock b/Cargo.lock index f1d155e3ecb..7cc4dbed46d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3495,9 +3495,9 @@ dependencies = [ [[package]] name = "rlimit" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "347703a5ae47adf1e693144157be231dde38c72bd485925cae7407ad3e52480b" +checksum = "f7278a1ec8bfd4a4e07515c589f5ff7b309a373f987393aef44813d9dcf87aa3" dependencies = [ "libc", ] diff --git a/.dockerignore b/docker/.dockerignore similarity index 100% rename from .dockerignore rename to docker/.dockerignore diff --git a/zebra-chain/src/transparent/address.rs b/zebra-chain/src/transparent/address.rs index e4a2ad1bb1e..fda1bb28a4a 100644 --- a/zebra-chain/src/transparent/address.rs +++ b/zebra-chain/src/transparent/address.rs @@ -6,15 +6,14 @@ use ripemd160::{Digest, Ripemd160}; use secp256k1::PublicKey; use sha2::Sha256; -#[cfg(test)] -use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; - use crate::{ parameters::Network, serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, + transparent::Script, }; -use super::Script; +#[cfg(test)] +use proptest::prelude::*; /// Magic numbers used to identify what networks Transparent Addresses /// are associated with. @@ -41,7 +40,11 @@ mod magics { /// to a Bitcoin address just by removing the "t".) /// /// https://zips.z.cash/protocol/protocol.pdf#transparentaddrencoding -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr( + any(test, feature = "proptest-impl"), + derive(proptest_derive::Arbitrary) +)] pub enum Address { /// P2SH (Pay to Script Hash) addresses PayToScriptHash { @@ -208,6 +211,26 @@ impl Address { } } + /// Returns the network for this address. + pub fn network(&self) -> Network { + match *self { + Address::PayToScriptHash { network, .. } => network, + Address::PayToPublicKeyHash { network, .. } => network, + } + } + + /// Returns the hash bytes for this address, regardless of the address type. + /// + /// # Correctness + /// + /// Use [`ZcashSerialize`] and [`ZcashDeserialize`] for consensus-critical serialization. + pub fn hash_bytes(&self) -> [u8; 20] { + match *self { + Address::PayToScriptHash { script_hash, .. } => script_hash, + Address::PayToPublicKeyHash { pub_key_hash, .. } => pub_key_hash, + } + } + /// A hash of a transparent address payload, as used in /// transparent pay-to-script-hash and pay-to-publickey-hash /// addresses. @@ -224,46 +247,6 @@ impl Address { } } -#[cfg(test)] -impl Address { - fn p2pkh_strategy() -> impl Strategy { - (any::(), vec(any::(), 20)) - .prop_map(|(network, payload_bytes)| { - let mut bytes = [0; 20]; - bytes.copy_from_slice(payload_bytes.as_slice()); - Self::PayToPublicKeyHash { - network, - pub_key_hash: bytes, - } - }) - .boxed() - } - - fn p2sh_strategy() -> impl Strategy { - (any::(), vec(any::(), 20)) - .prop_map(|(network, payload_bytes)| { - let mut bytes = [0; 20]; - bytes.copy_from_slice(payload_bytes.as_slice()); - Self::PayToScriptHash { - network, - script_hash: bytes, - } - }) - .boxed() - } -} - -#[cfg(test)] -impl Arbitrary for Address { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - prop_oneof![Self::p2pkh_strategy(), Self::p2sh_strategy(),].boxed() - } - - type Strategy = BoxedStrategy; -} - #[cfg(test)] mod tests { diff --git a/zebra-chain/src/transparent/utxo.rs b/zebra-chain/src/transparent/utxo.rs index 4f836159acd..4e27fc3da36 100644 --- a/zebra-chain/src/transparent/utxo.rs +++ b/zebra-chain/src/transparent/utxo.rs @@ -17,6 +17,10 @@ use crate::{ pub struct Utxo { /// The output itself. pub output: transparent::Output, + + // TODO: replace the height and from_coinbase fields with OutputLocation, + // and provide lookup/calculation methods for height and from_coinbase + // /// The height at which the output was created. pub height: block::Height, /// Whether the output originated in a coinbase transaction. @@ -35,6 +39,8 @@ pub struct Utxo { any(test, feature = "proptest-impl"), derive(proptest_derive::Arbitrary) )] +// +// TODO: after modifying UTXO to contain an OutputLocation, replace this type with UTXO pub struct OrderedUtxo { /// An unspent transaction output. pub utxo: Utxo, diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index df8ba0e95c9..767b8c31e9b 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -15,13 +15,14 @@ dirs = "4.0.0" displaydoc = "0.2.3" futures = "0.3.21" hex = "0.4.3" +itertools = "0.10.3" lazy_static = "1.4.0" metrics = "0.17.1" mset = "0.1.0" proptest = { version = "0.10.1", optional = true } proptest-derive = { version = "0.3.0", optional = true } regex = "1.5.5" -rlimit = "0.7.0" +rlimit = "0.8.3" rocksdb = "0.18.0" serde = { version = "1.0.136", features = ["serde_derive"] } tempfile = "3.3.0" @@ -35,7 +36,6 @@ zebra-test = { path = "../zebra-test/", optional = true } [dev-dependencies] color-eyre = "0.6.0" -itertools = "0.10.3" once_cell = "1.10.0" spandoc = "0.2.1" diff --git a/zebra-state/src/constants.rs b/zebra-state/src/constants.rs index 149a4279be8..8193857f21a 100644 --- a/zebra-state/src/constants.rs +++ b/zebra-state/src/constants.rs @@ -18,7 +18,7 @@ pub use zebra_chain::transparent::MIN_TRANSPARENT_COINBASE_MATURITY; pub const MAX_BLOCK_REORG_HEIGHT: u32 = MIN_TRANSPARENT_COINBASE_MATURITY - 1; /// The database format version, incremented each time the database format changes. -pub const DATABASE_FORMAT_VERSION: u32 = 14; +pub const DATABASE_FORMAT_VERSION: u32 = 18; /// The maximum number of blocks to check for NU5 transactions, /// before we assume we are on a pre-NU5 legacy chain. diff --git a/zebra-state/src/request.rs b/zebra-state/src/request.rs index 985f6932e43..3894cd4cede 100644 --- a/zebra-state/src/request.rs +++ b/zebra-state/src/request.rs @@ -10,8 +10,8 @@ use zebra_chain::{ value_balance::{ValueBalance, ValueBalanceError}, }; -// Allow *only* this unused import, so that rustdoc link resolution -// will work with inline links. +/// Allow *only* this unused import, so that rustdoc link resolution +/// will work with inline links. #[allow(unused_imports)] use crate::Response; @@ -119,10 +119,6 @@ pub struct FinalizedBlock { /// New transparent outputs created in this block, indexed by /// [`Outpoint`](transparent::Outpoint). /// - /// Each output is tagged with its transaction index in the block. - /// (The outputs of earlier transactions in a block can be spent by later - /// transactions.) - /// /// Note: although these transparent outputs are newly created, they may not /// be unspent, since a later transaction in a block can spend outputs of an /// earlier transaction. diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 0a342d9ca63..ca1f540cafe 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -497,7 +497,12 @@ impl StateService { .or_else(|| self.disk.db().height(hash)) } - /// Return the [`Utxo`] pointed to by `outpoint` if it exists in any chain. + /// Return the [`Utxo`] pointed to by `outpoint`, if it exists in any chain, + /// or in any pending block. + /// + /// Some of the returned UTXOs may be invalid, because: + /// - they are not in the best chain, or + /// - their block fails contextual validation. pub fn any_utxo(&self, outpoint: &transparent::OutPoint) -> Option { self.mem .any_utxo(outpoint) diff --git a/zebra-state/src/service/finalized_state/disk_db.rs b/zebra-state/src/service/finalized_state/disk_db.rs index 4a0351968a1..d336a464980 100644 --- a/zebra-state/src/service/finalized_state/disk_db.rs +++ b/zebra-state/src/service/finalized_state/disk_db.rs @@ -23,14 +23,40 @@ use crate::{ #[cfg(any(test, feature = "proptest-impl"))] mod tests; +/// The [`rocksdb::ThreadMode`] used by the database. +pub type DBThreadMode = rocksdb::SingleThreaded; + +/// The [`rocksdb`] database type, including thread mode. +/// +/// Also the [`rocksdb::DBAccess`] used by database iterators. +pub type DB = rocksdb::DBWithThreadMode; + /// Wrapper struct to ensure low-level database access goes through the correct API. +/// +/// # Correctness +/// +/// Reading transactions from the database using RocksDB iterators causes hangs. +/// But creating iterators and reading the tip height works fine. +/// +/// So these hangs are probably caused by holding column family locks to read: +/// - multiple values, or +/// - large values. +/// +/// This bug might be fixed by moving database operations to blocking threads (#2188), +/// so that they don't block the tokio executor. +/// (Or it might be fixed by future RocksDB upgrades.) #[derive(Clone, Debug)] pub struct DiskDb { /// The shared inner RocksDB database. /// /// RocksDB allows reads and writes via a shared reference. - /// Only column family changes and [`Drop`] require exclusive access. - db: Arc, + /// + /// In [`SingleThreaded`](rocksdb::SingleThreaded) mode, + /// column family changes and [`Drop`] require exclusive access. + /// + /// In [`MultiThreaded`](rocksdb::MultiThreaded) mode, + /// only [`Drop`] requires exclusive access. + db: Arc, /// The configured temporary database setting. /// @@ -42,31 +68,43 @@ pub struct DiskDb { /// /// [`rocksdb::WriteBatch`] is a batched set of database updates, /// which must be written to the database using `DiskDb::write(batch)`. +// +// TODO: move DiskDb, FinalizedBlock, and the source String into this struct, +// (DiskDb can be cloned), +// and make them accessible via read-only methods #[must_use = "batches must be written to the database"] pub struct DiskWriteBatch { /// The inner RocksDB write batch. batch: rocksdb::WriteBatch, + + /// The configured network. + network: Network, } /// Helper trait for inserting (Key, Value) pairs into rocksdb with a consistently /// defined format +// +// TODO: just implement these methods directly on WriteBatch pub trait WriteDisk { /// Serialize and insert the given key and value into a rocksdb column family, /// overwriting any existing `value` for `key`. - fn zs_insert(&mut self, cf: &rocksdb::ColumnFamily, key: K, value: V) + fn zs_insert(&mut self, cf: &C, key: K, value: V) where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk + Debug, V: IntoDisk; /// Remove the given key form rocksdb column family if it exists. - fn zs_delete(&mut self, cf: &rocksdb::ColumnFamily, key: K) + fn zs_delete(&mut self, cf: &C, key: K) where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk + Debug; } impl WriteDisk for DiskWriteBatch { - fn zs_insert(&mut self, cf: &rocksdb::ColumnFamily, key: K, value: V) + fn zs_insert(&mut self, cf: &C, key: K, value: V) where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk + Debug, V: IntoDisk, { @@ -75,8 +113,9 @@ impl WriteDisk for DiskWriteBatch { self.batch.put_cf(cf, key_bytes, value_bytes); } - fn zs_delete(&mut self, cf: &rocksdb::ColumnFamily, key: K) + fn zs_delete(&mut self, cf: &C, key: K) where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk + Debug, { let key_bytes = key.as_bytes(); @@ -86,16 +125,65 @@ impl WriteDisk for DiskWriteBatch { /// Helper trait for retrieving values from rocksdb column familys with a consistently /// defined format +// +// TODO: just implement these methods directly on DiskDb pub trait ReadDisk { + /// Returns true if a rocksdb column family `cf` does not contain any entries. + fn zs_is_empty(&self, cf: &C) -> bool + where + C: rocksdb::AsColumnFamilyRef; + /// Returns the value for `key` in the rocksdb column family `cf`, if present. - fn zs_get(&self, cf: &rocksdb::ColumnFamily, key: &K) -> Option + fn zs_get(&self, cf: &C, key: &K) -> Option where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk, V: FromDisk; /// Check if a rocksdb column family `cf` contains the serialized form of `key`. - fn zs_contains(&self, cf: &rocksdb::ColumnFamily, key: &K) -> bool + fn zs_contains(&self, cf: &C, key: &K) -> bool + where + C: rocksdb::AsColumnFamilyRef, + K: IntoDisk; + + /// Returns the lowest key in `cf`, and the corresponding value. + /// + /// Returns `None` if the column family is empty. + fn zs_first_key_value(&self, cf: &C) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef; + + /// Returns the highest key in `cf`, and the corresponding value. + /// + /// Returns `None` if the column family is empty. + fn zs_last_key_value(&self, cf: &C) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef; + + /// Returns the first key greater than or equal to `lower_bound` in `cf`, + /// and the corresponding value. + /// + /// Returns `None` if there are no keys greater than or equal to `lower_bound`. + fn zs_next_key_value_from( + &self, + cf: &C, + lower_bound: &K, + ) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef, + K: IntoDisk; + + /// Returns the first key less than or equal to `upper_bound` in `cf`, + /// and the corresponding value. + /// + /// Returns `None` if there are no keys less than or equal to `upper_bound`. + fn zs_prev_key_value_back_from( + &self, + cf: &C, + upper_bound: &K, + ) -> Option<(Box<[u8]>, Box<[u8]>)> where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk; } @@ -116,8 +204,22 @@ impl PartialEq for DiskDb { impl Eq for DiskDb {} impl ReadDisk for DiskDb { - fn zs_get(&self, cf: &rocksdb::ColumnFamily, key: &K) -> Option + fn zs_is_empty(&self, cf: &C) -> bool + where + C: rocksdb::AsColumnFamilyRef, + { + // Empty column families return invalid forward iterators. + // + // Checking iterator validity does not seem to cause database hangs. + !self + .db + .iterator_cf(cf, rocksdb::IteratorMode::Start) + .valid() + } + + fn zs_get(&self, cf: &C, key: &K) -> Option where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk, V: FromDisk, { @@ -136,8 +238,9 @@ impl ReadDisk for DiskDb { value_bytes.map(V::from_bytes) } - fn zs_contains(&self, cf: &rocksdb::ColumnFamily, key: &K) -> bool + fn zs_contains(&self, cf: &C, key: &K) -> bool where + C: rocksdb::AsColumnFamilyRef, K: IntoDisk, { let key_bytes = key.as_bytes(); @@ -151,14 +254,75 @@ impl ReadDisk for DiskDb { .expect("expected that disk errors would not occur") .is_some() } + + fn zs_first_key_value(&self, cf: &C) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef, + { + // Reading individual values from iterators does not seem to cause database hangs. + self.db.iterator_cf(cf, rocksdb::IteratorMode::Start).next() + } + + fn zs_last_key_value(&self, cf: &C) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef, + { + // Reading individual values from iterators does not seem to cause database hangs. + self.db.iterator_cf(cf, rocksdb::IteratorMode::End).next() + } + + fn zs_next_key_value_from( + &self, + cf: &C, + lower_bound: &K, + ) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef, + K: IntoDisk, + { + let lower_bound = lower_bound.as_bytes(); + let from = rocksdb::IteratorMode::From(lower_bound.as_ref(), rocksdb::Direction::Forward); + + // Reading individual values from iterators does not seem to cause database hangs. + self.db.iterator_cf(cf, from).next() + } + + fn zs_prev_key_value_back_from( + &self, + cf: &C, + upper_bound: &K, + ) -> Option<(Box<[u8]>, Box<[u8]>)> + where + C: rocksdb::AsColumnFamilyRef, + K: IntoDisk, + { + let upper_bound = upper_bound.as_bytes(); + let from = rocksdb::IteratorMode::From(upper_bound.as_ref(), rocksdb::Direction::Reverse); + + // Reading individual values from iterators does not seem to cause database hangs. + self.db.iterator_cf(cf, from).next() + } } impl DiskWriteBatch { - pub fn new() -> Self { + /// Creates and returns a new transactional batch write. + /// + /// # Correctness + /// + /// Each block must be written to the state inside a batch, so that: + /// - concurrent `ReadStateService` queries don't see half-written blocks, and + /// - if Zebra calls `exit`, panics, or crashes, half-written blocks are rolled back. + pub fn new(network: Network) -> Self { DiskWriteBatch { batch: rocksdb::WriteBatch::default(), + network, } } + + /// Returns the configured network for this write batch. + pub fn network(&self) -> Network { + self.network + } } impl DiskDb { @@ -182,6 +346,11 @@ impl DiskDb { /// stdio (3), and other OS facilities (2+). const RESERVED_FILE_COUNT: u64 = 48; + /// The size of the database memtable RAM cache in megabytes. + /// + /// https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ#configuration-and-tuning + const MEMTABLE_RAM_CACHE_MEGABYTES: usize = 128; + /// Opens or creates the database at `config.path` for `network`, /// and returns a shared low-level database wrapper. pub fn new(config: &Config, network: Network) -> DiskDb { @@ -189,32 +358,53 @@ impl DiskDb { let db_options = DiskDb::options(); let column_families = vec![ + // Blocks + // TODO: rename to block_header_by_height (#3151) + rocksdb::ColumnFamilyDescriptor::new("block_by_height", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new("hash_by_height", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new("height_by_hash", db_options.clone()), - rocksdb::ColumnFamilyDescriptor::new("block_by_height", db_options.clone()), + // Transactions + rocksdb::ColumnFamilyDescriptor::new("tx_by_loc", db_options.clone()), + rocksdb::ColumnFamilyDescriptor::new("hash_by_tx_loc", db_options.clone()), + // TODO: rename to tx_loc_by_hash (#3950) rocksdb::ColumnFamilyDescriptor::new("tx_by_hash", db_options.clone()), + // Transparent + rocksdb::ColumnFamilyDescriptor::new("balance_by_transparent_addr", db_options.clone()), + // TODO: #3951 + //rocksdb::ColumnFamilyDescriptor::new("tx_by_transparent_addr_loc", db_options.clone()), + // TODO: rename to utxo_by_out_loc (#3952) rocksdb::ColumnFamilyDescriptor::new("utxo_by_outpoint", db_options.clone()), + // TODO: #3953 + //rocksdb::ColumnFamilyDescriptor::new("utxo_by_transparent_addr_loc", db_options.clone()), + // Sprout rocksdb::ColumnFamilyDescriptor::new("sprout_nullifiers", db_options.clone()), - rocksdb::ColumnFamilyDescriptor::new("sapling_nullifiers", db_options.clone()), - rocksdb::ColumnFamilyDescriptor::new("orchard_nullifiers", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new("sprout_anchors", db_options.clone()), - rocksdb::ColumnFamilyDescriptor::new("sapling_anchors", db_options.clone()), - rocksdb::ColumnFamilyDescriptor::new("orchard_anchors", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new("sprout_note_commitment_tree", db_options.clone()), + // Sapling + rocksdb::ColumnFamilyDescriptor::new("sapling_nullifiers", db_options.clone()), + rocksdb::ColumnFamilyDescriptor::new("sapling_anchors", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new( "sapling_note_commitment_tree", db_options.clone(), ), + // Orchard + rocksdb::ColumnFamilyDescriptor::new("orchard_nullifiers", db_options.clone()), + rocksdb::ColumnFamilyDescriptor::new("orchard_anchors", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new( "orchard_note_commitment_tree", db_options.clone(), ), + // Chain rocksdb::ColumnFamilyDescriptor::new("history_tree", db_options.clone()), rocksdb::ColumnFamilyDescriptor::new("tip_chain_value_pool", db_options.clone()), ]; // TODO: move opening the database to a blocking thread (#2188) - let db_result = rocksdb::DB::open_cf_descriptors(&db_options, &path, column_families); + let db_result = rocksdb::DBWithThreadMode::::open_cf_descriptors( + &db_options, + &path, + column_families, + ); match db_result { Ok(db) => { @@ -240,7 +430,7 @@ impl DiskDb { } } - // Read methods + // Accessor methods /// Returns the `Path` where the files used by this database are located. pub fn path(&self) -> &Path { @@ -248,31 +438,14 @@ impl DiskDb { } /// Returns the column family handle for `cf_name`. - pub fn cf_handle(&self, cf_name: &str) -> Option<&rocksdb::ColumnFamily> { + pub fn cf_handle(&self, cf_name: &str) -> Option { self.db.cf_handle(cf_name) } - /// Returns an iterator over the keys in `cf_name`, starting from the first key. - /// - /// TODO: add an iterator wrapper struct that does disk reads in a blocking thread (#2188) - pub fn forward_iterator(&self, cf_handle: &rocksdb::ColumnFamily) -> rocksdb::DBIterator { - self.db.iterator_cf(cf_handle, rocksdb::IteratorMode::Start) - } - - /// Returns a reverse iterator over the keys in `cf_name`, starting from the last key. - /// - /// TODO: add an iterator wrapper struct that does disk reads in a blocking thread (#2188) - pub fn reverse_iterator(&self, cf_handle: &rocksdb::ColumnFamily) -> rocksdb::DBIterator { - self.db.iterator_cf(cf_handle, rocksdb::IteratorMode::End) - } - - /// Returns true if `cf` does not contain any entries. - pub fn is_empty(&self, cf_handle: &rocksdb::ColumnFamily) -> bool { - // Empty column families return invalid iterators. - !self.forward_iterator(cf_handle).valid() - } + // Read methods are located in the ReadDisk trait // Write methods + // Low-level write methods are located in the WriteDisk trait /// Writes `batch` to the database. pub fn write(&self, batch: DiskWriteBatch) -> Result<(), rocksdb::Error> { @@ -285,10 +458,31 @@ impl DiskDb { /// Returns the database options for the finalized state database. fn options() -> rocksdb::Options { let mut opts = rocksdb::Options::default(); + let mut block_based_opts = rocksdb::BlockBasedOptions::default(); + + const ONE_MEGABYTE: usize = 1024 * 1024; opts.create_if_missing(true); opts.create_missing_column_families(true); + // Use the recommended Ribbon filter setting for all column families. + // + // Ribbon filters are faster than Bloom filters in Zebra, as of April 2022. + // (They aren't needed for single-valued column families, but they don't hurt either.) + block_based_opts.set_ribbon_filter(9.9); + + // Use the recommended LZ4 compression type. + // + // https://github.com/facebook/rocksdb/wiki/Compression#configuration + opts.set_compression_type(rocksdb::DBCompressionType::Lz4); + + // Tune level-style database file compaction. + // + // This improves Zebra's initial sync speed slightly, as of April 2022. + opts.optimize_level_style_compaction(Self::MEMTABLE_RAM_CACHE_MEGABYTES * ONE_MEGABYTE); + + // Increase the process open file limit if needed, + // then use it to set RocksDB's limit. let open_file_limit = DiskDb::increase_open_file_limit(); let db_file_limit = DiskDb::get_db_open_file_limit(open_file_limit); @@ -300,6 +494,9 @@ impl DiskDb { opts.set_max_open_files(db_file_limit); + // Set the block-based options + opts.set_block_based_table_factory(&block_based_opts); + opts } @@ -402,6 +599,8 @@ impl DiskDb { current_limit } + // Cleanup methods + /// Shut down the database, cleaning up background tasks and ephemeral data. /// /// If `force` is true, clean up regardless of any shared references. @@ -532,7 +731,7 @@ impl DiskDb { fn assert_default_cf_is_empty(&self) { if let Some(default_cf) = self.cf_handle("default") { assert!( - self.is_empty(default_cf), + self.zs_is_empty(&default_cf), "Zebra should not store data in the 'default' column family" ); } diff --git a/zebra-state/src/service/finalized_state/disk_db/tests.rs b/zebra-state/src/service/finalized_state/disk_db/tests.rs index c11edb89ed4..17613e8b3b5 100644 --- a/zebra-state/src/service/finalized_state/disk_db/tests.rs +++ b/zebra-state/src/service/finalized_state/disk_db/tests.rs @@ -2,7 +2,18 @@ #![allow(dead_code)] -use crate::service::finalized_state::disk_db::DiskDb; +use std::ops::Deref; + +use crate::service::finalized_state::disk_db::{DiskDb, DB}; + +// Enable older test code to automatically access the inner database via Deref coercion. +impl Deref for DiskDb { + type Target = DB; + + fn deref(&self) -> &Self::Target { + &self.db + } +} impl DiskDb { /// Returns a list of column family names in this database. diff --git a/zebra-state/src/service/finalized_state/disk_format.rs b/zebra-state/src/service/finalized_state/disk_format.rs index 0790ceda740..e663d005441 100644 --- a/zebra-state/src/service/finalized_state/disk_format.rs +++ b/zebra-state/src/service/finalized_state/disk_format.rs @@ -15,7 +15,7 @@ pub mod transparent; #[cfg(test)] mod tests; -pub use block::TransactionLocation; +pub use block::{TransactionIndex, TransactionLocation}; /// Helper type for writing types to disk as raw bytes. /// Also used to convert key types to raw bytes for disk lookups. diff --git a/zebra-state/src/service/finalized_state/disk_format/block.rs b/zebra-state/src/service/finalized_state/disk_format/block.rs index 22e2ff6b7e0..eda3ca56cc7 100644 --- a/zebra-state/src/service/finalized_state/disk_format/block.rs +++ b/zebra-state/src/service/finalized_state/disk_format/block.rs @@ -5,14 +5,12 @@ //! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must //! be incremented each time the database format (column, serialization, etc) changes. -use std::fmt::Debug; - use serde::{Deserialize, Serialize}; use zebra_chain::{ - block::{self, Block, Height}, - serialization::{ZcashDeserialize, ZcashSerialize}, - transaction, + block::{self, Height}, + serialization::{ZcashDeserializeInto, ZcashSerialize}, + transaction::{self, Transaction}, }; use crate::service::finalized_state::disk_format::{ @@ -24,7 +22,7 @@ use proptest_derive::Arbitrary; /// The maximum value of an on-disk serialized [`Height`]. /// -/// This allows us to store [`OutputIndex`]es in 8 bytes, +/// This allows us to store [`OutputLocation`]s in 8 bytes, /// which makes database searches more efficient. /// /// # Consensus @@ -46,25 +44,40 @@ pub const HEIGHT_DISK_BYTES: usize = 3; /// This reduces database size and increases lookup performance. pub const TX_INDEX_DISK_BYTES: usize = 2; -// Transaction types +/// [`TransactionLocation`]s are stored as a 3 byte height and a 2 byte transaction index. +/// +/// This reduces database size and increases lookup performance. +pub const TRANSACTION_LOCATION_DISK_BYTES: usize = HEIGHT_DISK_BYTES + TX_INDEX_DISK_BYTES; + +// Block and transaction types /// A transaction's index in its block. /// /// # Consensus /// -/// This maximum height supports on-disk storage of transactions in blocks up to ~5 MB. +/// A 2-byte index supports on-disk storage of transactions in blocks up to ~5 MB. /// (The current maximum block size is 2 MB.) /// /// Since Zebra only stores fully verified blocks on disk, /// blocks larger than this size are rejected before reaching the database. /// /// (The maximum transaction count is tested by the large generated block serialization tests.) -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct TransactionIndex(u16); impl TransactionIndex { - /// Creates a transaction index from the native index integer type. + /// Creates a transaction index from the inner type. + pub fn from_index(transaction_index: u16) -> TransactionIndex { + TransactionIndex(transaction_index) + } + + /// Returns this index as the inner type. + pub fn index(&self) -> u16 { + self.0 + } + + /// Creates a transaction index from a `usize`. pub fn from_usize(transaction_index: usize) -> TransactionIndex { TransactionIndex( transaction_index @@ -73,18 +86,36 @@ impl TransactionIndex { ) } - /// Returns this index as the native index integer type. + /// Returns this index as a `usize` + #[allow(dead_code)] pub fn as_usize(&self) -> usize { self.0 .try_into() .expect("the maximum valid index fits in usize") } + + /// Creates a transaction index from a `u64`. + pub fn from_u64(transaction_index: u64) -> TransactionIndex { + TransactionIndex( + transaction_index + .try_into() + .expect("the maximum valid index fits in the inner type"), + ) + } + + /// Returns this index as a `u64` + #[allow(dead_code)] + pub fn as_u64(&self) -> u64 { + self.0 + .try_into() + .expect("the maximum valid index fits in u64") + } } /// A transaction's location in the chain, by block height and transaction index. /// /// This provides a chain-order list of transactions. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct TransactionLocation { /// The block height of the transaction. @@ -95,18 +126,35 @@ pub struct TransactionLocation { } impl TransactionLocation { - /// Creates a transaction location from a block height and index (as the native index integer type). + /// Creates a transaction location from a block height and transaction index. + #[allow(dead_code)] + pub fn from_index(height: Height, transaction_index: u16) -> TransactionLocation { + TransactionLocation { + height, + index: TransactionIndex::from_index(transaction_index), + } + } + + /// Creates a transaction location from a block height and `usize` transaction index. pub fn from_usize(height: Height, transaction_index: usize) -> TransactionLocation { TransactionLocation { height, index: TransactionIndex::from_usize(transaction_index), } } + + /// Creates a transaction location from a block height and `u64` transaction index. + pub fn from_u64(height: Height, transaction_index: u64) -> TransactionLocation { + TransactionLocation { + height, + index: TransactionIndex::from_u64(transaction_index), + } + } } -// Block trait impls +// Block and transaction trait impls -impl IntoDisk for Block { +impl IntoDisk for block::Header { type Bytes = Vec; fn as_bytes(&self) -> Self::Bytes { @@ -115,9 +163,11 @@ impl IntoDisk for Block { } } -impl FromDisk for Block { +impl FromDisk for block::Header { fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { - Block::zcash_deserialize(bytes.as_ref()) + bytes + .as_ref() + .zcash_deserialize_into() .expect("deserialization format should match the serialization format used by IntoDisk") } } @@ -136,12 +186,13 @@ impl IntoDisk for Height { } impl FromDisk for Height { - fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { + fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { let mem_len = u32::BITS / 8; let mem_len = mem_len.try_into().unwrap(); - let mem_bytes = expand_zero_be_bytes(bytes.as_ref(), mem_len); - Height(u32::from_be_bytes(mem_bytes.try_into().unwrap())) + let mem_bytes = expand_zero_be_bytes(disk_bytes.as_ref(), mem_len); + let mem_bytes = mem_bytes.try_into().unwrap(); + Height(u32::from_be_bytes(mem_bytes)) } } @@ -162,22 +213,43 @@ impl FromDisk for block::Hash { // Transaction trait impls +impl IntoDisk for Transaction { + type Bytes = Vec; + + fn as_bytes(&self) -> Self::Bytes { + self.zcash_serialize_to_vec() + .expect("serialization to vec doesn't fail") + } +} + +impl FromDisk for Transaction { + fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { + bytes + .as_ref() + .zcash_deserialize_into() + .expect("deserialization format should match the serialization format used by IntoDisk") + } +} + +/// TransactionIndex is only serialized as part of TransactionLocation impl IntoDisk for TransactionIndex { type Bytes = [u8; TX_INDEX_DISK_BYTES]; fn as_bytes(&self) -> Self::Bytes { - self.0.to_be_bytes() + self.index().to_be_bytes() } } impl FromDisk for TransactionIndex { fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { - TransactionIndex(u16::from_be_bytes(disk_bytes.as_ref().try_into().unwrap())) + let disk_bytes = disk_bytes.as_ref().try_into().unwrap(); + + TransactionIndex::from_index(u16::from_be_bytes(disk_bytes)) } } impl IntoDisk for TransactionLocation { - type Bytes = [u8; HEIGHT_DISK_BYTES + TX_INDEX_DISK_BYTES]; + type Bytes = [u8; TRANSACTION_LOCATION_DISK_BYTES]; fn as_bytes(&self) -> Self::Bytes { let height_bytes = self.height.as_bytes().to_vec(); diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs b/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs index 70eaf61fdcc..2ce2457644e 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs +++ b/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs @@ -3,17 +3,26 @@ use proptest::{arbitrary::any, prelude::*}; use zebra_chain::{ - amount::NonNegative, - block::{self, Block, Height}, + amount::{Amount, NonNegative}, + block::{self, Height}, + orchard, sapling, sprout, + transaction::{self, Transaction}, transparent, value_balance::ValueBalance, }; use crate::service::finalized_state::{ arbitrary::assert_value_properties, - disk_format::{block::MAX_ON_DISK_HEIGHT, transparent::OutputLocation, TransactionLocation}, + disk_format::{ + block::MAX_ON_DISK_HEIGHT, + transparent::{AddressBalanceLocation, AddressLocation, OutputLocation}, + IntoDisk, TransactionLocation, + }, }; +// Block +// TODO: split these tests into the disk_format sub-modules + #[test] fn roundtrip_block_height() { zebra_test::init(); @@ -29,6 +38,22 @@ fn roundtrip_block_height() { ); } +#[test] +fn roundtrip_block_hash() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + +#[test] +fn roundtrip_block_header() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + +// Transaction + #[test] fn roundtrip_transaction_location() { zebra_test::init(); @@ -41,27 +66,100 @@ fn roundtrip_transaction_location() { ); } +#[test] +fn roundtrip_transaction_hash() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + +#[test] +fn roundtrip_transaction() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + +// Transparent + +// TODO: turn this into a generic function like assert_value_properties() +#[test] +fn serialized_transparent_address_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +#[test] +fn roundtrip_transparent_address() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + #[test] fn roundtrip_output_location() { zebra_test::init(); - proptest!(|(val in any::())| assert_value_properties(val)); + + proptest!( + |(mut val in any::())| { + *val.height_mut() = val.height().clamp(Height(0), MAX_ON_DISK_HEIGHT); + assert_value_properties(val) + } + ); } #[test] -fn roundtrip_block_hash() { +fn roundtrip_address_location() { zebra_test::init(); - proptest!(|(val in any::())| assert_value_properties(val)); + + proptest!( + |(mut val in any::())| { + *val.height_mut() = val.height().clamp(Height(0), MAX_ON_DISK_HEIGHT); + assert_value_properties(val) + } + ); } #[test] -fn roundtrip_block() { +fn roundtrip_address_balance_location() { zebra_test::init(); - proptest!(|(val in any::())| assert_value_properties(val)); + proptest!( + |(mut val in any::())| { + *val.height_mut() = val.location().height().clamp(Height(0), MAX_ON_DISK_HEIGHT); + assert_value_properties(val) + } + ); } #[test] -fn roundtrip_transparent_output() { +fn roundtrip_unspent_transparent_output() { zebra_test::init(); proptest!( @@ -72,6 +170,228 @@ fn roundtrip_transparent_output() { ); } +#[test] +fn roundtrip_transparent_output() { + zebra_test::init(); + + proptest!(|(val in any::())| assert_value_properties(val)); +} + +#[test] +fn roundtrip_amount() { + zebra_test::init(); + + proptest!(|(val in any::>())| assert_value_properties(val)); +} + +// Sprout + +#[test] +fn serialized_sprout_nullifier_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +#[test] +fn serialized_sprout_tree_root_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +// TODO: test note commitment tree round-trip, after implementing proptest::Arbitrary + +// Sapling + +#[test] +fn serialized_sapling_nullifier_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +#[test] +fn serialized_sapling_tree_root_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +// TODO: test note commitment tree round-trip, after implementing proptest::Arbitrary + +// Orchard + +#[test] +fn serialized_orchard_nullifier_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +#[test] +fn serialized_orchard_tree_root_equal() { + zebra_test::init(); + + proptest!(|(val1 in any::(), val2 in any::())| { + if val1 == val2 { + prop_assert_eq!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were equal, but serialized bytes were not.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } else { + prop_assert_ne!( + val1.as_bytes(), + val2.as_bytes(), + "struct values were not equal, but serialized bytes were equal.\n\ + Values:\n\ + {:?}\n\ + {:?}", + val1, + val2, + ); + } + } + ); +} + +// TODO: test note commitment tree round-trip, after implementing proptest::Arbitrary + +// Chain + +// TODO: test NonEmptyHistoryTree round-trip, after implementing proptest::Arbitrary + #[test] fn roundtrip_value_balance() { zebra_test::init(); diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs b/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs index 656d4391e4b..e9e172fda82 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs @@ -123,7 +123,8 @@ fn snapshot_raw_rocksdb_column_family_data(db: &DiskDb, original_cf_names: &[Str .cf_handle(cf_name) .expect("RocksDB API provides correct names"); - let mut cf_iter = db.forward_iterator(cf_handle); + // Correctness: Multi-key iteration causes hangs in concurrent code, but seems ok in tests. + let mut cf_iter = db.full_iterator_cf(&cf_handle, rocksdb::IteratorMode::Start); // The default raw data serialization is very verbose, so we hex-encode the bytes. let cf_data: Vec = cf_iter diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_1.snap new file mode 100644 index 00000000000..cbb88f6fa6e --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_1.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "017d46a730d31f97b1930d3368a967c309bd4d136a", + v: "d4300000000000000000010000000001", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_2.snap new file mode 100644 index 00000000000..646afbe0750 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@mainnet_2.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "017d46a730d31f97b1930d3368a967c309bd4d136a", + v: "7c920000000000000000010000000001", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_1.snap new file mode 100644 index 00000000000..3e6546dde3c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_1.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "03ef775f1f997f122a062fff1a2d7443abd1f9c642", + v: "d4300000000000000000010000000001", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_2.snap new file mode 100644 index 00000000000..b7cfb00febe --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/balance_by_transparent_addr_raw_data@testnet_2.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "03ef775f1f997f122a062fff1a2d7443abd1f9c642", + v: "7c920000000000000000010000000001", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_0.snap index c4dac544f54..7fe345a56f8 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_0.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_0.snap @@ -5,6 +5,6 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce157", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_1.snap index 260ae9ddefc..5ddd398fcdc 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_1.snap @@ -5,10 +5,10 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce157", ), KV( k: "000001", - v: "0400000008ce3d9731b000c08338455c8a4a6bd05da16e26b11daa1b917184ece80f04000946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b850000000000000000000000000000000000000000000000000000000000000000ac7a1358ffff071f7534e8cf161ff2e49d54bdb3bfbcde8cdbf2fc5963c9ec7d86aed4a67e975790fd4005002b2ee0d2f5d0c1ebf5a265b6f5b428f2fdc9aaea07078a6c5cab4f1bbfcd56489863deae6ea3fd8d3d0762e8e5295ff2670c9e90d8e8c68a54a40927e82a65e1d44ced20d835818e172d7b7f5ffe0245d0c3860a3f11af5658d68b6a7253b4684ffef5242fefa77a0bfc3437e8d94df9dc57510f5a128e676dd9ddf23f0ef75b460090f507499585541ab53a470c547ea02723d3a979930941157792c4362e42d3b9faca342a5c05a56909b046b5e92e2870fca7c932ae2c2fdd97d75b6e0ecb501701c1250246093c73efc5ec2838aeb80b59577741aa5ccdf4a631b79f70fc419e28714fa22108d991c29052b2f5f72294c355b57504369313470ecdd8e0ae97fc48e243a38c2ee7315bb05b7de9602047e97449c81e46746513221738dc729d7077a1771cea858865d85261e71e82003ccfbba2416358f023251206d6ef4c5596bc35b2b5bce3e9351798aa2c9904723034e5815c7512d260cc957df5db6adf9ed7272483312d1e68c60955a944e713355089876a704aef06359238f6de5a618f7bd0b4552ba72d05a6165e582f62d55ff2e1b76991971689ba3bee16a520fd85380a6e5a31de4dd4654d561101ce0ca390862d5774921eae2c284008692e9e08562144e8aa1f399a9d3fab0c4559c1f12bc945e626f7a89668613e8829767f4116ee9a4f832cf7c3ade3a7aba8cb04de39edd94d0d05093ed642adf9fbd9d373a80832ffd1c62034e4341546b3515f0e42e6d8570393c6754be5cdb7753b4709527d3f164aebf3d315934f7b3736a1b31052f6cc5699758950331163b3df05b9772e9bf99c8c77f8960e10a15edb06200106f45742d740c422c86b7e4f5a52d3732aa79ee54cfc92f76e03c268ae226477c19924e733caf95b8f350233a5312f4ed349d3ad76f032358f83a6d0d6f83b2a456742aad7f3e615fa72286300f0ea1c9793831ef3a5a4ae08640a6e32f53d1cba0be284b25e923d0d110ba227e54725632efcbbe17c05a9cde976504f6aece0c461b562cfae1b85d5f6782ee27b3e332ac0775f681682ce524b32889f1dc4231226f1aada0703beaf8d41732c9647a0a940a86f8a1be7f239c44fcaa7ed7a055506bdbe1df848f9e047226bee1b6d788a03f6e352eead99b419cfc41741942dbeb7a5c55788d5a3e636d8aab7b36b4db71d16700373bbc1cdeba8f9b1db10bf39a621bc737ea4f4e333698d6e09b51ac7a97fb6fd117ccad1d6b6b3a7451699d5bfe448650396d7b58867b3b0872be13ad0b43da267df0ad77025155f04e20c56d6a9befb3e9c7d23b82cbf3a534295ebda540682cc81be9273781b92519c858f9c25294fbacf75c3b3c15bda6d36de1c83336f93e96910dbdcb190d6ef123c98565ff6df1e903f57d4e4df167ba6b829d6d9713eb2126b0cf869940204137babcc6a1b7cb2f0b94318a7460e5d1a605c249bd2e72123ebad332332c18adcb285ed8874dbde084ebcd4f744465350d57110f037fffed1569d642c258749e65b0d13e117eaa37014a769b5ab479b7c77178880e77099f999abe712e543dbbf626ca9bcfddc42ff2f109d21c8bd464894e55ae504fdf81e1a7694180225da7dac8879abd1036cf26bb50532b8cf138b337a1a1bd1a43f8dd70b7399e2690c8e7a5a1fe099026b8f2a6f65fc0dbedda15ba65e0abd66c7176fb426980549892b4817de78e345a7aeab05744c3def4a2f283b4255b02c91c1af7354a368c67a11703c642a385c7453131ce3a78b24c5e22ab7e136a38498ce82082181884418cb4d6c2920f258a3ad20cfbe7104af1c6c6cb5e58bf29a9901721ad19c0a260cd09a3a772443a45aea4a5c439a95834ef5dc2e26343278947b7b796f796ae9bcadb29e2899a1d7313e6f7bfb6f8b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025100ffffffff0250c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875acd43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + v: "0400000008ce3d9731b000c08338455c8a4a6bd05da16e26b11daa1b917184ece80f04000946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b850000000000000000000000000000000000000000000000000000000000000000ac7a1358ffff071f7534e8cf161ff2e49d54bdb3bfbcde8cdbf2fc5963c9ec7d86aed4a67e975790fd4005002b2ee0d2f5d0c1ebf5a265b6f5b428f2fdc9aaea07078a6c5cab4f1bbfcd56489863deae6ea3fd8d3d0762e8e5295ff2670c9e90d8e8c68a54a40927e82a65e1d44ced20d835818e172d7b7f5ffe0245d0c3860a3f11af5658d68b6a7253b4684ffef5242fefa77a0bfc3437e8d94df9dc57510f5a128e676dd9ddf23f0ef75b460090f507499585541ab53a470c547ea02723d3a979930941157792c4362e42d3b9faca342a5c05a56909b046b5e92e2870fca7c932ae2c2fdd97d75b6e0ecb501701c1250246093c73efc5ec2838aeb80b59577741aa5ccdf4a631b79f70fc419e28714fa22108d991c29052b2f5f72294c355b57504369313470ecdd8e0ae97fc48e243a38c2ee7315bb05b7de9602047e97449c81e46746513221738dc729d7077a1771cea858865d85261e71e82003ccfbba2416358f023251206d6ef4c5596bc35b2b5bce3e9351798aa2c9904723034e5815c7512d260cc957df5db6adf9ed7272483312d1e68c60955a944e713355089876a704aef06359238f6de5a618f7bd0b4552ba72d05a6165e582f62d55ff2e1b76991971689ba3bee16a520fd85380a6e5a31de4dd4654d561101ce0ca390862d5774921eae2c284008692e9e08562144e8aa1f399a9d3fab0c4559c1f12bc945e626f7a89668613e8829767f4116ee9a4f832cf7c3ade3a7aba8cb04de39edd94d0d05093ed642adf9fbd9d373a80832ffd1c62034e4341546b3515f0e42e6d8570393c6754be5cdb7753b4709527d3f164aebf3d315934f7b3736a1b31052f6cc5699758950331163b3df05b9772e9bf99c8c77f8960e10a15edb06200106f45742d740c422c86b7e4f5a52d3732aa79ee54cfc92f76e03c268ae226477c19924e733caf95b8f350233a5312f4ed349d3ad76f032358f83a6d0d6f83b2a456742aad7f3e615fa72286300f0ea1c9793831ef3a5a4ae08640a6e32f53d1cba0be284b25e923d0d110ba227e54725632efcbbe17c05a9cde976504f6aece0c461b562cfae1b85d5f6782ee27b3e332ac0775f681682ce524b32889f1dc4231226f1aada0703beaf8d41732c9647a0a940a86f8a1be7f239c44fcaa7ed7a055506bdbe1df848f9e047226bee1b6d788a03f6e352eead99b419cfc41741942dbeb7a5c55788d5a3e636d8aab7b36b4db71d16700373bbc1cdeba8f9b1db10bf39a621bc737ea4f4e333698d6e09b51ac7a97fb6fd117ccad1d6b6b3a7451699d5bfe448650396d7b58867b3b0872be13ad0b43da267df0ad77025155f04e20c56d6a9befb3e9c7d23b82cbf3a534295ebda540682cc81be9273781b92519c858f9c25294fbacf75c3b3c15bda6d36de1c83336f93e96910dbdcb190d6ef123c98565ff6df1e903f57d4e4df167ba6b829d6d9713eb2126b0cf869940204137babcc6a1b7cb2f0b94318a7460e5d1a605c249bd2e72123ebad332332c18adcb285ed8874dbde084ebcd4f744465350d57110f037fffed1569d642c258749e65b0d13e117eaa37014a769b5ab479b7c77178880e77099f999abe712e543dbbf626ca9bcfddc42ff2f109d21c8bd464894e55ae504fdf81e1a7694180225da7dac8879abd1036cf26bb50532b8cf138b337a1a1bd1a43f8dd70b7399e2690c8e7a5a1fe099026b8f2a6f65fc0dbedda15ba65e0abd66c7176fb426980549892b4817de78e345a7aeab05744c3def4a2f283b4255b02c91c1af7354a368c67a11703c642a385c7453131ce3a78b24c5e22ab7e136a38498ce82082181884418cb4d6c2920f258a3ad20cfbe7104af1c6c6cb5e58bf29a9901721ad19c0a260cd09a3a772443a45aea4a5c439a95834ef5dc2e26343278947b7b796f796ae9bcadb29e2899a1d7313e6f7bfb6f8b", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_2.snap index 7663a0d29f4..d8414b39478 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@mainnet_2.snap @@ -5,14 +5,14 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce157", ), KV( k: "000001", - v: "0400000008ce3d9731b000c08338455c8a4a6bd05da16e26b11daa1b917184ece80f04000946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b850000000000000000000000000000000000000000000000000000000000000000ac7a1358ffff071f7534e8cf161ff2e49d54bdb3bfbcde8cdbf2fc5963c9ec7d86aed4a67e975790fd4005002b2ee0d2f5d0c1ebf5a265b6f5b428f2fdc9aaea07078a6c5cab4f1bbfcd56489863deae6ea3fd8d3d0762e8e5295ff2670c9e90d8e8c68a54a40927e82a65e1d44ced20d835818e172d7b7f5ffe0245d0c3860a3f11af5658d68b6a7253b4684ffef5242fefa77a0bfc3437e8d94df9dc57510f5a128e676dd9ddf23f0ef75b460090f507499585541ab53a470c547ea02723d3a979930941157792c4362e42d3b9faca342a5c05a56909b046b5e92e2870fca7c932ae2c2fdd97d75b6e0ecb501701c1250246093c73efc5ec2838aeb80b59577741aa5ccdf4a631b79f70fc419e28714fa22108d991c29052b2f5f72294c355b57504369313470ecdd8e0ae97fc48e243a38c2ee7315bb05b7de9602047e97449c81e46746513221738dc729d7077a1771cea858865d85261e71e82003ccfbba2416358f023251206d6ef4c5596bc35b2b5bce3e9351798aa2c9904723034e5815c7512d260cc957df5db6adf9ed7272483312d1e68c60955a944e713355089876a704aef06359238f6de5a618f7bd0b4552ba72d05a6165e582f62d55ff2e1b76991971689ba3bee16a520fd85380a6e5a31de4dd4654d561101ce0ca390862d5774921eae2c284008692e9e08562144e8aa1f399a9d3fab0c4559c1f12bc945e626f7a89668613e8829767f4116ee9a4f832cf7c3ade3a7aba8cb04de39edd94d0d05093ed642adf9fbd9d373a80832ffd1c62034e4341546b3515f0e42e6d8570393c6754be5cdb7753b4709527d3f164aebf3d315934f7b3736a1b31052f6cc5699758950331163b3df05b9772e9bf99c8c77f8960e10a15edb06200106f45742d740c422c86b7e4f5a52d3732aa79ee54cfc92f76e03c268ae226477c19924e733caf95b8f350233a5312f4ed349d3ad76f032358f83a6d0d6f83b2a456742aad7f3e615fa72286300f0ea1c9793831ef3a5a4ae08640a6e32f53d1cba0be284b25e923d0d110ba227e54725632efcbbe17c05a9cde976504f6aece0c461b562cfae1b85d5f6782ee27b3e332ac0775f681682ce524b32889f1dc4231226f1aada0703beaf8d41732c9647a0a940a86f8a1be7f239c44fcaa7ed7a055506bdbe1df848f9e047226bee1b6d788a03f6e352eead99b419cfc41741942dbeb7a5c55788d5a3e636d8aab7b36b4db71d16700373bbc1cdeba8f9b1db10bf39a621bc737ea4f4e333698d6e09b51ac7a97fb6fd117ccad1d6b6b3a7451699d5bfe448650396d7b58867b3b0872be13ad0b43da267df0ad77025155f04e20c56d6a9befb3e9c7d23b82cbf3a534295ebda540682cc81be9273781b92519c858f9c25294fbacf75c3b3c15bda6d36de1c83336f93e96910dbdcb190d6ef123c98565ff6df1e903f57d4e4df167ba6b829d6d9713eb2126b0cf869940204137babcc6a1b7cb2f0b94318a7460e5d1a605c249bd2e72123ebad332332c18adcb285ed8874dbde084ebcd4f744465350d57110f037fffed1569d642c258749e65b0d13e117eaa37014a769b5ab479b7c77178880e77099f999abe712e543dbbf626ca9bcfddc42ff2f109d21c8bd464894e55ae504fdf81e1a7694180225da7dac8879abd1036cf26bb50532b8cf138b337a1a1bd1a43f8dd70b7399e2690c8e7a5a1fe099026b8f2a6f65fc0dbedda15ba65e0abd66c7176fb426980549892b4817de78e345a7aeab05744c3def4a2f283b4255b02c91c1af7354a368c67a11703c642a385c7453131ce3a78b24c5e22ab7e136a38498ce82082181884418cb4d6c2920f258a3ad20cfbe7104af1c6c6cb5e58bf29a9901721ad19c0a260cd09a3a772443a45aea4a5c439a95834ef5dc2e26343278947b7b796f796ae9bcadb29e2899a1d7313e6f7bfb6f8b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025100ffffffff0250c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875acd43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + v: "0400000008ce3d9731b000c08338455c8a4a6bd05da16e26b11daa1b917184ece80f04000946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b850000000000000000000000000000000000000000000000000000000000000000ac7a1358ffff071f7534e8cf161ff2e49d54bdb3bfbcde8cdbf2fc5963c9ec7d86aed4a67e975790fd4005002b2ee0d2f5d0c1ebf5a265b6f5b428f2fdc9aaea07078a6c5cab4f1bbfcd56489863deae6ea3fd8d3d0762e8e5295ff2670c9e90d8e8c68a54a40927e82a65e1d44ced20d835818e172d7b7f5ffe0245d0c3860a3f11af5658d68b6a7253b4684ffef5242fefa77a0bfc3437e8d94df9dc57510f5a128e676dd9ddf23f0ef75b460090f507499585541ab53a470c547ea02723d3a979930941157792c4362e42d3b9faca342a5c05a56909b046b5e92e2870fca7c932ae2c2fdd97d75b6e0ecb501701c1250246093c73efc5ec2838aeb80b59577741aa5ccdf4a631b79f70fc419e28714fa22108d991c29052b2f5f72294c355b57504369313470ecdd8e0ae97fc48e243a38c2ee7315bb05b7de9602047e97449c81e46746513221738dc729d7077a1771cea858865d85261e71e82003ccfbba2416358f023251206d6ef4c5596bc35b2b5bce3e9351798aa2c9904723034e5815c7512d260cc957df5db6adf9ed7272483312d1e68c60955a944e713355089876a704aef06359238f6de5a618f7bd0b4552ba72d05a6165e582f62d55ff2e1b76991971689ba3bee16a520fd85380a6e5a31de4dd4654d561101ce0ca390862d5774921eae2c284008692e9e08562144e8aa1f399a9d3fab0c4559c1f12bc945e626f7a89668613e8829767f4116ee9a4f832cf7c3ade3a7aba8cb04de39edd94d0d05093ed642adf9fbd9d373a80832ffd1c62034e4341546b3515f0e42e6d8570393c6754be5cdb7753b4709527d3f164aebf3d315934f7b3736a1b31052f6cc5699758950331163b3df05b9772e9bf99c8c77f8960e10a15edb06200106f45742d740c422c86b7e4f5a52d3732aa79ee54cfc92f76e03c268ae226477c19924e733caf95b8f350233a5312f4ed349d3ad76f032358f83a6d0d6f83b2a456742aad7f3e615fa72286300f0ea1c9793831ef3a5a4ae08640a6e32f53d1cba0be284b25e923d0d110ba227e54725632efcbbe17c05a9cde976504f6aece0c461b562cfae1b85d5f6782ee27b3e332ac0775f681682ce524b32889f1dc4231226f1aada0703beaf8d41732c9647a0a940a86f8a1be7f239c44fcaa7ed7a055506bdbe1df848f9e047226bee1b6d788a03f6e352eead99b419cfc41741942dbeb7a5c55788d5a3e636d8aab7b36b4db71d16700373bbc1cdeba8f9b1db10bf39a621bc737ea4f4e333698d6e09b51ac7a97fb6fd117ccad1d6b6b3a7451699d5bfe448650396d7b58867b3b0872be13ad0b43da267df0ad77025155f04e20c56d6a9befb3e9c7d23b82cbf3a534295ebda540682cc81be9273781b92519c858f9c25294fbacf75c3b3c15bda6d36de1c83336f93e96910dbdcb190d6ef123c98565ff6df1e903f57d4e4df167ba6b829d6d9713eb2126b0cf869940204137babcc6a1b7cb2f0b94318a7460e5d1a605c249bd2e72123ebad332332c18adcb285ed8874dbde084ebcd4f744465350d57110f037fffed1569d642c258749e65b0d13e117eaa37014a769b5ab479b7c77178880e77099f999abe712e543dbbf626ca9bcfddc42ff2f109d21c8bd464894e55ae504fdf81e1a7694180225da7dac8879abd1036cf26bb50532b8cf138b337a1a1bd1a43f8dd70b7399e2690c8e7a5a1fe099026b8f2a6f65fc0dbedda15ba65e0abd66c7176fb426980549892b4817de78e345a7aeab05744c3def4a2f283b4255b02c91c1af7354a368c67a11703c642a385c7453131ce3a78b24c5e22ab7e136a38498ce82082181884418cb4d6c2920f258a3ad20cfbe7104af1c6c6cb5e58bf29a9901721ad19c0a260cd09a3a772443a45aea4a5c439a95834ef5dc2e26343278947b7b796f796ae9bcadb29e2899a1d7313e6f7bfb6f8b", ), KV( k: "000002", - v: "040000008392336da29773c56b1649ab555156ceb7e700ad7c230ea7a4571c7e22bc0700f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd074890000000000000000000000000000000000000000000000000000000000000000ca7a1358ffff071fa5556cd346010000000000000000000000000000000000000000000000000002fd4005005605e4490c2e7fc1acf199d7401e18ab8d2be4c843103a7ebdd34046d5514559e6ecbe29c00b9adf6f1aa49f1d63b9c20fd9bca4d9bbb381cb82f59cee9f387deb34ec4fd6b1e12f656a554bc21db88bd1560a033e64099c0bef439cdd6055aaa4f79c360ad37d1f1df1fbd35214e17fc5a0b3c0d272b1e693d6ba9e5e0ae71c6ff58545776838c18b756bf98a83a6b9739b4dec356117b2b227f6f6ea3f04fd854aadf27b40b302d3fa50719aa02f99c2003b51eab8c64cfd145117054dcadb604ba65a8854a095bd9f02884a65225baf0547a7ee44882b11343d40b1a6511cbc4db1d2fd840a8cd63610d29c47bd5c920fe13c349d1044185cd40854f8e60a212d59e1fe281e8bd1343a682e95f3ea23fb5ca83f9913bbcb11232ffd7165ea4a475273df1f3bb53cb721548b28f772acf56060da5d26fab50c4f8b87781bf28843bea805340531a61f002b5aad9a0427b597af1a08659f1a7b4b6d69d53b13191cf35512bc3521359dda47911112d06ae5410281d918bf53049f8295f067f2b3794a90cc15358e294c6cbd7896108d7c897e4bf61aa72451a280cfce72e0515b8dc510a52743b7615b25ba2f13419d562f6148fa36132622953c0fb74ea0b4870f86ccc1ece9661b29516a2226ea16b7100dbeb718a674eedbbe9d23ab02fe1c634234f3c1275ae9d7f74c754c66dec0af7331fc1407075a06cba62098a9be09d24889e7d0a6cf77d875131fe1278e6fdea2bfd9423903e1cb4502edcef971c60b064d4d8a9703ff324574e3d0535a59ab091355185499545be1baffddf6c2b654e5c30e7e1291763fd70896217d91d876a9be914a8472fa292ea3cfdc4be84f4c645f62d8ccff990ac4f5c84e0775b147d1532e2d4f3a8fb92fda899280a3e42f2b927dbef872ec6058254eb20e2770efde7c57905e7741321e833533e0006344a4c6deb9a78e8496de1ae1464ef8367ae97714700e76658e2390cb9702d1413b333d7f04fb89dd09cefeb34e0ead616cd5d352a2f348758e0f5fc4220c6a0693acc90b8dcd7a372ecb688d86356c151d9703576af8e904adea9941d1a6296774ba62b4dae7bf0a078f740af040c584f0245ed2ffa351f0b550c8b80e192ba1a75eb40fc42d67b722ea04ea947ed53e831fe057153a8bd6897ddcd43cb558d2766fb05640ed0c1d14eae0739b11ec07e34f3ea6acbd9f807b9ea6476bda5964a9fca1819c854680f75857e57fbf3fc50e3f5b0d25cadadcd9b3428b85b70b95080c9423a836e9e9e2cbd485075a29452d65acf3d5762111d70a0fd389ac7214b96b11eb14ae48ff1e4930ea50d8261472fd8d04877af717b4d463c0d9a6cf397b5b91fb1a898b329c4b46b8c350e3c0122e186bc393fe6d361e117963d38e44e0ccf1c45f33440aaebd8f99ad7b019c6411bb070178fb6b76e085e3bdae4c883f1f4112e7db91c519c48769fe96f56350cc8687679747730f0aad3bc58b78f87d162104beee449e55eab45558241f32cb5a0f30fea0f38632adfc8a2b7292ff89641581bb6e0111af26dad9199596ce8d432e6f7d0a7415aacc473acfb8af68c9c6ef8b60c535da095cd3a02598fd82fe20481dc87bf6ed25fb95633dc7ff8bcf3f81c323546084170e567536b5c4ce9392ae1dc1f201d732134597e3c9353416fa40ff8f2628815e9b980f27a9c05adefa779ef1a35fdfe6423e9f671677311971bd91d9aeb6adf4c45769d07df7a24955f4082730fb0d3f6467472f75add86b827a7b664005931130029553fdb62ad9ffdb64b44701c0d94e7c5f5ba2340e641d9e34737e29b47e619659f458a161648c9fb81dddbcc73f1eebc92fd7f7b70356635f0de19912d82c9a978c2750aacbfbeee3ab62e96f7df7ce918fa30101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025200ffffffff02a0860100000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875aca86100000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + v: "040000008392336da29773c56b1649ab555156ceb7e700ad7c230ea7a4571c7e22bc0700f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd074890000000000000000000000000000000000000000000000000000000000000000ca7a1358ffff071fa5556cd346010000000000000000000000000000000000000000000000000002fd4005005605e4490c2e7fc1acf199d7401e18ab8d2be4c843103a7ebdd34046d5514559e6ecbe29c00b9adf6f1aa49f1d63b9c20fd9bca4d9bbb381cb82f59cee9f387deb34ec4fd6b1e12f656a554bc21db88bd1560a033e64099c0bef439cdd6055aaa4f79c360ad37d1f1df1fbd35214e17fc5a0b3c0d272b1e693d6ba9e5e0ae71c6ff58545776838c18b756bf98a83a6b9739b4dec356117b2b227f6f6ea3f04fd854aadf27b40b302d3fa50719aa02f99c2003b51eab8c64cfd145117054dcadb604ba65a8854a095bd9f02884a65225baf0547a7ee44882b11343d40b1a6511cbc4db1d2fd840a8cd63610d29c47bd5c920fe13c349d1044185cd40854f8e60a212d59e1fe281e8bd1343a682e95f3ea23fb5ca83f9913bbcb11232ffd7165ea4a475273df1f3bb53cb721548b28f772acf56060da5d26fab50c4f8b87781bf28843bea805340531a61f002b5aad9a0427b597af1a08659f1a7b4b6d69d53b13191cf35512bc3521359dda47911112d06ae5410281d918bf53049f8295f067f2b3794a90cc15358e294c6cbd7896108d7c897e4bf61aa72451a280cfce72e0515b8dc510a52743b7615b25ba2f13419d562f6148fa36132622953c0fb74ea0b4870f86ccc1ece9661b29516a2226ea16b7100dbeb718a674eedbbe9d23ab02fe1c634234f3c1275ae9d7f74c754c66dec0af7331fc1407075a06cba62098a9be09d24889e7d0a6cf77d875131fe1278e6fdea2bfd9423903e1cb4502edcef971c60b064d4d8a9703ff324574e3d0535a59ab091355185499545be1baffddf6c2b654e5c30e7e1291763fd70896217d91d876a9be914a8472fa292ea3cfdc4be84f4c645f62d8ccff990ac4f5c84e0775b147d1532e2d4f3a8fb92fda899280a3e42f2b927dbef872ec6058254eb20e2770efde7c57905e7741321e833533e0006344a4c6deb9a78e8496de1ae1464ef8367ae97714700e76658e2390cb9702d1413b333d7f04fb89dd09cefeb34e0ead616cd5d352a2f348758e0f5fc4220c6a0693acc90b8dcd7a372ecb688d86356c151d9703576af8e904adea9941d1a6296774ba62b4dae7bf0a078f740af040c584f0245ed2ffa351f0b550c8b80e192ba1a75eb40fc42d67b722ea04ea947ed53e831fe057153a8bd6897ddcd43cb558d2766fb05640ed0c1d14eae0739b11ec07e34f3ea6acbd9f807b9ea6476bda5964a9fca1819c854680f75857e57fbf3fc50e3f5b0d25cadadcd9b3428b85b70b95080c9423a836e9e9e2cbd485075a29452d65acf3d5762111d70a0fd389ac7214b96b11eb14ae48ff1e4930ea50d8261472fd8d04877af717b4d463c0d9a6cf397b5b91fb1a898b329c4b46b8c350e3c0122e186bc393fe6d361e117963d38e44e0ccf1c45f33440aaebd8f99ad7b019c6411bb070178fb6b76e085e3bdae4c883f1f4112e7db91c519c48769fe96f56350cc8687679747730f0aad3bc58b78f87d162104beee449e55eab45558241f32cb5a0f30fea0f38632adfc8a2b7292ff89641581bb6e0111af26dad9199596ce8d432e6f7d0a7415aacc473acfb8af68c9c6ef8b60c535da095cd3a02598fd82fe20481dc87bf6ed25fb95633dc7ff8bcf3f81c323546084170e567536b5c4ce9392ae1dc1f201d732134597e3c9353416fa40ff8f2628815e9b980f27a9c05adefa779ef1a35fdfe6423e9f671677311971bd91d9aeb6adf4c45769d07df7a24955f4082730fb0d3f6467472f75add86b827a7b664005931130029553fdb62ad9ffdb64b44701c0d94e7c5f5ba2340e641d9e34737e29b47e619659f458a161648c9fb81dddbcc73f1eebc92fd7f7b70356635f0de19912d82c9a978c2750aacbfbeee3ab62e96f7df7ce918fa3", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_0.snap index b52ff970fdb..6be07b222ef 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_0.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_0.snap @@ -5,6 +5,6 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_1.snap index 19a943cb552..406ec0865f7 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_1.snap @@ -5,10 +5,10 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff", ), KV( k: "000001", - v: "04000000382c4a332661c7ed0671f32a34d724619f086c61873bce7c99859dd9920aa605755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef30000000000000000000000000000000000000000000000000000000000000000e9851358ffff0720000056c2264c31261d597c6fcea7c5e00160cf6be1cd89ca96a0389473e50000fd40050053f4438864bc5d6dfc009d4bba545ac5e5feaaf46f9455b975b02115f842a966e26517ce678f1c074d09cc8d0049a190859eb505af5f3e760312fbbe54da115db2bc03c96408f39b679891790b539d2d9d17a801dc6af9af14ca3f6ba060edce2a1dd45aa45f11fe37dbaf1eb2647ae7c393f6680c3d5d7e53687e34530f48edf58924a04d3e0231c150b1c8218998f674bc171edd222bcb4ac4ba4ea52d7baa86399f371d5284043e1e166f9069dd0f2904ff94c7922a70fa7c660e0553cc40a20d9ee08eb3f47278485801ddae9c270411360773f0b74e03db2d92c50952c9bd4924bbca2a260e1235e99df51fe71e75744232f2d641ef94f394110a5ad05f51a057e4cb515b92c16cb1404a8cdcc43d4a4bb2caa54ca35dccf41aa7d832da65123b7029223c46ed2a13387d598d445435d3cb32fdad9e27672903864c90d86353b162033078327b5b7aaffc89b40096ae004f2d5c6bd2c99188574348518db66e9b6020f93f12ee1c06f7b00fe346fefceaffb1da9e3cdf08285057f549733eb10825737fcd1431bfdfb155f323f24e95a869212baacf445b30f2670206645779110e6547d5da90a5f2fe5151da911d5ecd5a833023661d1356b6c395d85968947678d53efd4db7b06f23b21125e74492644277ea0c1131b80d6a4e3e8093b82332556fbb3255a55ac3f0b7e4844c0e12bf577c37fd02323ae5ef4781772ed501d63b568032a3d31576c5104a48c01ac54f715286932351a8adc8cf2467a84a0572e99f366ee00f82c3735545fd4bb941d591ce70070425a81304272db89887949bc7dd8236bb7e82190f9815da938cd6e8fec7660e91354326a7a9bfe38120e97997fca3c289d54513ed00286c2b825fbe84f91a39528f335674b5e957425a6edfdd00f2feb2c2df575616197998c1e964e069875d4d934f419a9b02b100848d023b76d47bd4e284c3895ef9227a40d8ea8826e86c7155d6aa95b8f9175812523a32cd611efc700688e03f7c245c5bff01718281b5d75cefe8318b2c08962236b14a0bf79534c203df735fd9cced97cbae07c2b4ee9cda8c9993f3f6277ff3fec261fb94d3961c4befe4b0893dcf67b312c7d8d6ff7adc8539cb2b1d3534fccf109efddd07a9f1e77b94ab1e505b164221dca1c34621b1e9d234c31a032a401267d95f65b800d579a2482638dfeade804149c81e95d7ef5510ac0b6212231506b1c635a2e1d2f0c9712989f9f246762fadb4c55c20f707dcc0e510a33e9465fc5d5bdbfa524dab0d7a1c6a1baaa36869cf542aa2257c5c44ef07547a570343442c6091e13bc04d559dc0e6db5b001861914bf956816edce2a86b274bd97f27e2dbb08608c16a3e5d8595952faa91fb162d7fa6a7a47e849a1ad8fab3ba620ee3295a04fe13e5fb655ac92ae60d01020b8999526af8d56b28733e69c9ffb285de27c61edc0bf62261ac0787eff347d0fcd62257301ede9603106ea41650a3e3119bd5c4e86a7f6a3f00934f3a545f7f21d41699f3e35d38cf925a8bdaf2bf7eedea11c31c3d8bf6c527c77c6378281cdf02211a58fa5e46d28d7e7c5fb79d69b31703fd752395da115845952cf99aaeb2155c2ab951a69f67d938f223185567e52cfa3e57b62c790bf78674c4b02c12b7d3225fe8f705b408ba11c24245b3924482e2f3480994461b550641a88cd941d371139f3498afacdcba1249631402b20695760eaada5376e68df0e45139c410700effc9420dc3726515e7fcb3f349320f30511451964bd9b6530682efec65910ceb548aa2ab05ac3309e803161697213631ae8e13cc7d223ac28446c1bf94a19a8782ac16ff57df7ee4f10fb6e488c02c68d6b6dee6987f6d2c39227da366c59f54ff67e312ca530e7c467c3dc80101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0250c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99acd43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + v: "04000000382c4a332661c7ed0671f32a34d724619f086c61873bce7c99859dd9920aa605755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef30000000000000000000000000000000000000000000000000000000000000000e9851358ffff0720000056c2264c31261d597c6fcea7c5e00160cf6be1cd89ca96a0389473e50000fd40050053f4438864bc5d6dfc009d4bba545ac5e5feaaf46f9455b975b02115f842a966e26517ce678f1c074d09cc8d0049a190859eb505af5f3e760312fbbe54da115db2bc03c96408f39b679891790b539d2d9d17a801dc6af9af14ca3f6ba060edce2a1dd45aa45f11fe37dbaf1eb2647ae7c393f6680c3d5d7e53687e34530f48edf58924a04d3e0231c150b1c8218998f674bc171edd222bcb4ac4ba4ea52d7baa86399f371d5284043e1e166f9069dd0f2904ff94c7922a70fa7c660e0553cc40a20d9ee08eb3f47278485801ddae9c270411360773f0b74e03db2d92c50952c9bd4924bbca2a260e1235e99df51fe71e75744232f2d641ef94f394110a5ad05f51a057e4cb515b92c16cb1404a8cdcc43d4a4bb2caa54ca35dccf41aa7d832da65123b7029223c46ed2a13387d598d445435d3cb32fdad9e27672903864c90d86353b162033078327b5b7aaffc89b40096ae004f2d5c6bd2c99188574348518db66e9b6020f93f12ee1c06f7b00fe346fefceaffb1da9e3cdf08285057f549733eb10825737fcd1431bfdfb155f323f24e95a869212baacf445b30f2670206645779110e6547d5da90a5f2fe5151da911d5ecd5a833023661d1356b6c395d85968947678d53efd4db7b06f23b21125e74492644277ea0c1131b80d6a4e3e8093b82332556fbb3255a55ac3f0b7e4844c0e12bf577c37fd02323ae5ef4781772ed501d63b568032a3d31576c5104a48c01ac54f715286932351a8adc8cf2467a84a0572e99f366ee00f82c3735545fd4bb941d591ce70070425a81304272db89887949bc7dd8236bb7e82190f9815da938cd6e8fec7660e91354326a7a9bfe38120e97997fca3c289d54513ed00286c2b825fbe84f91a39528f335674b5e957425a6edfdd00f2feb2c2df575616197998c1e964e069875d4d934f419a9b02b100848d023b76d47bd4e284c3895ef9227a40d8ea8826e86c7155d6aa95b8f9175812523a32cd611efc700688e03f7c245c5bff01718281b5d75cefe8318b2c08962236b14a0bf79534c203df735fd9cced97cbae07c2b4ee9cda8c9993f3f6277ff3fec261fb94d3961c4befe4b0893dcf67b312c7d8d6ff7adc8539cb2b1d3534fccf109efddd07a9f1e77b94ab1e505b164221dca1c34621b1e9d234c31a032a401267d95f65b800d579a2482638dfeade804149c81e95d7ef5510ac0b6212231506b1c635a2e1d2f0c9712989f9f246762fadb4c55c20f707dcc0e510a33e9465fc5d5bdbfa524dab0d7a1c6a1baaa36869cf542aa2257c5c44ef07547a570343442c6091e13bc04d559dc0e6db5b001861914bf956816edce2a86b274bd97f27e2dbb08608c16a3e5d8595952faa91fb162d7fa6a7a47e849a1ad8fab3ba620ee3295a04fe13e5fb655ac92ae60d01020b8999526af8d56b28733e69c9ffb285de27c61edc0bf62261ac0787eff347d0fcd62257301ede9603106ea41650a3e3119bd5c4e86a7f6a3f00934f3a545f7f21d41699f3e35d38cf925a8bdaf2bf7eedea11c31c3d8bf6c527c77c6378281cdf02211a58fa5e46d28d7e7c5fb79d69b31703fd752395da115845952cf99aaeb2155c2ab951a69f67d938f223185567e52cfa3e57b62c790bf78674c4b02c12b7d3225fe8f705b408ba11c24245b3924482e2f3480994461b550641a88cd941d371139f3498afacdcba1249631402b20695760eaada5376e68df0e45139c410700effc9420dc3726515e7fcb3f349320f30511451964bd9b6530682efec65910ceb548aa2ab05ac3309e803161697213631ae8e13cc7d223ac28446c1bf94a19a8782ac16ff57df7ee4f10fb6e488c02c68d6b6dee6987f6d2c39227da366c59f54ff67e312ca530e7c467c3dc8", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_2.snap index cc4da55c462..bd58f0be7e7 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/block_by_height_raw_data@testnet_2.snap @@ -5,14 +5,14 @@ expression: cf_data [ KV( k: "000000", - v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + v: "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000a11e1358ffff07200600000000000000000000000000000000000000000000000000000000000000fd400500a6a51259c3f6732481e2d035197218b7a69504461d04335503cd69759b2d02bd2b53a9653f42cb33c608511c953673fa9da76170958115fe92157ad3bb5720d927f18e09459bf5c6072973e143e20f9bdf0584058c96b7c2234c7565f100d5eea083ba5d3dbaff9f0681799a113e7beff4a611d2b49590563109962baa149b628aae869af791f2f70bb041bd7ebfa658570917f6654a142b05e7ec0289a4f46470be7be5f693b90173eaaa6e84907170f32602204f1f4e1c04b1830116ffd0c54f0b1caa9a5698357bd8aa1f5ac8fc93b405265d824ba0e49f69dab5446653927298e6b7bdc61ee86ff31c07bde86331b4e500d42e4e50417e285502684b7966184505b885b42819a88469d1e9cf55072d7f3510f85580db689302eab377e4e11b14a91fdd0df7627efc048934f0aff8e7eb77eb17b3a95de13678004f2512293891d8baf8dde0ef69be520a58bbd6038ce899c9594cf3e30b8c3d9c7ecc832d4c19a6212747b50724e6f70f6451f78fd27b58ce43ca33b1641304a916186cfbe7dbca224f55d08530ba851e4df22baf7ab7078e9cbea46c0798b35a750f54103b0cdd08c81a6505c4932f6bfbd492a9fced31d54e98b6370d4c96600552fcf5b37780ed18c8787d03200963600db297a8f05dfa551321d17b9917edadcda51e274830749d133ad226f8bb6b94f13b4f77e67b35b71f52112ce9ba5da706ad9573584a2570a4ff25d29ab9761a06bdcf2c33638bf9baf2054825037881c14adf3816ba0cbd0fca689aad3ce16f2fe362c98f48134a9221765d939f0b49677d1c2447e56b46859f1810e2cf23e82a53e0d44f34dae932581b3b7f49eaec59af872cf9de757a964f7b33d143a36c270189508fcafe19398e4d2966948164d40556b05b7ff532f66f5d1edc41334ef742f78221dfe0c7ae2275bb3f24c89ae35f00afeea4e6ed187b866b209dc6e83b660593fce7c40e143beb07ac86c56f39e895385924667efe3a3f031938753c7764a2dbeb0a643fd359c46e614873fd0424e435fa7fac083b9a41a9d6bf7e284eee537ea7c50dd239f359941a43dc982745184bf3ee31a8dc850316aa9c6b66d6985acee814373be3458550659e1a06287c3b3b76a185c5cb93e38c1eebcf34ff072894b6430aed8d34122dafd925c46a515cca79b0269c92b301890ca6b0dc8b679cdac0f23318c105de73d7a46d16d2dad988d49c22e9963c117960bdc70ef0db6b091cf09445a516176b7f6d58ec29539166cc8a38bbff387acefffab2ea5faad0e8bb70625716ef0edf61940733c25993ea3de9f0be23d36e7cb8da10505f9dc426cd0e6e5b173ab4fff8c37e1f1fb56d1ea372013d075e0934c6919393cfc21395eea20718fad03542a4162a9ded66c814ad8320b2d7c2da3ecaf206da34c502db2096d1c46699a91dd1c432f019ad434e2c1ce507f91104f66f491fed37b225b8e0b2888c37276cfa0468fc13b8d593fd9a2675f0f5b20b8a15f8fa7558176a530d6865738ddb25d3426dab905221681cf9da0e0200eea5b2eba3ad3a5237d2a391f9074bf1779a2005cee43eec2b058511532635e0fea61664f531ac2b356f40db5c5d275a4cf5c82d468976455af4e3362cc8f71aa95e71d394aff3ead6f7101279f95bcd8a0fedce1d21cb3c9f6dd3b182fce0db5d6712981b651f29178a24119968b14783cafa713bc5f2a65205a42e4ce9dc7ba462bdb1f3e4553afc15f5f39998fdb53e7e231e3e520a46943734a007c2daa1eda9f495791657eefcac5c32833936e568d06187857ed04d7b97167ae207c5c5ae54e528c36016a984235e9c5b2f0718d7b3aa93c7822ccc772580b6599671b3c02ece8a21399abd33cfd3028790133167d0a97e7de53dc8ff", ), KV( k: "000001", - v: "04000000382c4a332661c7ed0671f32a34d724619f086c61873bce7c99859dd9920aa605755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef30000000000000000000000000000000000000000000000000000000000000000e9851358ffff0720000056c2264c31261d597c6fcea7c5e00160cf6be1cd89ca96a0389473e50000fd40050053f4438864bc5d6dfc009d4bba545ac5e5feaaf46f9455b975b02115f842a966e26517ce678f1c074d09cc8d0049a190859eb505af5f3e760312fbbe54da115db2bc03c96408f39b679891790b539d2d9d17a801dc6af9af14ca3f6ba060edce2a1dd45aa45f11fe37dbaf1eb2647ae7c393f6680c3d5d7e53687e34530f48edf58924a04d3e0231c150b1c8218998f674bc171edd222bcb4ac4ba4ea52d7baa86399f371d5284043e1e166f9069dd0f2904ff94c7922a70fa7c660e0553cc40a20d9ee08eb3f47278485801ddae9c270411360773f0b74e03db2d92c50952c9bd4924bbca2a260e1235e99df51fe71e75744232f2d641ef94f394110a5ad05f51a057e4cb515b92c16cb1404a8cdcc43d4a4bb2caa54ca35dccf41aa7d832da65123b7029223c46ed2a13387d598d445435d3cb32fdad9e27672903864c90d86353b162033078327b5b7aaffc89b40096ae004f2d5c6bd2c99188574348518db66e9b6020f93f12ee1c06f7b00fe346fefceaffb1da9e3cdf08285057f549733eb10825737fcd1431bfdfb155f323f24e95a869212baacf445b30f2670206645779110e6547d5da90a5f2fe5151da911d5ecd5a833023661d1356b6c395d85968947678d53efd4db7b06f23b21125e74492644277ea0c1131b80d6a4e3e8093b82332556fbb3255a55ac3f0b7e4844c0e12bf577c37fd02323ae5ef4781772ed501d63b568032a3d31576c5104a48c01ac54f715286932351a8adc8cf2467a84a0572e99f366ee00f82c3735545fd4bb941d591ce70070425a81304272db89887949bc7dd8236bb7e82190f9815da938cd6e8fec7660e91354326a7a9bfe38120e97997fca3c289d54513ed00286c2b825fbe84f91a39528f335674b5e957425a6edfdd00f2feb2c2df575616197998c1e964e069875d4d934f419a9b02b100848d023b76d47bd4e284c3895ef9227a40d8ea8826e86c7155d6aa95b8f9175812523a32cd611efc700688e03f7c245c5bff01718281b5d75cefe8318b2c08962236b14a0bf79534c203df735fd9cced97cbae07c2b4ee9cda8c9993f3f6277ff3fec261fb94d3961c4befe4b0893dcf67b312c7d8d6ff7adc8539cb2b1d3534fccf109efddd07a9f1e77b94ab1e505b164221dca1c34621b1e9d234c31a032a401267d95f65b800d579a2482638dfeade804149c81e95d7ef5510ac0b6212231506b1c635a2e1d2f0c9712989f9f246762fadb4c55c20f707dcc0e510a33e9465fc5d5bdbfa524dab0d7a1c6a1baaa36869cf542aa2257c5c44ef07547a570343442c6091e13bc04d559dc0e6db5b001861914bf956816edce2a86b274bd97f27e2dbb08608c16a3e5d8595952faa91fb162d7fa6a7a47e849a1ad8fab3ba620ee3295a04fe13e5fb655ac92ae60d01020b8999526af8d56b28733e69c9ffb285de27c61edc0bf62261ac0787eff347d0fcd62257301ede9603106ea41650a3e3119bd5c4e86a7f6a3f00934f3a545f7f21d41699f3e35d38cf925a8bdaf2bf7eedea11c31c3d8bf6c527c77c6378281cdf02211a58fa5e46d28d7e7c5fb79d69b31703fd752395da115845952cf99aaeb2155c2ab951a69f67d938f223185567e52cfa3e57b62c790bf78674c4b02c12b7d3225fe8f705b408ba11c24245b3924482e2f3480994461b550641a88cd941d371139f3498afacdcba1249631402b20695760eaada5376e68df0e45139c410700effc9420dc3726515e7fcb3f349320f30511451964bd9b6530682efec65910ceb548aa2ab05ac3309e803161697213631ae8e13cc7d223ac28446c1bf94a19a8782ac16ff57df7ee4f10fb6e488c02c68d6b6dee6987f6d2c39227da366c59f54ff67e312ca530e7c467c3dc80101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0250c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99acd43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + v: "04000000382c4a332661c7ed0671f32a34d724619f086c61873bce7c99859dd9920aa605755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef30000000000000000000000000000000000000000000000000000000000000000e9851358ffff0720000056c2264c31261d597c6fcea7c5e00160cf6be1cd89ca96a0389473e50000fd40050053f4438864bc5d6dfc009d4bba545ac5e5feaaf46f9455b975b02115f842a966e26517ce678f1c074d09cc8d0049a190859eb505af5f3e760312fbbe54da115db2bc03c96408f39b679891790b539d2d9d17a801dc6af9af14ca3f6ba060edce2a1dd45aa45f11fe37dbaf1eb2647ae7c393f6680c3d5d7e53687e34530f48edf58924a04d3e0231c150b1c8218998f674bc171edd222bcb4ac4ba4ea52d7baa86399f371d5284043e1e166f9069dd0f2904ff94c7922a70fa7c660e0553cc40a20d9ee08eb3f47278485801ddae9c270411360773f0b74e03db2d92c50952c9bd4924bbca2a260e1235e99df51fe71e75744232f2d641ef94f394110a5ad05f51a057e4cb515b92c16cb1404a8cdcc43d4a4bb2caa54ca35dccf41aa7d832da65123b7029223c46ed2a13387d598d445435d3cb32fdad9e27672903864c90d86353b162033078327b5b7aaffc89b40096ae004f2d5c6bd2c99188574348518db66e9b6020f93f12ee1c06f7b00fe346fefceaffb1da9e3cdf08285057f549733eb10825737fcd1431bfdfb155f323f24e95a869212baacf445b30f2670206645779110e6547d5da90a5f2fe5151da911d5ecd5a833023661d1356b6c395d85968947678d53efd4db7b06f23b21125e74492644277ea0c1131b80d6a4e3e8093b82332556fbb3255a55ac3f0b7e4844c0e12bf577c37fd02323ae5ef4781772ed501d63b568032a3d31576c5104a48c01ac54f715286932351a8adc8cf2467a84a0572e99f366ee00f82c3735545fd4bb941d591ce70070425a81304272db89887949bc7dd8236bb7e82190f9815da938cd6e8fec7660e91354326a7a9bfe38120e97997fca3c289d54513ed00286c2b825fbe84f91a39528f335674b5e957425a6edfdd00f2feb2c2df575616197998c1e964e069875d4d934f419a9b02b100848d023b76d47bd4e284c3895ef9227a40d8ea8826e86c7155d6aa95b8f9175812523a32cd611efc700688e03f7c245c5bff01718281b5d75cefe8318b2c08962236b14a0bf79534c203df735fd9cced97cbae07c2b4ee9cda8c9993f3f6277ff3fec261fb94d3961c4befe4b0893dcf67b312c7d8d6ff7adc8539cb2b1d3534fccf109efddd07a9f1e77b94ab1e505b164221dca1c34621b1e9d234c31a032a401267d95f65b800d579a2482638dfeade804149c81e95d7ef5510ac0b6212231506b1c635a2e1d2f0c9712989f9f246762fadb4c55c20f707dcc0e510a33e9465fc5d5bdbfa524dab0d7a1c6a1baaa36869cf542aa2257c5c44ef07547a570343442c6091e13bc04d559dc0e6db5b001861914bf956816edce2a86b274bd97f27e2dbb08608c16a3e5d8595952faa91fb162d7fa6a7a47e849a1ad8fab3ba620ee3295a04fe13e5fb655ac92ae60d01020b8999526af8d56b28733e69c9ffb285de27c61edc0bf62261ac0787eff347d0fcd62257301ede9603106ea41650a3e3119bd5c4e86a7f6a3f00934f3a545f7f21d41699f3e35d38cf925a8bdaf2bf7eedea11c31c3d8bf6c527c77c6378281cdf02211a58fa5e46d28d7e7c5fb79d69b31703fd752395da115845952cf99aaeb2155c2ab951a69f67d938f223185567e52cfa3e57b62c790bf78674c4b02c12b7d3225fe8f705b408ba11c24245b3924482e2f3480994461b550641a88cd941d371139f3498afacdcba1249631402b20695760eaada5376e68df0e45139c410700effc9420dc3726515e7fcb3f349320f30511451964bd9b6530682efec65910ceb548aa2ab05ac3309e803161697213631ae8e13cc7d223ac28446c1bf94a19a8782ac16ff57df7ee4f10fb6e488c02c68d6b6dee6987f6d2c39227da366c59f54ff67e312ca530e7c467c3dc8", ), KV( k: "000002", - v: "04000000238d665a062b9007836a7d8f968ba2f3847af5f542733389a952cf9b86795502d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c022580000000000000000000000000000000000000000000000000000000000000000898c1358ffff072000005b7d311fedc046109a4482bd0eccdf21a6089c99fce43633d03352530000fd400500282db5ba22a2c122aba42724a991196cd01cc2b7013318f691d61171db79202d2e5979b0b6d5692cd129eb37b7541ff51b7b2a840b45273f86d2509acfaa39183bb3850f9916ec8246ad9ee785462c9cda0ea202f12c7ccba8cc155096016a87a6fc40a6a44f5f3b309a868f30d9080b128c75234a6c3d019fb7fbe29708d01daaab84e4891a00d15ffdd9a598dd678899102265e2090a4b7b26ec55764febbfd1f5fe791aef8500619578359cb2abfb19844981b5c0e67e86b6549765bd638f3a701b0fc8a56d00c4efb87b55883f1d81012e5b02d44e10ec9bf620f20ad62ca549be934d11103f9142b3201ff31b7791c1636aaeadc512b2c0f801a64959300d5d526c2fc58e2838162659fe59168f2214b41d1ec963d543e2660ea630d031e2671c8c841fa9c1b58f7475bfe958724cf89c038d29306dc0043b93148ab95f6e99017ec5863db2f9130c48187bfd013924b34eaefd1db6b2818f4f6a604185fa774c2c069455c6eb195a5382403404c47db312b29b5d84e44c4a645f06ef7899f0b78962e95d5476bc989dcb9458c24733a435b151c9fb46c32cbebd3318cf3ed7310533cfa0b087d58c687505070858765968d1f7077f0e6dd75ebf15d74bb8c7466ef2f4974df537f5dd64097f4adf8b1cff61c00181ad26f94cca9c01960db31edc454c1650da4f4390b4aa0efd46c9ed527ed8bb068494285da2680993e8d355caf6a0bd42a4d681780db2312eef129aa76c6081ceff231311ea93fd65fb0b80df077c49ca69d8996b1ebcfd74bad793d7914b4748af45f31ad018dd12997bfcf809df3894bbd7a10cc585797915356389b744f71ee58ac25484b635fe12a1b20909c97edb1d7ae20b1ef1c776260ebab06e16a34c2789fb5555ddc954cc38f07ac551ac3b46c1370f4fa1ba22ac35d82134eaa0d3f3198eeef723030072214ede447893a03f706d389ea60ef8a81ff7e20ae920cb1a5219e93e1bd2058df6296dc8ba39e4d403199d2c209c3d6b3b2d462aecc04b0e248e7f1e9d204a1f6b7df51073ae2faab55be3353713743c5db40555bebda203a5c79fc3324cb8fb7629c9391931a1268c97fad6d6ab7ebc583330356372df8c5e9e885422c75ab956932351858452c5904a5aad3d9fd840e356abd580479d9a531cda6de08277008bb3a1bdf08604c1df0d8e8cd475cb455161bfe5d9710bc0dfac4214afeeed4bca6148b54241b8f4ab221502917f261705715c7388d9e91d3685a1f67c484a24b716912fe33a89ca7ebc3a5b77e6b36657c7e2b2e1e8b2b699690ca749339b7b2673fb1083496bbc753fdfc49ff6e921c5e35f27d9175afa7da3793d6a7ad5eb0ab8c9ee0e60a8ae438e3145cf64b5f6417625ca934b9d7acc150efa9b53618c15b4d8318be5de0855696d92ef2e018d97ebd24102e824bbd040aed958a51016a91661180e64932f2316b5ee55923263d19d293996118f511f22912e8c9c435af630099fc47b7c4ab581b7d760418314c0e6e814b3bbddb486517436d56ddc774701072cd77beada2cc94cad87f3d1cb83db4da05c2e141bc175bc8848e548c27584995333ef1d9eadd8d7f028cae60d5b0e9642db7245d388ff58c6a31556319a29c0dc14362b957b6220a428966d66d6c3339a12a503806de7dc4c4561bab6968245e41b27ae89fffbfd1bd2f4104d074f0f2b759576f9e16c0e2f73bedc7c0e0da97698e07ca1d729b113938a6b29c3b19d9b8225303f80d6dc0e39bec343ac9a2d23926ab414666e079e68745998ff73dacbe1645bd004dd06236f615f11d47e9b2d54cf8573d9a295bda88af4b2c6c603db0c0757485a543725b1cc04f7e9f38445ed875ec54317418600b4113600e137417e5d1fc333159a7e365d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03520103ffffffff02a086010000000000232102acce9f6c16986c525fd34759d851ef5b4b85b5019a57bd59747be0ef1ba62523aca86100000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + v: "04000000238d665a062b9007836a7d8f968ba2f3847af5f542733389a952cf9b86795502d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c022580000000000000000000000000000000000000000000000000000000000000000898c1358ffff072000005b7d311fedc046109a4482bd0eccdf21a6089c99fce43633d03352530000fd400500282db5ba22a2c122aba42724a991196cd01cc2b7013318f691d61171db79202d2e5979b0b6d5692cd129eb37b7541ff51b7b2a840b45273f86d2509acfaa39183bb3850f9916ec8246ad9ee785462c9cda0ea202f12c7ccba8cc155096016a87a6fc40a6a44f5f3b309a868f30d9080b128c75234a6c3d019fb7fbe29708d01daaab84e4891a00d15ffdd9a598dd678899102265e2090a4b7b26ec55764febbfd1f5fe791aef8500619578359cb2abfb19844981b5c0e67e86b6549765bd638f3a701b0fc8a56d00c4efb87b55883f1d81012e5b02d44e10ec9bf620f20ad62ca549be934d11103f9142b3201ff31b7791c1636aaeadc512b2c0f801a64959300d5d526c2fc58e2838162659fe59168f2214b41d1ec963d543e2660ea630d031e2671c8c841fa9c1b58f7475bfe958724cf89c038d29306dc0043b93148ab95f6e99017ec5863db2f9130c48187bfd013924b34eaefd1db6b2818f4f6a604185fa774c2c069455c6eb195a5382403404c47db312b29b5d84e44c4a645f06ef7899f0b78962e95d5476bc989dcb9458c24733a435b151c9fb46c32cbebd3318cf3ed7310533cfa0b087d58c687505070858765968d1f7077f0e6dd75ebf15d74bb8c7466ef2f4974df537f5dd64097f4adf8b1cff61c00181ad26f94cca9c01960db31edc454c1650da4f4390b4aa0efd46c9ed527ed8bb068494285da2680993e8d355caf6a0bd42a4d681780db2312eef129aa76c6081ceff231311ea93fd65fb0b80df077c49ca69d8996b1ebcfd74bad793d7914b4748af45f31ad018dd12997bfcf809df3894bbd7a10cc585797915356389b744f71ee58ac25484b635fe12a1b20909c97edb1d7ae20b1ef1c776260ebab06e16a34c2789fb5555ddc954cc38f07ac551ac3b46c1370f4fa1ba22ac35d82134eaa0d3f3198eeef723030072214ede447893a03f706d389ea60ef8a81ff7e20ae920cb1a5219e93e1bd2058df6296dc8ba39e4d403199d2c209c3d6b3b2d462aecc04b0e248e7f1e9d204a1f6b7df51073ae2faab55be3353713743c5db40555bebda203a5c79fc3324cb8fb7629c9391931a1268c97fad6d6ab7ebc583330356372df8c5e9e885422c75ab956932351858452c5904a5aad3d9fd840e356abd580479d9a531cda6de08277008bb3a1bdf08604c1df0d8e8cd475cb455161bfe5d9710bc0dfac4214afeeed4bca6148b54241b8f4ab221502917f261705715c7388d9e91d3685a1f67c484a24b716912fe33a89ca7ebc3a5b77e6b36657c7e2b2e1e8b2b699690ca749339b7b2673fb1083496bbc753fdfc49ff6e921c5e35f27d9175afa7da3793d6a7ad5eb0ab8c9ee0e60a8ae438e3145cf64b5f6417625ca934b9d7acc150efa9b53618c15b4d8318be5de0855696d92ef2e018d97ebd24102e824bbd040aed958a51016a91661180e64932f2316b5ee55923263d19d293996118f511f22912e8c9c435af630099fc47b7c4ab581b7d760418314c0e6e814b3bbddb486517436d56ddc774701072cd77beada2cc94cad87f3d1cb83db4da05c2e141bc175bc8848e548c27584995333ef1d9eadd8d7f028cae60d5b0e9642db7245d388ff58c6a31556319a29c0dc14362b957b6220a428966d66d6c3339a12a503806de7dc4c4561bab6968245e41b27ae89fffbfd1bd2f4104d074f0f2b759576f9e16c0e2f73bedc7c0e0da97698e07ca1d729b113938a6b29c3b19d9b8225303f80d6dc0e39bec343ac9a2d23926ab414666e079e68745998ff73dacbe1645bd004dd06236f615f11d47e9b2d54cf8573d9a295bda88af4b2c6c603db0c0757485a543725b1cc04f7e9f38445ed875ec54317418600b4113600e137417e5d1fc333159a7e365d", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/column_family_names.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/column_family_names.snap index 9d4578554db..cde7c9aab7f 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/column_family_names.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/column_family_names.snap @@ -1,13 +1,13 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 41 expression: cf_names - --- [ + "balance_by_transparent_addr", "block_by_height", "default", "hash_by_height", + "hash_by_tx_loc", "height_by_hash", "history_tree", "orchard_anchors", @@ -21,5 +21,6 @@ expression: cf_names "sprout_nullifiers", "tip_chain_value_pool", "tx_by_hash", + "tx_by_loc", "utxo_by_outpoint", ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_0.snap index ccedb7da156..1b887c09937 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_0.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_0.snap @@ -1,10 +1,9 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ + "balance_by_transparent_addr: no entries", "history_tree: no entries", "orchard_anchors: no entries", "orchard_nullifiers: no entries", @@ -13,6 +12,5 @@ expression: empty_column_families "sprout_anchors: no entries", "sprout_nullifiers: no entries", "tip_chain_value_pool: no entries", - "tx_by_hash: no entries", "utxo_by_outpoint: no entries", ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_1.snap index 04606c4d166..c2606c3e4b8 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_1.snap @@ -1,8 +1,6 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ "history_tree: no entries", diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_2.snap index 04606c4d166..c2606c3e4b8 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@mainnet_2.snap @@ -1,8 +1,6 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ "history_tree: no entries", diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@no_blocks.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@no_blocks.snap index 92b776bf185..f83855a2d18 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@no_blocks.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@no_blocks.snap @@ -1,12 +1,12 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ + "balance_by_transparent_addr: no entries", "block_by_height: no entries", "hash_by_height: no entries", + "hash_by_tx_loc: no entries", "height_by_hash: no entries", "history_tree: no entries", "orchard_anchors: no entries", @@ -20,5 +20,6 @@ expression: empty_column_families "sprout_nullifiers: no entries", "tip_chain_value_pool: no entries", "tx_by_hash: no entries", + "tx_by_loc: no entries", "utxo_by_outpoint: no entries", ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_0.snap index ccedb7da156..1b887c09937 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_0.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_0.snap @@ -1,10 +1,9 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ + "balance_by_transparent_addr: no entries", "history_tree: no entries", "orchard_anchors: no entries", "orchard_nullifiers: no entries", @@ -13,6 +12,5 @@ expression: empty_column_families "sprout_anchors: no entries", "sprout_nullifiers: no entries", "tip_chain_value_pool: no entries", - "tx_by_hash: no entries", "utxo_by_outpoint: no entries", ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_1.snap index 04606c4d166..c2606c3e4b8 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_1.snap @@ -1,8 +1,6 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ "history_tree: no entries", diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_2.snap index 04606c4d166..c2606c3e4b8 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/empty_column_families@testnet_2.snap @@ -1,8 +1,6 @@ --- source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs -assertion_line: 140 expression: empty_column_families - --- [ "history_tree: no entries", diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_0.snap new file mode 100644 index 00000000000..7d2c328722c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_1.snap new file mode 100644 index 00000000000..05a414d0f0b --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_1.snap @@ -0,0 +1,14 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), + KV( + k: "0000010000", + v: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b85", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_2.snap new file mode 100644 index 00000000000..ee3bfedcb8f --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@mainnet_2.snap @@ -0,0 +1,18 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), + KV( + k: "0000010000", + v: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b85", + ), + KV( + k: "0000020000", + v: "f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd07489", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_0.snap new file mode 100644 index 00000000000..7d2c328722c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_1.snap new file mode 100644 index 00000000000..3732b7a027c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_1.snap @@ -0,0 +1,14 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), + KV( + k: "0000010000", + v: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef3", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_2.snap new file mode 100644 index 00000000000..a8ba7487fcc --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/hash_by_tx_loc_raw_data@testnet_2.snap @@ -0,0 +1,18 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + ), + KV( + k: "0000010000", + v: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef3", + ), + KV( + k: "0000020000", + v: "d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c02258", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_0.snap new file mode 100644 index 00000000000..4ea246afb4d --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_1.snap index b2833ecaefe..5660a3684d2 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_1.snap @@ -7,4 +7,8 @@ expression: cf_data k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b85", v: "0000010000", ), + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_2.snap index 9645d50aa5e..b5426feac3f 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@mainnet_2.snap @@ -7,6 +7,10 @@ expression: cf_data k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b85", v: "0000010000", ), + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), KV( k: "f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd07489", v: "0000020000", diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_0.snap new file mode 100644 index 00000000000..4ea246afb4d --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_1.snap index e4ad2a9694e..66ff4d26dd3 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_1.snap @@ -7,4 +7,8 @@ expression: cf_data k: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef3", v: "0000010000", ), + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_2.snap index cff37221577..f1a52743b89 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_hash_raw_data@testnet_2.snap @@ -11,4 +11,8 @@ expression: cf_data k: "d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c02258", v: "0000020000", ), + KV( + k: "db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4", + v: "0000000000", + ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_0.snap new file mode 100644 index 00000000000..8ced65ede12 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_1.snap new file mode 100644 index 00000000000..317fd0fc83c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_1.snap @@ -0,0 +1,14 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), + KV( + k: "0000010000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025100ffffffff0250c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875acd43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_2.snap new file mode 100644 index 00000000000..1dc5c1e0bc4 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@mainnet_2.snap @@ -0,0 +1,18 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), + KV( + k: "0000010000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025100ffffffff0250c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875acd43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + ), + KV( + k: "0000020000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025200ffffffff02a0860100000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875aca86100000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a8700000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_0.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_0.snap new file mode 100644 index 00000000000..8ced65ede12 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_0.snap @@ -0,0 +1,10 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_1.snap new file mode 100644 index 00000000000..23426696f3c --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_1.snap @@ -0,0 +1,14 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), + KV( + k: "0000010000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0250c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99acd43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_2.snap new file mode 100644 index 00000000000..0cef85d4487 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/tx_by_loc_raw_data@testnet_2.snap @@ -0,0 +1,18 @@ +--- +source: zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +expression: cf_data +--- +[ + KV( + k: "0000000000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + ), + KV( + k: "0000010000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0250c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99acd43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + ), + KV( + k: "0000020000", + v: "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03520103ffffffff02a086010000000000232102acce9f6c16986c525fd34759d851ef5b4b85b5019a57bd59747be0ef1ba62523aca86100000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c6428700000000", + ), +] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_1.snap index 61687a76f32..4630a1d5647 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_1.snap @@ -4,11 +4,11 @@ expression: cf_data --- [ KV( - k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b8500000000", + k: "0000010000000000", v: "0000010150c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875ac", ), KV( - k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b8501000000", + k: "0000010000000001", v: "00000101d43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a87", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_2.snap index 2f2c982943a..c2bf99ce4ff 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@mainnet_2.snap @@ -4,19 +4,19 @@ expression: cf_data --- [ KV( - k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b8500000000", + k: "0000010000000000", v: "0000010150c30000000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875ac", ), KV( - k: "0946edb9c083c9942d92305444527765fad789c438c717783276a9f7fbf61b8501000000", + k: "0000010000000001", v: "00000101d43000000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a87", ), KV( - k: "f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd0748900000000", + k: "0000020000000000", v: "00000201a0860100000000002321027a46eb513588b01b37ea24303f4b628afd12cc20df789fede0921e43cad3e875ac", ), KV( - k: "f4b084a7c2fc5a5aa2985f2bcb1d4a9a65562a589d628b0d869c5f1c8dd0748901000000", + k: "0000020000000001", v: "00000201a86100000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a87", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_1.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_1.snap index b153b108efc..dfd6f813feb 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_1.snap @@ -4,11 +4,11 @@ expression: cf_data --- [ KV( - k: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef300000000", + k: "0000010000000000", v: "0000010150c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99ac", ), KV( - k: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef301000000", + k: "0000010000000001", v: "00000101d43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c64287", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_2.snap b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_2.snap index 28dcd57e3d1..ea774a64e7a 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshots/utxo_by_outpoint_raw_data@testnet_2.snap @@ -4,19 +4,19 @@ expression: cf_data --- [ KV( - k: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef300000000", + k: "0000010000000000", v: "0000010150c30000000000002321025229e1240a21004cf8338db05679fa34753706e84f6aebba086ba04317fd8f99ac", ), KV( - k: "755f7c7d27a811596e9fae6dd30ca45be86e901d499909de35b6ff1f699f7ef301000000", + k: "0000010000000001", v: "00000101d43000000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c64287", ), KV( - k: "d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c0225800000000", + k: "0000020000000000", v: "00000201a086010000000000232102acce9f6c16986c525fd34759d851ef5b4b85b5019a57bd59747be0ef1ba62523ac", ), KV( - k: "d5b3ccfd5e7828c4b2d221bae3178c500e21d33399c39a2508a0a82d53c0225801000000", + k: "0000020000000001", v: "00000201a86100000000000017a914ef775f1f997f122a062fff1a2d7443abd1f9c64287", ), ] diff --git a/zebra-state/src/service/finalized_state/disk_format/transparent.rs b/zebra-state/src/service/finalized_state/disk_format/transparent.rs index cb0d5f4da12..57e25df902b 100644 --- a/zebra-state/src/service/finalized_state/disk_format/transparent.rs +++ b/zebra-state/src/service/finalized_state/disk_format/transparent.rs @@ -10,35 +10,61 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; use zebra_chain::{ + amount::{Amount, NonNegative}, block::Height, + parameters::Network::*, serialization::{ZcashDeserializeInto, ZcashSerialize}, - transaction, transparent, + transparent::{self, Address::*}, }; -use crate::service::finalized_state::disk_format::{block::HEIGHT_DISK_BYTES, FromDisk, IntoDisk}; +use crate::service::finalized_state::disk_format::{ + block::{ + TransactionIndex, TransactionLocation, HEIGHT_DISK_BYTES, TRANSACTION_LOCATION_DISK_BYTES, + }, + expand_zero_be_bytes, truncate_zero_be_bytes, FromDisk, IntoDisk, +}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; -/// Output transaction locations are stored as a 32 byte transaction hash on disk. +#[cfg(any(test, feature = "proptest-impl"))] +mod arbitrary; + +/// Transparent balances are stored as an 8 byte integer on disk. +pub const BALANCE_DISK_BYTES: usize = 8; + +/// [`OutputIndex`]es are stored as 3 bytes on disk. /// -/// TODO: change to TransactionLocation to reduce database size and increases lookup performance (#3151) -pub const OUTPUT_TX_HASH_DISK_BYTES: usize = 32; +/// This reduces database size and increases lookup performance. +pub const OUTPUT_INDEX_DISK_BYTES: usize = 3; -/// [`OutputIndex`]es are stored as 4 bytes on disk. +/// [`OutputLocation`]s are stored as a 3 byte height, 2 byte transaction index, +/// and 3 byte output index on disk. /// -/// TODO: change to 3 bytes to reduce database size and increases lookup performance (#3151) -pub const OUTPUT_INDEX_DISK_BYTES: usize = 4; +/// This reduces database size and increases lookup performance. +pub const OUTPUT_LOCATION_DISK_BYTES: usize = + TRANSACTION_LOCATION_DISK_BYTES + OUTPUT_INDEX_DISK_BYTES; // Transparent types -/// A transaction's index in its block. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +/// A transparent output's index in its transaction. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub struct OutputIndex(u32); impl OutputIndex { - /// Create a transparent output index from the native index integer type. + /// Create a transparent output index from the Zcash consensus integer type. + /// + /// `u32` is also the inner type. + pub fn from_index(output_index: u32) -> OutputIndex { + OutputIndex(output_index) + } + + /// Returns this index as the inner type. + pub fn index(&self) -> u32 { + self.0 + } + + /// Create a transparent output index from `usize`. #[allow(dead_code)] pub fn from_usize(output_index: usize) -> OutputIndex { OutputIndex( @@ -48,7 +74,7 @@ impl OutputIndex { ) } - /// Return this index as the native index integer type. + /// Return this index as `usize`. #[allow(dead_code)] pub fn as_usize(&self) -> usize { self.0 @@ -56,93 +82,330 @@ impl OutputIndex { .expect("the maximum valid index fits in usize") } - /// Create a transparent output index from the Zcash consensus integer type. - pub fn from_zcash(output_index: u32) -> OutputIndex { - OutputIndex(output_index) + /// Create a transparent output index from `u64`. + #[allow(dead_code)] + pub fn from_u64(output_index: u64) -> OutputIndex { + OutputIndex( + output_index + .try_into() + .expect("the maximum u64 index fits in the inner type"), + ) } - /// Return this index as the Zcash consensus integer type. + /// Return this index as `u64`. #[allow(dead_code)] - pub fn as_zcash(&self) -> u32 { - self.0 + pub fn as_u64(&self) -> u64 { + self.0.into() } } /// A transparent output's location in the chain, by block height and transaction index. /// -/// TODO: provide a chain-order list of transactions (#3150) -/// derive Ord, PartialOrd (#3150) -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +/// [`OutputLocation`]s are sorted in increasing chain order, by height, transaction index, +/// and output index. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct OutputLocation { - /// The transaction hash. - pub hash: transaction::Hash, + /// The location of the transparent input's transaction. + transaction_location: TransactionLocation, /// The index of the transparent output in its transaction. - pub index: OutputIndex, + output_index: OutputIndex, } impl OutputLocation { - /// Create a transparent output location from a transaction hash and index - /// (as the native index integer type). + /// Creates an output location from a block height, and `usize` transaction and output indexes. #[allow(dead_code)] - pub fn from_usize(hash: transaction::Hash, output_index: usize) -> OutputLocation { + pub fn from_usize( + height: Height, + transaction_index: usize, + output_index: usize, + ) -> OutputLocation { OutputLocation { - hash, - index: OutputIndex::from_usize(output_index), + transaction_location: TransactionLocation::from_usize(height, transaction_index), + output_index: OutputIndex::from_usize(output_index), } } - /// Create a transparent output location from a [`transparent::OutPoint`]. - pub fn from_outpoint(outpoint: &transparent::OutPoint) -> OutputLocation { + /// Creates an output location from an [`Outpoint`], + /// and the [`TransactionLocation`] of its transaction. + /// + /// The [`TransactionLocation`] is provided separately, + /// because the lookup is a database operation. + pub fn from_outpoint( + transaction_location: TransactionLocation, + outpoint: &transparent::OutPoint, + ) -> OutputLocation { + OutputLocation::from_output_index(transaction_location, outpoint.index) + } + + /// Creates an output location from a [`TransactionLocation`] and a `u32` output index. + /// + /// Output indexes are serialized to `u32` in the Zcash consensus-critical transaction format. + pub fn from_output_index( + transaction_location: TransactionLocation, + output_index: u32, + ) -> OutputLocation { OutputLocation { - hash: outpoint.hash, - index: OutputIndex::from_zcash(outpoint.index), + transaction_location, + output_index: OutputIndex::from_index(output_index), + } + } + + /// Returns the height of this [`transparent::Output`]. + #[allow(dead_code)] + pub fn height(&self) -> Height { + self.transaction_location.height + } + + /// Returns the transaction index of this [`transparent::Output`]. + #[allow(dead_code)] + pub fn transaction_index(&self) -> TransactionIndex { + self.transaction_location.index + } + + /// Returns the output index of this [`transparent::Output`]. + pub fn output_index(&self) -> OutputIndex { + self.output_index + } + + /// Returns the location of the transaction for this [`transparent::Output`]. + pub fn transaction_location(&self) -> TransactionLocation { + self.transaction_location + } + + /// Allows tests to set the height of this output location. + #[cfg(any(test, feature = "proptest-impl"))] + #[allow(dead_code)] + pub fn height_mut(&mut self) -> &mut Height { + &mut self.transaction_location.height + } +} + +/// The location of the first [`transparent::Output`] sent to an address. +/// +/// The address location stays the same, even if the corresponding output +/// has been spent. +/// +/// The first output location is used to represent the address in the database, +/// because output locations are significantly smaller than addresses. +/// +/// TODO: make this a different type to OutputLocation? +/// derive IntoDisk and FromDisk? +pub type AddressLocation = OutputLocation; + +/// Data which Zebra indexes for each [`transparent::Address`]. +/// +/// Currently, Zebra tracks this data 1:1 for each address: +/// - the balance [`Amount`] for a transparent address, and +/// - the [`OutputLocation`] for the first [`transparent::Output`] sent to that address +/// (regardless of whether that output is spent or unspent). +/// +/// All other address data is tracked multiple times for each address +/// (UTXOs and transactions). +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct AddressBalanceLocation { + /// The total balance of all UTXOs sent to an address. + balance: Amount, + + /// The location of the first [`transparent::Output`] sent to an address. + location: AddressLocation, +} + +impl AddressBalanceLocation { + /// Creates a new [`AddressBalanceLocation`] from the location of + /// the first [`transparent::Output`] sent to an address. + /// + /// The returned value has a zero initial balance. + pub fn new(first_output: OutputLocation) -> AddressBalanceLocation { + AddressBalanceLocation { + balance: Amount::zero(), + location: first_output, } } + + /// Returns the current balance for the address. + pub fn balance(&self) -> Amount { + self.balance + } + + /// Returns a mutable reference to the current balance for the address. + pub fn balance_mut(&mut self) -> &mut Amount { + &mut self.balance + } + + /// Returns the location of the first [`transparent::Output`] sent to an address. + pub fn location(&self) -> AddressLocation { + self.location + } + + /// Allows tests to set the height of the address location. + #[cfg(any(test, feature = "proptest-impl"))] + #[allow(dead_code)] + pub fn height_mut(&mut self) -> &mut Height { + &mut self.location.transaction_location.height + } } // Transparent trait impls -// TODO: serialize the index into a smaller number of bytes (#3152) -// serialize the index in big-endian order (#3150) +/// Returns a byte representing the [`transparent::Address`] variant. +fn address_variant(address: &transparent::Address) -> u8 { + // Return smaller values for more common variants. + // + // (This probably doesn't matter, but it might help slightly with data compression.) + match (address.network(), address) { + (Mainnet, PayToPublicKeyHash { .. }) => 0, + (Mainnet, PayToScriptHash { .. }) => 1, + (Testnet, PayToPublicKeyHash { .. }) => 2, + (Testnet, PayToScriptHash { .. }) => 3, + } +} + +impl IntoDisk for transparent::Address { + type Bytes = [u8; 21]; + + fn as_bytes(&self) -> Self::Bytes { + let variant_bytes = vec![address_variant(self)]; + let hash_bytes = self.hash_bytes().to_vec(); + + [variant_bytes, hash_bytes].concat().try_into().unwrap() + } +} + +#[cfg(any(test, feature = "proptest-impl"))] +impl FromDisk for transparent::Address { + fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { + let (address_variant, hash_bytes) = disk_bytes.as_ref().split_at(1); + + let address_variant = address_variant[0]; + let hash_bytes = hash_bytes.try_into().unwrap(); + + let network = if address_variant < 2 { + Mainnet + } else { + Testnet + }; + + if address_variant % 2 == 0 { + transparent::Address::from_pub_key_hash(network, hash_bytes) + } else { + transparent::Address::from_script_hash(network, hash_bytes) + } + } +} + +impl IntoDisk for Amount { + type Bytes = [u8; BALANCE_DISK_BYTES]; + + fn as_bytes(&self) -> Self::Bytes { + self.to_bytes() + } +} + +impl FromDisk for Amount { + fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { + let array = bytes.as_ref().try_into().unwrap(); + Amount::from_bytes(array).unwrap() + } +} + +// TODO: serialize the index into a smaller number of bytes (#3953) +// serialize the index in big-endian order (#3953) impl IntoDisk for OutputIndex { type Bytes = [u8; OUTPUT_INDEX_DISK_BYTES]; fn as_bytes(&self) -> Self::Bytes { - self.0.to_le_bytes() + let mem_bytes = self.index().to_be_bytes(); + + let disk_bytes = truncate_zero_be_bytes(&mem_bytes, OUTPUT_INDEX_DISK_BYTES); + + disk_bytes.try_into().unwrap() } } impl FromDisk for OutputIndex { fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { - OutputIndex(u32::from_le_bytes(disk_bytes.as_ref().try_into().unwrap())) + let mem_len = u32::BITS / 8; + let mem_len = mem_len.try_into().unwrap(); + + let mem_bytes = expand_zero_be_bytes(disk_bytes.as_ref(), mem_len); + let mem_bytes = mem_bytes.try_into().unwrap(); + OutputIndex::from_index(u32::from_be_bytes(mem_bytes)) } } impl IntoDisk for OutputLocation { - type Bytes = [u8; OUTPUT_TX_HASH_DISK_BYTES + OUTPUT_INDEX_DISK_BYTES]; + type Bytes = [u8; OUTPUT_LOCATION_DISK_BYTES]; fn as_bytes(&self) -> Self::Bytes { - let hash_bytes = self.hash.as_bytes().to_vec(); - let index_bytes = self.index.as_bytes().to_vec(); + let transaction_location_bytes = self.transaction_location().as_bytes().to_vec(); + let output_index_bytes = self.output_index().as_bytes().to_vec(); - [hash_bytes, index_bytes].concat().try_into().unwrap() + [transaction_location_bytes, output_index_bytes] + .concat() + .try_into() + .unwrap() } } impl FromDisk for OutputLocation { fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { - let (hash_bytes, index_bytes) = disk_bytes.as_ref().split_at(OUTPUT_TX_HASH_DISK_BYTES); + let (transaction_location_bytes, output_index_bytes) = disk_bytes + .as_ref() + .split_at(TRANSACTION_LOCATION_DISK_BYTES); - let hash = transaction::Hash::from_bytes(hash_bytes); - let index = OutputIndex::from_bytes(index_bytes); + let transaction_location = TransactionLocation::from_bytes(transaction_location_bytes); + let output_index = OutputIndex::from_bytes(output_index_bytes); + + OutputLocation { + transaction_location, + output_index, + } + } +} + +impl IntoDisk for AddressBalanceLocation { + type Bytes = [u8; BALANCE_DISK_BYTES + OUTPUT_LOCATION_DISK_BYTES]; + + fn as_bytes(&self) -> Self::Bytes { + let balance_bytes = self.balance().as_bytes().to_vec(); + let location_bytes = self.location().as_bytes().to_vec(); + + [balance_bytes, location_bytes].concat().try_into().unwrap() + } +} - OutputLocation { hash, index } +impl FromDisk for AddressBalanceLocation { + fn from_bytes(disk_bytes: impl AsRef<[u8]>) -> Self { + let (balance_bytes, location_bytes) = disk_bytes.as_ref().split_at(BALANCE_DISK_BYTES); + + let balance = Amount::from_bytes(balance_bytes.try_into().unwrap()).unwrap(); + let location = AddressLocation::from_bytes(location_bytes); + + let mut balance_location = AddressBalanceLocation::new(location); + *balance_location.balance_mut() = balance; + + balance_location + } +} + +impl IntoDisk for transparent::Output { + type Bytes = Vec; + + fn as_bytes(&self) -> Self::Bytes { + self.zcash_serialize_to_vec().unwrap() + } +} + +impl FromDisk for transparent::Output { + fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { + bytes.as_ref().zcash_deserialize_into().unwrap() } } -// TODO: just serialize the Output, and derive the Utxo data from OutputLocation (#3151) +// TODO: delete UTXO serialization (#3953) impl IntoDisk for transparent::Utxo { type Bytes = Vec; diff --git a/zebra-state/src/service/finalized_state/disk_format/transparent/arbitrary.rs b/zebra-state/src/service/finalized_state/disk_format/transparent/arbitrary.rs new file mode 100644 index 00000000000..c99385945f3 --- /dev/null +++ b/zebra-state/src/service/finalized_state/disk_format/transparent/arbitrary.rs @@ -0,0 +1,19 @@ +//! Randomised data generation for disk format property tests. + +use proptest::prelude::*; + +use zebra_chain::{serialization::TrustedPreallocate, transparent}; + +use super::OutputIndex; + +impl Arbitrary for OutputIndex { + type Parameters = (); + + fn arbitrary_with(_args: ()) -> Self::Strategy { + (0..=transparent::Output::max_allocation()) + .prop_map(OutputIndex::from_u64) + .boxed() + } + + type Strategy = BoxedStrategy; +} diff --git a/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs b/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs index c9792a53f08..1f2dc5726e9 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs @@ -4,7 +4,9 @@ use std::ops::Deref; -use zebra_chain::{amount::NonNegative, block::Block, sprout, value_balance::ValueBalance}; +use zebra_chain::{ + amount::NonNegative, block::Block, parameters::Network::*, sprout, value_balance::ValueBalance, +}; use crate::service::finalized_state::{ disk_db::{DiskDb, DiskWriteBatch, WriteDisk}, @@ -31,17 +33,17 @@ impl ZebraDb { /// Allow to set up a fake value pool in the database for testing purposes. pub fn set_finalized_value_pool(&self, fake_value_pool: ValueBalance) { - let mut batch = DiskWriteBatch::new(); + let mut batch = DiskWriteBatch::new(Mainnet); let value_pool_cf = self.db().cf_handle("tip_chain_value_pool").unwrap(); - batch.zs_insert(value_pool_cf, (), fake_value_pool); + batch.zs_insert(&value_pool_cf, (), fake_value_pool); self.db().write(batch).unwrap(); } /// Artificially prime the note commitment tree anchor sets with anchors /// referenced in a block, for testing purposes _only_. pub fn populate_with_anchors(&self, block: &Block) { - let mut batch = DiskWriteBatch::new(); + let mut batch = DiskWriteBatch::new(Mainnet); let sprout_anchors = self.db().cf_handle("sprout_anchors").unwrap(); let sapling_anchors = self.db().cf_handle("sapling_anchors").unwrap(); @@ -51,7 +53,7 @@ impl ZebraDb { // Sprout for joinsplit in transaction.sprout_groth16_joinsplits() { batch.zs_insert( - sprout_anchors, + &sprout_anchors, joinsplit.anchor, sprout::tree::NoteCommitmentTree::default(), ); @@ -59,12 +61,12 @@ impl ZebraDb { // Sapling for anchor in transaction.sapling_anchors() { - batch.zs_insert(sapling_anchors, anchor, ()); + batch.zs_insert(&sapling_anchors, anchor, ()); } // Orchard if let Some(orchard_shielded_data) = transaction.orchard_shielded_data() { - batch.zs_insert(orchard_anchors, orchard_shielded_data.shared_anchor, ()); + batch.zs_insert(&orchard_anchors, orchard_shielded_data.shared_anchor, ()); } } diff --git a/zebra-state/src/service/finalized_state/zebra_db/block.rs b/zebra-state/src/service/finalized_state/zebra_db/block.rs index 7fa7f9aecd3..220c9c9c176 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block.rs @@ -9,13 +9,19 @@ //! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must //! be incremented each time the database format (column, serialization, etc) changes. -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; + +use itertools::Itertools; use zebra_chain::{ amount::NonNegative, - block::{self, Block}, + block::{self, Block, Height}, history_tree::HistoryTree, parameters::{Network, GENESIS_PREVIOUS_BLOCK_HASH}, + serialization::TrustedPreallocate, transaction::{self, Transaction}, transparent, value_balance::ValueBalance, @@ -24,7 +30,11 @@ use zebra_chain::{ use crate::{ service::finalized_state::{ disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk}, - disk_format::{FromDisk, TransactionLocation}, + disk_format::{ + block::TransactionLocation, + transparent::{AddressBalanceLocation, OutputLocation}, + FromDisk, + }, zebra_db::{metrics::block_precommit_metrics, shielded::NoteCommitmentTrees, ZebraDb}, FinalizedBlock, }, @@ -38,17 +48,20 @@ impl ZebraDb { // Read block methods /// Returns true if the database is empty. + // + // TODO: move this method to the tip section pub fn is_empty(&self) -> bool { let hash_by_height = self.db.cf_handle("hash_by_height").unwrap(); - self.db.is_empty(hash_by_height) + self.db.zs_is_empty(&hash_by_height) } /// Returns the tip height and hash, if there is one. + // + // TODO: move this method to the tip section pub fn tip(&self) -> Option<(block::Height, block::Hash)> { let hash_by_height = self.db.cf_handle("hash_by_height").unwrap(); self.db - .reverse_iterator(hash_by_height) - .next() + .zs_last_key_value(&hash_by_height) .map(|(height_bytes, hash_bytes)| { let height = block::Height::from_bytes(height_bytes); let hash = block::Hash::from_bytes(hash_bytes); @@ -60,23 +73,50 @@ impl ZebraDb { /// Returns the finalized hash for a given `block::Height` if it is present. pub fn hash(&self, height: block::Height) -> Option { let hash_by_height = self.db.cf_handle("hash_by_height").unwrap(); - self.db.zs_get(hash_by_height, &height) + self.db.zs_get(&hash_by_height, &height) } /// Returns the height of the given block if it exists. pub fn height(&self, hash: block::Hash) -> Option { let height_by_hash = self.db.cf_handle("height_by_hash").unwrap(); - self.db.zs_get(height_by_hash, &hash) + self.db.zs_get(&height_by_hash, &hash) } /// Returns the [`Block`] with [`block::Hash`](zebra_chain::block::Hash) or /// [`Height`](zebra_chain::block::Height), if it exists in the finalized chain. + // + // TODO: move this method to the start of the section pub fn block(&self, hash_or_height: HashOrHeight) -> Option> { + // Blocks + let block_header_by_height = self.db.cf_handle("block_by_height").unwrap(); let height_by_hash = self.db.cf_handle("height_by_hash").unwrap(); - let block_by_height = self.db.cf_handle("block_by_height").unwrap(); - let height = hash_or_height.height_or_else(|hash| self.db.zs_get(height_by_hash, &hash))?; - self.db.zs_get(block_by_height, &height) + let height = + hash_or_height.height_or_else(|hash| self.db.zs_get(&height_by_hash, &hash))?; + let header = self.db.zs_get(&block_header_by_height, &height)?; + + // Transactions + let tx_by_loc = self.db.cf_handle("tx_by_loc").unwrap(); + + // Fetch the entire block's transactions + let mut transactions = Vec::new(); + + // TODO: is this loop more efficient if we store the number of transactions? + // is the difference large enough to matter? + for tx_index in 0..=Transaction::max_allocation() { + let tx_loc = TransactionLocation::from_u64(height, tx_index); + + if let Some(tx) = self.db.zs_get(&tx_by_loc, &tx_loc) { + transactions.push(tx); + } else { + break; + } + } + + Some(Arc::new(Block { + header, + transactions, + })) } // Read tip block methods @@ -105,25 +145,30 @@ impl ZebraDb { /// Returns the [`TransactionLocation`] for [`transaction::Hash`], /// if it exists in the finalized chain. pub fn transaction_location(&self, hash: transaction::Hash) -> Option { - let tx_by_hash = self.db.cf_handle("tx_by_hash").unwrap(); - self.db.zs_get(tx_by_hash, &hash) + let tx_loc_by_hash = self.db.cf_handle("tx_by_hash").unwrap(); + self.db.zs_get(&tx_loc_by_hash, &hash) } - /// Returns the [`Transaction`] with [`transaction::Hash`], + /// Returns the [`transaction::Hash`] for [`TransactionLocation`], /// if it exists in the finalized chain. - pub fn transaction( - &self, - hash: transaction::Hash, - ) -> Option<(Arc, block::Height)> { - self.transaction_location(hash) - .map(|TransactionLocation { index, height }| { - let block = self - .block(height.into()) - .expect("block will exist if TransactionLocation does"); - - // TODO: store transactions in a separate database index (#3151) - (block.transactions[index.as_usize()].clone(), height) - }) + #[allow(dead_code)] + pub fn transaction_hash(&self, location: TransactionLocation) -> Option { + let hash_by_tx_loc = self.db.cf_handle("hash_by_tx_loc").unwrap(); + self.db.zs_get(&hash_by_tx_loc, &location) + } + + /// Returns the [`Transaction`] with [`transaction::Hash`], and its [`Height`], + /// if a transaction with that hash exists in the finalized chain. + // + // TODO: move this method to the start of the section + pub fn transaction(&self, hash: transaction::Hash) -> Option<(Arc, Height)> { + let tx_by_loc = self.db.cf_handle("tx_by_loc").unwrap(); + + let transaction_location = self.transaction_location(hash)?; + + self.db + .zs_get(&tx_by_loc, &transaction_location) + .map(|tx| (tx, transaction_location.height)) } // Write block methods @@ -148,24 +193,81 @@ impl ZebraDb { ) -> Result { let finalized_hash = finalized.hash; - // Get a list of the spent UTXOs, before we delete any from the database - let all_utxos_spent_by_block = finalized - .block - .transactions + let tx_hash_indexes: HashMap = finalized + .transaction_hashes .iter() - .flat_map(|tx| tx.inputs().iter()) - .flat_map(|input| input.outpoint()) - .flat_map(|outpoint| self.utxo(&outpoint).map(|utxo| (outpoint, utxo))) + .enumerate() + .map(|(index, hash)| (*hash, index)) + .collect(); + + // Get a list of the new UTXOs in the format we need for database updates. + // + // TODO: index new_outputs by TransactionLocation, + // simplify the spent_utxos location lookup code, + // and remove the extra new_outputs_by_out_loc argument + let new_outputs_by_out_loc: BTreeMap = finalized + .new_outputs + .iter() + .map(|(outpoint, utxo)| { + ( + lookup_out_loc(finalized.height, outpoint, &tx_hash_indexes), + utxo.clone(), + ) + }) + .collect(); + + // Get a list of the spent UTXOs, before we delete any from the database + let spent_utxos: Vec<(transparent::OutPoint, OutputLocation, transparent::Utxo)> = + finalized + .block + .transactions + .iter() + .flat_map(|tx| tx.inputs().iter()) + .flat_map(|input| input.outpoint()) + .map(|outpoint| { + ( + outpoint, + // Some utxos are spent in the same block, so they will be in + // `tx_hash_indexes` and `new_outputs` + self.output_location(&outpoint).unwrap_or_else(|| { + lookup_out_loc(finalized.height, &outpoint, &tx_hash_indexes) + }), + self.utxo(&outpoint) + .or_else(|| finalized.new_outputs.get(&outpoint).cloned()) + .expect("already checked UTXO was in state or block"), + ) + }) + .collect(); + + let spent_utxos_by_outpoint: HashMap = + spent_utxos + .iter() + .map(|(outpoint, _output_loc, utxo)| (*outpoint, utxo.clone())) + .collect(); + let spent_utxos_by_out_loc: BTreeMap = spent_utxos + .into_iter() + .map(|(_outpoint, out_loc, utxo)| (out_loc, utxo)) + .collect(); + + // Get the current address balances, before the transactions in this block + let address_balances = spent_utxos_by_out_loc + .values() + .chain(finalized.new_outputs.values()) + .filter_map(|utxo| utxo.output.address(network)) + .unique() + .filter_map(|address| Some((address, self.address_balance_location(&address)?))) .collect(); - let mut batch = DiskWriteBatch::new(); + let mut batch = DiskWriteBatch::new(network); // In case of errors, propagate and do not write the batch. batch.prepare_block_batch( &self.db, finalized, - network, - all_utxos_spent_by_block, + new_outputs_by_out_loc, + spent_utxos_by_outpoint, + spent_utxos_by_out_loc, + address_balances, self.note_commitment_trees(), history_tree, self.finalized_value_pool(), @@ -179,6 +281,23 @@ impl ZebraDb { } } +/// Lookup the output location for an outpoint. +/// +/// `tx_hash_indexes` must contain `outpoint.hash` and that transaction's index in its block. +fn lookup_out_loc( + height: Height, + outpoint: &transparent::OutPoint, + tx_hash_indexes: &HashMap, +) -> OutputLocation { + let tx_index = tx_hash_indexes + .get(&outpoint.hash) + .expect("already checked UTXO was in state or block"); + + let tx_loc = TransactionLocation::from_usize(height, *tx_index); + + OutputLocation::from_outpoint(tx_loc, outpoint) +} + impl DiskWriteBatch { // Write block methods @@ -196,9 +315,10 @@ impl DiskWriteBatch { &mut self, db: &DiskDb, finalized: FinalizedBlock, - network: Network, - all_utxos_spent_by_block: HashMap, - // TODO: make an argument struct for all the current note commitment trees & history + new_outputs_by_out_loc: BTreeMap, + spent_utxos_by_outpoint: HashMap, + spent_utxos_by_out_loc: BTreeMap, + address_balances: HashMap, mut note_commitment_trees: NoteCommitmentTrees, history_tree: HistoryTree, value_pool: ValueBalance, @@ -210,8 +330,8 @@ impl DiskWriteBatch { .. } = &finalized; - // Commit block and transaction data, - // but not transaction indexes, note commitments, or UTXOs. + // Commit block and transaction data. + // (Transaction indexes, note commitments, and UTXOs are committed later.) self.prepare_block_header_transactions_batch(db, &finalized)?; // # Consensus @@ -228,18 +348,19 @@ impl DiskWriteBatch { } // Commit transaction indexes - self.prepare_transaction_index_batch(db, &finalized, &mut note_commitment_trees)?; - - self.prepare_note_commitment_batch( + self.prepare_transaction_index_batch( db, &finalized, - network, - note_commitment_trees, - history_tree, + new_outputs_by_out_loc, + spent_utxos_by_out_loc, + address_balances, + &mut note_commitment_trees, )?; + self.prepare_note_commitment_batch(db, &finalized, note_commitment_trees, history_tree)?; + // Commit UTXOs and value pools - self.prepare_chain_value_pools_batch(db, &finalized, all_utxos_spent_by_block, value_pool)?; + self.prepare_chain_value_pools_batch(db, &finalized, spent_utxos_by_outpoint, value_pool)?; // The block has passed contextual validation, so update the metrics block_precommit_metrics(block, *hash, *height); @@ -258,23 +379,46 @@ impl DiskWriteBatch { db: &DiskDb, finalized: &FinalizedBlock, ) -> Result<(), BoxError> { + // Blocks + let block_header_by_height = db.cf_handle("block_by_height").unwrap(); let hash_by_height = db.cf_handle("hash_by_height").unwrap(); let height_by_hash = db.cf_handle("height_by_hash").unwrap(); - let block_by_height = db.cf_handle("block_by_height").unwrap(); + + // Transactions + let tx_by_loc = db.cf_handle("tx_by_loc").unwrap(); + let hash_by_tx_loc = db.cf_handle("hash_by_tx_loc").unwrap(); + let tx_loc_by_hash = db.cf_handle("tx_by_hash").unwrap(); let FinalizedBlock { block, hash, height, + transaction_hashes, .. } = finalized; - // Index the block - self.zs_insert(hash_by_height, height, hash); - self.zs_insert(height_by_hash, hash, height); + // Commit block header data + self.zs_insert(&block_header_by_height, height, block.header); + + // Index the block hash and height + self.zs_insert(&hash_by_height, height, hash); + self.zs_insert(&height_by_hash, hash, height); + + for (transaction_index, (transaction, transaction_hash)) in block + .transactions + .iter() + .zip(transaction_hashes.iter()) + .enumerate() + { + let transaction_location = TransactionLocation::from_usize(*height, transaction_index); + + // Commit each transaction's data + self.zs_insert(&tx_by_loc, transaction_location, transaction); - // Commit block and transaction data, but not UTXOs or address indexes - self.zs_insert(block_by_height, height, block); + // Index each transaction hash and location + self.zs_insert(&hash_by_tx_loc, transaction_location, transaction_hash); + self.zs_insert(&tx_loc_by_hash, transaction_hash, transaction_location); + } Ok(()) } @@ -316,32 +460,25 @@ impl DiskWriteBatch { &mut self, db: &DiskDb, finalized: &FinalizedBlock, + new_outputs_by_out_loc: BTreeMap, + utxos_spent_by_block: BTreeMap, + address_balances: HashMap, note_commitment_trees: &mut NoteCommitmentTrees, ) -> Result<(), BoxError> { - let tx_by_hash = db.cf_handle("tx_by_hash").unwrap(); - - let FinalizedBlock { - block, - height, - transaction_hashes, - .. - } = finalized; - - // Index each transaction hash - for (transaction_index, (transaction, transaction_hash)) in block - .transactions - .iter() - .zip(transaction_hashes.iter()) - .enumerate() - { - let transaction_location = TransactionLocation::from_usize(*height, transaction_index); - self.zs_insert(tx_by_hash, transaction_hash, transaction_location); + let FinalizedBlock { block, .. } = finalized; + // Index each transaction's transparent and shielded data + for transaction in block.transactions.iter() { self.prepare_nullifier_batch(db, transaction)?; DiskWriteBatch::update_note_commitment_trees(transaction, note_commitment_trees)?; } - self.prepare_transparent_outputs_batch(db, finalized) + self.prepare_transparent_outputs_batch( + db, + new_outputs_by_out_loc, + utxos_spent_by_block, + address_balances, + ) } } diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs index 97dac92c8b1..92813c7f92b 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs @@ -46,7 +46,9 @@ use zebra_chain::{ use crate::{ service::finalized_state::{ - disk_format::{block::TransactionIndex, transparent::OutputLocation, TransactionLocation}, + disk_format::{ + block::TransactionIndex, transparent::OutputLocation, FromDisk, TransactionLocation, + }, FinalizedState, }, Config, @@ -194,6 +196,7 @@ fn test_block_and_transaction_data_with_network(network: Network) { settings.set_snapshot_suffix(format!("{}_{}", net_suffix, height)); settings.bind(|| snapshot_block_and_transaction_data(&state)); + settings.bind(|| snapshot_transparent_address_data(&state)); } } @@ -216,17 +219,23 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { assert_eq!(sapling_tree, sapling::tree::NoteCommitmentTree::default()); assert_eq!(orchard_tree, orchard::tree::NoteCommitmentTree::default()); + // Blocks let mut stored_block_hashes = Vec::new(); let mut stored_blocks = Vec::new(); - let mut stored_sapling_trees = Vec::new(); - let mut stored_orchard_trees = Vec::new(); - + // Transactions let mut stored_transaction_hashes = Vec::new(); let mut stored_transactions = Vec::new(); + // Transparent + let mut stored_utxos = Vec::new(); + // Shielded + + let mut stored_sapling_trees = Vec::new(); + let mut stored_orchard_trees = Vec::new(); + let sapling_tree_at_tip = state.sapling_note_commitment_tree(); let orchard_tree_at_tip = state.orchard_note_commitment_tree(); @@ -236,6 +245,7 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { // test the rest of the chain data (value balance). let history_tree_at_tip = state.history_tree(); + // TODO: split out block snapshots into their own function (#3151) for query_height in 0..=max_height.0 { let query_height = Height(query_height); @@ -265,8 +275,18 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { // because they are fully determined by the tip and block hashes. // // But we do it anyway, so the snapshots are more readable. + + // Check that the heights are consistent. assert_eq!(stored_height, query_height); + assert_eq!( + stored_block + .coinbase_height() + .expect("stored blocks have valid heights"), + query_height, + ); + + // Check that the tips are consistent. if query_height == max_height { assert_eq!(stored_block_hash, tip_block_hash); @@ -280,13 +300,6 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { } } - assert_eq!( - stored_block - .coinbase_height() - .expect("stored blocks have valid heights"), - query_height, - ); - stored_block_hashes.push((stored_height, BlockHash(stored_block_hash.to_string()))); stored_blocks.push(BlockData::new(stored_height, &stored_block)); @@ -294,26 +307,46 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { stored_orchard_trees.push((stored_height, orchard_tree_by_height)); // Check block transaction hashes and transactions. + // + // TODO: split out transaction snapshots into their own function (#3151) for tx_index in 0..stored_block.transactions.len() { - let transaction = &stored_block.transactions[tx_index]; + let block_transaction = &stored_block.transactions[tx_index]; let transaction_location = TransactionLocation::from_usize(query_height, tx_index); - let transaction_hash = transaction.hash(); - let transaction_data = TransactionData::new(transaction_location, transaction); + let transaction_hash = block_transaction.hash(); + let transaction_data = + TransactionData::new(transaction_location, block_transaction); // Check all the transaction column families, // using transaction location queries. - let stored_transaction_location = state.transaction_location(transaction_hash); - // Consensus: the genesis transaction is not indexed. - if query_height.0 > 0 { - assert_eq!(stored_transaction_location, Some(transaction_location)); - } else { - assert_eq!(stored_transaction_location, None); - } - - let stored_transaction_hash = - TransactionHashByLocation::new(stored_transaction_location, transaction_hash); + // Check that the transaction indexes are consistent. + let (direct_transaction, direct_transaction_height) = state + .transaction(transaction_hash) + .expect("transactions in blocks must also be available directly"); + let stored_transaction_hash = state + .transaction_hash(transaction_location) + .expect("hashes of transactions in blocks must be indexed by location"); + let stored_transaction_location = state + .transaction_location(transaction_hash) + .expect("locations of transactions in blocks must be indexed by hash"); + + assert_eq!( + &direct_transaction, block_transaction, + "transactions in block must be the same as transactions looked up directly", + ); + assert_eq!( + direct_transaction_height, transaction_location.height, + "transaction heights must be the same as their block heights", + ); + assert_eq!(stored_transaction_hash, transaction_hash); + assert_eq!(stored_transaction_location, transaction_location); + + // TODO: snapshot TransactionLocations without Some (#3151) + let stored_transaction_hash = TransactionHashByLocation::new( + Some(stored_transaction_location), + transaction_hash, + ); stored_transaction_hashes.push(stored_transaction_hash); stored_transactions.push(transaction_data); @@ -324,11 +357,23 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { transparent::OutPoint::from_usize(transaction_hash, output_index); let output_location = - OutputLocation::from_usize(transaction_hash, output_index); + OutputLocation::from_usize(query_height, tx_index, output_index); + + let stored_output_location = state + .output_location(&outpoint) + .expect("all outpoints are indexed"); - let stored_utxo = state.utxo(&outpoint); + let stored_utxo_by_outpoint = state.utxo(&outpoint); + let stored_utxo_by_out_loc = state.utxo_by_location(output_location); - if let Some(stored_utxo) = &stored_utxo { + assert_eq!(stored_output_location, output_location); + assert_eq!(stored_utxo_by_out_loc, stored_utxo_by_outpoint); + + // # Consensus + // + // The genesis transaction's UTXO is not indexed. + // This check also ignores spent UTXOs. + if let Some(stored_utxo) = &stored_utxo_by_out_loc { assert_eq!(&stored_utxo.output, output); assert_eq!(stored_utxo.height, query_height); @@ -344,8 +389,7 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { ); } - // TODO: use output_location in #3151 - stored_utxos.push((outpoint, stored_utxo)); + stored_utxos.push((output_location, stored_utxo_by_out_loc)); } } } @@ -384,6 +428,47 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { } } +/// Snapshot transparent address data, using `cargo insta` and RON serialization. +fn snapshot_transparent_address_data(state: &FinalizedState) { + let balance_by_transparent_addr = state.cf_handle("balance_by_transparent_addr").unwrap(); + + let mut stored_address_balances = Vec::new(); + + // TODO: UTXOs for each address (#3953) + // transactions for each address (#3951) + + // Correctness: Multi-key iteration causes hangs in concurrent code, but seems ok in tests. + let addresses = + state.full_iterator_cf(&balance_by_transparent_addr, rocksdb::IteratorMode::Start); + + // The default raw data serialization is very verbose, so we hex-encode the bytes. + let addresses: Vec = addresses + .map(|(key, _value)| transparent::Address::from_bytes(key)) + .collect(); + + for address in addresses { + let stored_address_balance = state + .address_balance_location(&address) + .expect("address indexes are consistent"); + + stored_address_balances.push((address.to_string(), stored_address_balance)); + } + + // TODO: check that the UTXO and transaction lists are in chain order. + /* + assert!( + is_sorted(&stored_address_utxos), + "unsorted: {:?}", + stored_address_utxos, + ); + */ + + // We want to snapshot the order in the database, + // because sometimes it is significant for performance or correctness. + // So we don't sort the vectors before snapshotting. + insta::assert_ron_snapshot!("address_balances", stored_address_balances); +} + /// Return true if `list` is sorted in ascending order. /// /// TODO: replace with Vec::is_sorted when it stabilises diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_0.snap new file mode 100644 index 00000000000..7dbefb77ef3 --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_0.snap @@ -0,0 +1,5 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_1.snap new file mode 100644 index 00000000000..616b2c42b31 --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_1.snap @@ -0,0 +1,16 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[ + ("t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd", AddressBalanceLocation( + balance: Amount(12500), + location: OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), + ), + )), +] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_2.snap new file mode 100644 index 00000000000..14fe6eace99 --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@mainnet_2.snap @@ -0,0 +1,16 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[ + ("t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd", AddressBalanceLocation( + balance: Amount(37500), + location: OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), + ), + )), +] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_0.snap new file mode 100644 index 00000000000..7dbefb77ef3 --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_0.snap @@ -0,0 +1,5 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_1.snap new file mode 100644 index 00000000000..4ea25efcd3d --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_1.snap @@ -0,0 +1,16 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[ + ("t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", AddressBalanceLocation( + balance: Amount(12500), + location: OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), + ), + )), +] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_2.snap new file mode 100644 index 00000000000..6c792ba7981 --- /dev/null +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/address_balances@testnet_2.snap @@ -0,0 +1,16 @@ +--- +source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +expression: stored_address_balances +--- +[ + ("t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", AddressBalanceLocation( + balance: Amount(37500), + location: OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), + ), + )), +] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_0.snap index 80e54b74230..6dd50cb4de4 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_0.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_0.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), ] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_1.snap index a0549205579..698f7f40d84 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_1.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), TransactionHashByLocation( diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_2.snap index 4801bd4ffb3..b5909fac05c 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@mainnet_2.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), TransactionHashByLocation( diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_0.snap index 80e54b74230..6dd50cb4de4 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_0.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_0.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), ] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_1.snap index 2007dc6e90c..8af3886d85e 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_1.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), TransactionHashByLocation( diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_2.snap index 41a8590d50f..054d7b9be8a 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/transaction_hashes@testnet_2.snap @@ -4,7 +4,10 @@ expression: stored_transaction_hashes --- [ TransactionHashByLocation( - loc: None, + loc: Some(TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + )), hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", ), TransactionHashByLocation( diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_0.snap index 1b421f4a2ac..c99f6d9af47 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_0.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_0.snap @@ -3,8 +3,11 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), ] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_1.snap index 431016c01d1..0a32521109b 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_1.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_1.snap @@ -3,13 +3,19 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), - (OutPoint( - hash: "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(50000), @@ -18,9 +24,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(12500), diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_2.snap index 4c1e8e4148d..a64b3d04f63 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_2.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@mainnet_2.snap @@ -3,13 +3,19 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), - (OutPoint( - hash: "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(50000), @@ -18,9 +24,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(12500), @@ -29,9 +38,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "8974d08d1c5f9c860d8b629d582a56659a4a1dcb2b5f98a25a5afcc2a784b0f4", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(2), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(100000), @@ -40,9 +52,12 @@ expression: stored_utxos height: Height(2), from_coinbase: true, ))), - (OutPoint( - hash: "8974d08d1c5f9c860d8b629d582a56659a4a1dcb2b5f98a25a5afcc2a784b0f4", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(2), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(25000), diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_0.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_0.snap index 1b421f4a2ac..c99f6d9af47 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_0.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_0.snap @@ -3,8 +3,11 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), ] diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_1.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_1.snap index 50a4bd7ced5..45e2af9a200 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_1.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_1.snap @@ -3,13 +3,19 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), - (OutPoint( - hash: "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(50000), @@ -18,9 +24,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(12500), diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_2.snap b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_2.snap index 15aedd05749..2738dda5364 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_2.snap +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshots/utxos@testnet_2.snap @@ -3,13 +3,19 @@ source: zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs expression: stored_utxos --- [ - (OutPoint( - hash: "c4eaa58879081de3c24a7b117ed2b28300e7ec4c4c1dff1d3f1268b7857a4ddb", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(0), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), None), - (OutPoint( - hash: "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(50000), @@ -18,9 +24,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(1), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(12500), @@ -29,9 +38,12 @@ expression: stored_utxos height: Height(1), from_coinbase: true, ))), - (OutPoint( - hash: "5822c0532da8a008259ac39933d3210e508c17e3ba21d2b2c428785efdccb3d5", - index: 0, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(2), + index: TransactionIndex(0), + ), + output_index: OutputIndex(0), ), Some(Utxo( output: Output( value: Amount(100000), @@ -40,9 +52,12 @@ expression: stored_utxos height: Height(2), from_coinbase: true, ))), - (OutPoint( - hash: "5822c0532da8a008259ac39933d3210e508c17e3ba21d2b2c428785efdccb3d5", - index: 1, + (OutputLocation( + transaction_location: TransactionLocation( + height: Height(2), + index: TransactionIndex(0), + ), + output_index: OutputIndex(1), ), Some(Utxo( output: Output( value: Amount(25000), diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs b/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs index b053aca0de1..71890bc4119 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs @@ -26,7 +26,7 @@ use zebra_chain::{ use zebra_test::vectors::{MAINNET_BLOCKS, TESTNET_BLOCKS}; use crate::{ - service::finalized_state::{disk_db::DiskWriteBatch, disk_format::IntoDisk, FinalizedState}, + service::finalized_state::{disk_db::DiskWriteBatch, FinalizedState}, Config, FinalizedBlock, }; @@ -115,7 +115,7 @@ fn test_block_db_round_trip_with( }; // Skip validation by writing the block directly to the database - let mut batch = DiskWriteBatch::new(); + let mut batch = DiskWriteBatch::new(Mainnet); batch .prepare_block_header_transactions_batch(&state.db, &finalized) .expect("block is valid for batch"); @@ -136,9 +136,9 @@ fn test_block_db_round_trip_with( stored data: {:?}\n\ ", original_block, - hex::encode(original_block.as_bytes()), + hex::encode(original_block.zcash_serialize_to_vec().unwrap()), stored_block, - hex::encode(stored_block.as_bytes()), + hex::encode(stored_block.zcash_serialize_to_vec().unwrap()), ); } diff --git a/zebra-state/src/service/finalized_state/zebra_db/chain.rs b/zebra-state/src/service/finalized_state/zebra_db/chain.rs index fade94802f1..76e5aceac27 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/chain.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/chain.rs @@ -16,9 +16,7 @@ use std::{borrow::Borrow, collections::HashMap}; use zebra_chain::{ amount::NonNegative, history_tree::{HistoryTree, NonEmptyHistoryTree}, - orchard, - parameters::Network, - sapling, transparent, + orchard, sapling, transparent, value_balance::ValueBalance, }; @@ -39,7 +37,7 @@ impl ZebraDb { Some(height) => { let history_tree_cf = self.db.cf_handle("history_tree").unwrap(); let history_tree: Option = - self.db.zs_get(history_tree_cf, &height); + self.db.zs_get(&history_tree_cf, &height); if let Some(non_empty_tree) = history_tree { HistoryTree::from(non_empty_tree) } else { @@ -54,7 +52,7 @@ impl ZebraDb { pub fn finalized_value_pool(&self) -> ValueBalance { let value_pool_cf = self.db.cf_handle("tip_chain_value_pool").unwrap(); self.db - .zs_get(value_pool_cf, &()) + .zs_get(&value_pool_cf, &()) .unwrap_or_else(ValueBalance::zero) } } @@ -73,7 +71,6 @@ impl DiskWriteBatch { &mut self, db: &DiskDb, finalized: &FinalizedBlock, - network: Network, sapling_root: sapling::tree::Root, orchard_root: orchard::tree::Root, mut history_tree: HistoryTree, @@ -82,12 +79,12 @@ impl DiskWriteBatch { let FinalizedBlock { block, height, .. } = finalized; - history_tree.push(network, block.clone(), sapling_root, orchard_root)?; + history_tree.push(self.network(), block.clone(), sapling_root, orchard_root)?; // Update the tree in state let current_tip_height = *height - 1; if let Some(h) = current_tip_height { - self.zs_delete(history_tree_cf, h); + self.zs_delete(&history_tree_cf, h); } // TODO: if we ever need concurrent read-only access to the history tree, @@ -96,7 +93,7 @@ impl DiskWriteBatch { // that was just deleted by a concurrent StateService write. // This requires a database version update. if let Some(history_tree) = history_tree.as_ref() { - self.zs_insert(history_tree_cf, height, history_tree); + self.zs_insert(&history_tree_cf, height, history_tree); } Ok(()) @@ -115,20 +112,15 @@ impl DiskWriteBatch { &mut self, db: &DiskDb, finalized: &FinalizedBlock, - mut all_utxos_spent_by_block: HashMap, + utxos_spent_by_block: HashMap, value_pool: ValueBalance, ) -> Result<(), BoxError> { let tip_chain_value_pool = db.cf_handle("tip_chain_value_pool").unwrap(); - let FinalizedBlock { - block, new_outputs, .. - } = finalized; + let FinalizedBlock { block, .. } = finalized; - // Some utxos are spent in the same block, so they will be in `new_outputs`. - all_utxos_spent_by_block.extend(new_outputs.clone()); - - let new_pool = value_pool.add_block(block.borrow(), &all_utxos_spent_by_block)?; - self.zs_insert(tip_chain_value_pool, (), new_pool); + let new_pool = value_pool.add_block(block.borrow(), &utxos_spent_by_block)?; + self.zs_insert(&tip_chain_value_pool, (), new_pool); Ok(()) } diff --git a/zebra-state/src/service/finalized_state/zebra_db/shielded.rs b/zebra-state/src/service/finalized_state/zebra_db/shielded.rs index 0f599f293ee..30b77e964fe 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/shielded.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/shielded.rs @@ -13,8 +13,7 @@ //! be incremented each time the database format (column, serialization, etc) changes. use zebra_chain::{ - block::Height, history_tree::HistoryTree, orchard, parameters::Network, sapling, sprout, - transaction::Transaction, + block::Height, history_tree::HistoryTree, orchard, sapling, sprout, transaction::Transaction, }; use crate::{ @@ -40,38 +39,38 @@ impl ZebraDb { /// Returns `true` if the finalized state contains `sprout_nullifier`. pub fn contains_sprout_nullifier(&self, sprout_nullifier: &sprout::Nullifier) -> bool { let sprout_nullifiers = self.db.cf_handle("sprout_nullifiers").unwrap(); - self.db.zs_contains(sprout_nullifiers, &sprout_nullifier) + self.db.zs_contains(&sprout_nullifiers, &sprout_nullifier) } /// Returns `true` if the finalized state contains `sapling_nullifier`. pub fn contains_sapling_nullifier(&self, sapling_nullifier: &sapling::Nullifier) -> bool { let sapling_nullifiers = self.db.cf_handle("sapling_nullifiers").unwrap(); - self.db.zs_contains(sapling_nullifiers, &sapling_nullifier) + self.db.zs_contains(&sapling_nullifiers, &sapling_nullifier) } /// Returns `true` if the finalized state contains `orchard_nullifier`. pub fn contains_orchard_nullifier(&self, orchard_nullifier: &orchard::Nullifier) -> bool { let orchard_nullifiers = self.db.cf_handle("orchard_nullifiers").unwrap(); - self.db.zs_contains(orchard_nullifiers, &orchard_nullifier) + self.db.zs_contains(&orchard_nullifiers, &orchard_nullifier) } /// Returns `true` if the finalized state contains `sprout_anchor`. #[allow(unused)] pub fn contains_sprout_anchor(&self, sprout_anchor: &sprout::tree::Root) -> bool { let sprout_anchors = self.db.cf_handle("sprout_anchors").unwrap(); - self.db.zs_contains(sprout_anchors, &sprout_anchor) + self.db.zs_contains(&sprout_anchors, &sprout_anchor) } /// Returns `true` if the finalized state contains `sapling_anchor`. pub fn contains_sapling_anchor(&self, sapling_anchor: &sapling::tree::Root) -> bool { let sapling_anchors = self.db.cf_handle("sapling_anchors").unwrap(); - self.db.zs_contains(sapling_anchors, &sapling_anchor) + self.db.zs_contains(&sapling_anchors, &sapling_anchor) } /// Returns `true` if the finalized state contains `orchard_anchor`. pub fn contains_orchard_anchor(&self, orchard_anchor: &orchard::tree::Root) -> bool { let orchard_anchors = self.db.cf_handle("orchard_anchors").unwrap(); - self.db.zs_contains(orchard_anchors, &orchard_anchor) + self.db.zs_contains(&orchard_anchors, &orchard_anchor) } /// Returns the Sprout note commitment tree of the finalized tip @@ -85,7 +84,7 @@ impl ZebraDb { let sprout_note_commitment_tree = self.db.cf_handle("sprout_note_commitment_tree").unwrap(); self.db - .zs_get(sprout_note_commitment_tree, &height) + .zs_get(&sprout_note_commitment_tree, &height) .expect("Sprout note commitment tree must exist if there is a finalized tip") } @@ -98,7 +97,7 @@ impl ZebraDb { ) -> Option { let sprout_anchors = self.db.cf_handle("sprout_anchors").unwrap(); - self.db.zs_get(sprout_anchors, sprout_anchor) + self.db.zs_get(&sprout_anchors, sprout_anchor) } /// Returns the Sapling note commitment tree of the finalized tip @@ -113,7 +112,7 @@ impl ZebraDb { self.db.cf_handle("sapling_note_commitment_tree").unwrap(); self.db - .zs_get(sapling_note_commitment_tree, &height) + .zs_get(&sapling_note_commitment_tree, &height) .expect("Sapling note commitment tree must exist if there is a finalized tip") } @@ -125,7 +124,7 @@ impl ZebraDb { ) -> Option { let sapling_trees = self.db.cf_handle("sapling_note_commitment_tree").unwrap(); - self.db.zs_get(sapling_trees, height) + self.db.zs_get(&sapling_trees, height) } /// Returns the Orchard note commitment tree of the finalized tip @@ -140,7 +139,7 @@ impl ZebraDb { self.db.cf_handle("orchard_note_commitment_tree").unwrap(); self.db - .zs_get(orchard_note_commitment_tree, &height) + .zs_get(&orchard_note_commitment_tree, &height) .expect("Orchard note commitment tree must exist if there is a finalized tip") } @@ -152,7 +151,7 @@ impl ZebraDb { ) -> Option { let orchard_trees = self.db.cf_handle("orchard_note_commitment_tree").unwrap(); - self.db.zs_get(orchard_trees, height) + self.db.zs_get(&orchard_trees, height) } /// Returns the shielded note commitment trees of the finalized tip @@ -184,13 +183,13 @@ impl DiskWriteBatch { // Mark sprout, sapling and orchard nullifiers as spent for sprout_nullifier in transaction.sprout_nullifiers() { - self.zs_insert(sprout_nullifiers, sprout_nullifier, ()); + self.zs_insert(&sprout_nullifiers, sprout_nullifier, ()); } for sapling_nullifier in transaction.sapling_nullifiers() { - self.zs_insert(sapling_nullifiers, sapling_nullifier, ()); + self.zs_insert(&sapling_nullifiers, sapling_nullifier, ()); } for orchard_nullifier in transaction.orchard_nullifiers() { - self.zs_insert(orchard_nullifiers, orchard_nullifier, ()); + self.zs_insert(&orchard_nullifiers, orchard_nullifier, ()); } Ok(()) @@ -241,8 +240,6 @@ impl DiskWriteBatch { &mut self, db: &DiskDb, finalized: &FinalizedBlock, - network: Network, - // TODO: make an argument struct for all the note commitment trees & history note_commitment_trees: NoteCommitmentTrees, history_tree: HistoryTree, ) -> Result<(), BoxError> { @@ -262,14 +259,14 @@ impl DiskWriteBatch { // Compute the new anchors and index them // Note: if the root hasn't changed, we write the same value again. - self.zs_insert(sprout_anchors, sprout_root, ¬e_commitment_trees.sprout); - self.zs_insert(sapling_anchors, sapling_root, ()); - self.zs_insert(orchard_anchors, orchard_root, ()); + self.zs_insert(&sprout_anchors, sprout_root, ¬e_commitment_trees.sprout); + self.zs_insert(&sapling_anchors, sapling_root, ()); + self.zs_insert(&orchard_anchors, orchard_root, ()); // Delete the previously stored Sprout note commitment tree. let current_tip_height = *height - 1; if let Some(h) = current_tip_height { - self.zs_delete(sprout_note_commitment_tree_cf, h); + self.zs_delete(&sprout_note_commitment_tree_cf, h); } // TODO: if we ever need concurrent read-only access to the sprout tree, @@ -277,31 +274,24 @@ impl DiskWriteBatch { // access a height that was just deleted by a concurrent StateService // write. This requires a database version update. self.zs_insert( - sprout_note_commitment_tree_cf, + &sprout_note_commitment_tree_cf, height, note_commitment_trees.sprout, ); self.zs_insert( - sapling_note_commitment_tree_cf, + &sapling_note_commitment_tree_cf, height, note_commitment_trees.sapling, ); self.zs_insert( - orchard_note_commitment_tree_cf, + &orchard_note_commitment_tree_cf, height, note_commitment_trees.orchard, ); - self.prepare_history_batch( - db, - finalized, - network, - sapling_root, - orchard_root, - history_tree, - ) + self.prepare_history_batch(db, finalized, sapling_root, orchard_root, history_tree) } /// Prepare a database batch containing the initial note commitment trees, @@ -324,17 +314,17 @@ impl DiskWriteBatch { // since the block validation will make sure only appropriate // transactions are allowed in a block. self.zs_insert( - sprout_note_commitment_tree_cf, + &sprout_note_commitment_tree_cf, height, sprout::tree::NoteCommitmentTree::default(), ); self.zs_insert( - sapling_note_commitment_tree_cf, + &sapling_note_commitment_tree_cf, height, sapling::tree::NoteCommitmentTree::default(), ); self.zs_insert( - orchard_note_commitment_tree_cf, + &orchard_note_commitment_tree_cf, height, orchard::tree::NoteCommitmentTree::default(), ); diff --git a/zebra-state/src/service/finalized_state/zebra_db/transparent.rs b/zebra-state/src/service/finalized_state/zebra_db/transparent.rs index ac2e14ae4e3..a24f06739a7 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/transparent.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/transparent.rs @@ -1,6 +1,6 @@ //! Provides high-level access to database: -//! - unspent [`transparent::Outputs`]s -//! - transparent address indexes +//! - unspent [`transparent::Outputs`]s (UTXOs), and +//! - transparent address indexes. //! //! This module makes sure that: //! - all disk writes happen inside a RocksDB transaction, and @@ -11,16 +11,18 @@ //! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must //! be incremented each time the database format (column, serialization, etc) changes. -use std::borrow::Borrow; +use std::collections::{BTreeMap, HashMap}; -use zebra_chain::transparent; +use zebra_chain::{ + amount::{Amount, NonNegative}, + transparent, +}; use crate::{ service::finalized_state::{ disk_db::{DiskDb, DiskWriteBatch, ReadDisk, WriteDisk}, - disk_format::transparent::OutputLocation, + disk_format::transparent::{AddressBalanceLocation, AddressLocation, OutputLocation}, zebra_db::ZebraDb, - FinalizedBlock, }, BoxError, }; @@ -28,19 +30,68 @@ use crate::{ impl ZebraDb { // Read transparent methods - /// Returns the `transparent::Output` pointed to by the given - /// `transparent::OutPoint` if it is present. + /// Returns the [`AddressBalanceLocation`] for a [`transparent::Address`], + /// if it is in the finalized state. + pub fn address_balance_location( + &self, + address: &transparent::Address, + ) -> Option { + let balance_by_transparent_addr = self.db.cf_handle("balance_by_transparent_addr").unwrap(); + + self.db.zs_get(&balance_by_transparent_addr, address) + } + + /// Returns the balance for a [`transparent::Address`], + /// if it is in the finalized state. + #[allow(dead_code)] + pub fn address_balance(&self, address: &transparent::Address) -> Option> { + self.address_balance_location(address) + .map(|abl| abl.balance()) + } + + /// Returns the first output that sent funds to a [`transparent::Address`], + /// if it is in the finalized state. + /// + /// This location is used as an efficient index key for addresses. + #[allow(dead_code)] + pub fn address_location(&self, address: &transparent::Address) -> Option { + self.address_balance_location(address) + .map(|abl| abl.location()) + } + + /// Returns the [`OutputLocation`] for a [`transparent::OutPoint`]. + /// + /// This method returns the locations of spent and unspent outpoints. + /// Returns `None` if the output was never in the finalized state. + pub fn output_location(&self, outpoint: &transparent::OutPoint) -> Option { + self.transaction_location(outpoint.hash) + .map(|transaction_location| { + OutputLocation::from_outpoint(transaction_location, outpoint) + }) + } + + /// Returns the transparent output for a [`transparent::OutPoint`], + /// if it is unspent in the finalized state. pub fn utxo(&self, outpoint: &transparent::OutPoint) -> Option { - let utxo_by_outpoint = self.db.cf_handle("utxo_by_outpoint").unwrap(); + let output_location = self.output_location(outpoint)?; - let output_location = OutputLocation::from_outpoint(outpoint); + self.utxo_by_location(output_location) + } - self.db.zs_get(utxo_by_outpoint, &output_location) + /// Returns the transparent output for an [`OutputLocation`], + /// if it is unspent in the finalized state. + pub fn utxo_by_location(&self, output_location: OutputLocation) -> Option { + let utxo_by_out_loc = self.db.cf_handle("utxo_by_outpoint").unwrap(); + self.db.zs_get(&utxo_by_out_loc, &output_location) } } impl DiskWriteBatch { - /// Prepare a database batch containing `finalized.block`'s UTXO changes, + /// Prepare a database batch containing `finalized.block`'s: + /// - transparent address balance changes, + /// - UTXO changes, and + /// TODO: + /// - transparent address index changes (add in #3951, #3953), /// and return it (without actually writing anything). /// /// # Errors @@ -49,33 +100,60 @@ impl DiskWriteBatch { pub fn prepare_transparent_outputs_batch( &mut self, db: &DiskDb, - finalized: &FinalizedBlock, + new_outputs_by_out_loc: BTreeMap, + utxos_spent_by_block: BTreeMap, + mut address_balances: HashMap, ) -> Result<(), BoxError> { let utxo_by_outpoint = db.cf_handle("utxo_by_outpoint").unwrap(); - - let FinalizedBlock { - block, new_outputs, .. - } = finalized; + let balance_by_transparent_addr = db.cf_handle("balance_by_transparent_addr").unwrap(); // Index all new transparent outputs, before deleting any we've spent - for (outpoint, utxo) in new_outputs.borrow().iter() { - let output_location = OutputLocation::from_outpoint(outpoint); + for (output_location, utxo) in new_outputs_by_out_loc { + let receiving_address = utxo.output.address(self.network()); + + // Update the address balance by adding this UTXO's value + if let Some(receiving_address) = receiving_address { + let address_balance = address_balances + .entry(receiving_address) + .or_insert_with(|| AddressBalanceLocation::new(output_location)) + .balance_mut(); - self.zs_insert(utxo_by_outpoint, output_location, utxo); + let new_address_balance = (*address_balance + utxo.output.value()) + .expect("balance overflow already checked"); + + *address_balance = new_address_balance; + } + + self.zs_insert(&utxo_by_outpoint, output_location, utxo); } // Mark all transparent inputs as spent. // - // Coinbase inputs represent new coins, - // so there are no UTXOs to mark as spent. - for output_location in block - .transactions - .iter() - .flat_map(|tx| tx.inputs()) - .flat_map(|input| input.outpoint()) - .map(|outpoint| OutputLocation::from_outpoint(&outpoint)) - { - self.zs_delete(utxo_by_outpoint, output_location); + // Coinbase inputs represent new coins, so there are no UTXOs to mark as spent. + for (output_location, utxo) in utxos_spent_by_block { + let spent_output = utxo.output; + let sending_address = spent_output.address(self.network()); + + // Update the address balance by subtracting this UTXO's value + if let Some(sending_address) = sending_address { + let address_balance = address_balances + .entry(sending_address) + .or_insert_with(|| panic!("spent outputs must already have an address balance")) + .balance_mut(); + + let new_address_balance = (*address_balance - spent_output.value()) + .expect("balance underflow already checked"); + + *address_balance = new_address_balance; + } + + self.zs_delete(&utxo_by_outpoint, output_location); + } + + // Write the new address balances to the database + for (address, address_balance) in address_balances.into_iter() { + // Some of these balances are new, and some are updates + self.zs_insert(&balance_by_transparent_addr, address, address_balance); } Ok(())