diff --git a/Cargo.lock b/Cargo.lock index cb5bd9324e21f7..36ed681f63bb93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1134,6 +1134,7 @@ dependencies = [ "arc-swap", "arr_macro", "bcs 0.1.4", + "bitvec 1.0.1", "byteorder", "claims", "clap 4.4.14", @@ -3506,19 +3507,25 @@ name = "aptos-scratchpad" version = "0.1.0" dependencies = [ "aptos-crypto", + "aptos-crypto-derive", "aptos-drop-helper", + "aptos-experimental-layered-map", "aptos-experimental-runtimes", "aptos-infallible", "aptos-metrics-core", "aptos-types", + "bcs 0.1.4", + "bincode", "bitvec 1.0.1", "criterion", + "fastcrypto", "itertools 0.12.1", "jemallocator", "once_cell", "proptest", "rand 0.7.3", "rayon", + "serde", "thiserror", ] @@ -4170,7 +4177,7 @@ dependencies = [ "serde-big-array", "serde_bytes", "serde_json", - "serde_with", + "serde_with 3.4.0", "serde_yaml 0.8.26", "strum 0.24.1", "strum_macros 0.24.3", @@ -4598,6 +4605,17 @@ dependencies = [ "tracing-subscriber 0.2.25", ] +[[package]] +name = "ark-secp256r1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-serialize" version = "0.4.2" @@ -5011,6 +5029,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "auto_ops" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" + [[package]] name = "autocfg" version = "1.1.0" @@ -5240,6 +5264,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bellpepper" version = "0.4.1" @@ -5348,6 +5378,21 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -5561,9 +5606,15 @@ checksum = "b58071e8fd9ec1e930efd28e3a90c1251015872a2ce49f81f36421b86466932e" dependencies = [ "serde", "serde_repr", - "serde_with", + "serde_with 3.4.0", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + [[package]] name = "bstr" version = "0.2.17" @@ -6798,6 +6849,7 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core 0.9.9", + "rayon", ] [[package]] @@ -6878,6 +6930,17 @@ dependencies = [ "pem-rfc7468 0.3.1", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468 0.6.0", + "zeroize", +] + [[package]] name = "der" version = "0.7.8" @@ -7314,6 +7377,21 @@ dependencies = [ "signature 2.2.0", ] +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "thiserror", + "zeroize", +] + [[package]] name = "ed25519-dalek" version = "1.0.1" @@ -7742,6 +7820,65 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "fastcrypto" +version = "0.1.8" +source = "git+https://github.com/MystenLabs/fastcrypto.git#fcf250111ae4070c62e59bb68de857c59fcc09e6" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-secp256r1", + "ark-serialize", + "auto_ops", + "base64ct", + "bech32", + "bincode", + "blake2", + "blst", + "bs58", + "curve25519-dalek-ng", + "derive_more", + "digest 0.10.7", + "ecdsa", + "ed25519-consensus", + "elliptic-curve", + "fastcrypto-derive", + "generic-array 0.14.7", + "hex", + "hex-literal 0.4.1", + "hkdf 0.12.4", + "lazy_static", + "num-bigint 0.4.4", + "once_cell", + "p256", + "rand 0.8.5", + "readonly", + "rfc6979", + "rsa 0.8.2", + "schemars", + "secp256k1", + "serde", + "serde_json", + "serde_with 2.3.3", + "sha2 0.10.8", + "sha3 0.10.8", + "signature 2.2.0", + "static_assertions", + "thiserror", + "tokio", + "typenum", + "zeroize", +] + +[[package]] +name = "fastcrypto-derive" +version = "0.1.3" +source = "git+https://github.com/MystenLabs/fastcrypto.git#fcf250111ae4070c62e59bb68de857c59fcc09e6" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "fastrand" version = "1.9.0" @@ -8293,6 +8430,7 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", "zeroize", @@ -8815,6 +8953,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hidapi" version = "1.5.0" @@ -10472,7 +10616,7 @@ name = "move-bytecode-verifier" version = "0.1.0" dependencies = [ "fail", - "hex-literal", + "hex-literal 0.3.4", "invalid-mutations", "move-binary-format", "move-borrow-graph", @@ -12141,6 +12285,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -12342,6 +12495,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +dependencies = [ + "der 0.6.1", + "pkcs8 0.9.0", + "spki 0.6.0", + "zeroize", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -12364,6 +12529,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -13386,6 +13561,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "readonly" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "redis" version = "0.22.3" @@ -13732,6 +13918,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rsa" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" +dependencies = [ + "byteorder", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1 0.4.1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sha2 0.10.8", + "signature 2.2.0", + "subtle", + "zeroize", +] + [[package]] name = "rsa" version = "0.9.6" @@ -14102,6 +14309,30 @@ dependencies = [ "parking_lot 0.12.1", ] +[[package]] +name = "schemars" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.48", +] + [[package]] name = "scoped-futures" version = "0.1.3" @@ -14155,6 +14386,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "secret-vault-value" version = "0.3.8" @@ -14337,6 +14588,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "serde_json" version = "1.0.114" @@ -14402,6 +14664,22 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros 2.3.3", + "time", +] + [[package]] name = "serde_with" version = "3.4.0" @@ -14415,10 +14693,22 @@ dependencies = [ "indexmap 2.2.5", "serde", "serde_json", - "serde_with_macros", + "serde_with_macros 3.4.0", "time", ] +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling 0.20.9", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "serde_with_macros" version = "3.4.0" @@ -14962,6 +15252,16 @@ dependencies = [ "der 0.5.1", ] +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + [[package]] name = "spki" version = "0.7.3" diff --git a/crates/aptos-crypto/src/hash.rs b/crates/aptos-crypto/src/hash.rs index 9b38b0ae894053..a025302bdf8052 100644 --- a/crates/aptos-crypto/src/hash.rs +++ b/crates/aptos-crypto/src/hash.rs @@ -284,6 +284,11 @@ impl HashValue { hash[Self::LENGTH - bytes.len()..].copy_from_slice(&bytes[..]); Self::new(hash) } + + /// hack + pub fn into_inner(self) -> [u8; Self::LENGTH] { + self.hash + } } impl ser::Serialize for HashValue { diff --git a/execution/executor-types/src/lib.rs b/execution/executor-types/src/lib.rs index 5f87e40dc1456f..cb4eb9d878876a 100644 --- a/execution/executor-types/src/lib.rs +++ b/execution/executor-types/src/lib.rs @@ -18,7 +18,7 @@ use aptos_types::{ epoch_state::EpochState, jwks::OBSERVED_JWK_UPDATED_MOVE_TYPE_TAG, ledger_info::LedgerInfoWithSignatures, - proof::{AccumulatorExtensionProof, SparseMerkleProofExt}, + proof::AccumulatorExtensionProof, state_store::{state_key::StateKey, state_value::StateValue}, transaction::{ block_epilogue::{BlockEndInfo, BlockEpiloguePayload}, @@ -526,11 +526,11 @@ impl StateComputeResult { } pub struct ProofReader { - proofs: HashMap, + proofs: HashMap>, } impl ProofReader { - pub fn new(proofs: HashMap) -> Self { + pub fn new(proofs: HashMap>) -> Self { ProofReader { proofs } } @@ -540,8 +540,8 @@ impl ProofReader { } impl ProofRead for ProofReader { - fn get_proof(&self, key: HashValue) -> Option<&SparseMerkleProofExt> { - self.proofs.get(&key) + fn get_proof(&self, key: HashValue) -> Option { + *self.proofs.get(&key).unwrap() } } diff --git a/experimental/storage/layered-map/src/lib.rs b/experimental/storage/layered-map/src/lib.rs index a95e88a5b90dce..ef394b04bcb066 100644 --- a/experimental/storage/layered-map/src/lib.rs +++ b/experimental/storage/layered-map/src/lib.rs @@ -146,9 +146,13 @@ impl MapLayer { self.inner.log_layer(name) } - fn is_family(&self, other: &Self) -> bool { + pub fn is_family(&self, other: &Self) -> bool { self.inner.family == other.inner.family } + + pub fn layer(&self) -> u64 { + self.inner.layer + } } #[derive(Clone, Debug)] diff --git a/storage/aptosdb/Cargo.toml b/storage/aptosdb/Cargo.toml index a3a5c3d4390027..4bafbac706d63b 100644 --- a/storage/aptosdb/Cargo.toml +++ b/storage/aptosdb/Cargo.toml @@ -37,6 +37,7 @@ aptos-types = { workspace = true } arc-swap = { workspace = true } arr_macro = { workspace = true } bcs = { workspace = true } +bitvec = { workspace = true } byteorder = { workspace = true } claims = { workspace = true } clap = { workspace = true, optional = true } diff --git a/storage/aptosdb/src/db/include/aptosdb_writer.rs b/storage/aptosdb/src/db/include/aptosdb_writer.rs index e60bea6cce5587..5f3a920a37a7b6 100644 --- a/storage/aptosdb/src/db/include/aptosdb_writer.rs +++ b/storage/aptosdb/src/db/include/aptosdb_writer.rs @@ -147,7 +147,7 @@ impl DbWriter for AptosDB { &transaction_infos, &events, wsets, - Option::Some(( + Some(( &mut ledger_db_batch, &mut sharded_kv_batch, &state_kv_metadata_batch, diff --git a/storage/aptosdb/src/state_merkle_db.rs b/storage/aptosdb/src/state_merkle_db.rs index ff6c9f823225a2..0d1f9cf4ad59cf 100644 --- a/storage/aptosdb/src/state_merkle_db.rs +++ b/storage/aptosdb/src/state_merkle_db.rs @@ -1,6 +1,8 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 +#![allow(dead_code)] + use crate::{ common::NUM_STATE_SHARDS, db_options::{gen_state_merkle_cfds, state_merkle_db_column_families}, diff --git a/storage/aptosdb/src/state_store/mod.rs b/storage/aptosdb/src/state_store/mod.rs index cf598a8cbab164..6e7eb92fe150f9 100644 --- a/storage/aptosdb/src/state_store/mod.rs +++ b/storage/aptosdb/src/state_store/mod.rs @@ -46,7 +46,6 @@ use aptos_logger::info; use aptos_schemadb::SchemaBatch; use aptos_scratchpad::{SmtAncestors, SparseMerkleTree}; use aptos_storage_interface::{ - async_proof_fetcher::AsyncProofFetcher, cached_state_view::{CachedStateView, ShardedStateCache}, db_ensure as ensure, state_delta::StateDelta, @@ -503,7 +502,7 @@ impl StateStore { StateViewId::Miscellaneous, snapshot, speculative_state, - Arc::new(AsyncProofFetcher::new(state_db.clone())), + state_db.clone(), ); let write_sets = state_db .ledger_db diff --git a/storage/aptosdb/src/state_store/state_merkle_batch_committer.rs b/storage/aptosdb/src/state_store/state_merkle_batch_committer.rs index 3c9bce81f10b72..fa688c53632d4c 100644 --- a/storage/aptosdb/src/state_store/state_merkle_batch_committer.rs +++ b/storage/aptosdb/src/state_store/state_merkle_batch_committer.rs @@ -5,8 +5,8 @@ use crate::{ metrics::{LATEST_SNAPSHOT_VERSION, OTHER_TIMERS_SECONDS}, - pruner::PrunerManager, schema::jellyfish_merkle_node::JellyfishMerkleNodeSchema, + state_merkle_db::Node, state_store::{buffered_state::CommitMessage, StateDb}, }; use anyhow::{anyhow, ensure, Result}; @@ -14,15 +14,14 @@ use aptos_crypto::HashValue; use aptos_jellyfish_merkle::node_type::NodeKey; use aptos_logger::{info, trace}; use aptos_metrics_core::TimerHelper; -use aptos_schemadb::SchemaBatch; use aptos_scratchpad::SmtAncestors; use aptos_storage_interface::state_delta::StateDelta; -use aptos_types::state_store::state_value::StateValue; +use aptos_types::state_store::{state_key::StateKey, state_value::StateValue}; use std::sync::{mpsc::Receiver, Arc}; pub struct StateMerkleBatch { - pub top_levels_batch: SchemaBatch, - pub batches_for_shards: Vec, + // pub top_levels_batch: SchemaBatch, + // pub batches_for_shards: Vec, pub root_hash: HashValue, pub state_delta: Arc, } @@ -52,8 +51,8 @@ impl StateMerkleBatchCommitter { match msg { CommitMessage::Data(state_merkle_batch) => { let StateMerkleBatch { - top_levels_batch, - batches_for_shards, + // top_levels_batch, + // batches_for_shards, root_hash, state_delta, } = state_merkle_batch; @@ -62,10 +61,25 @@ impl StateMerkleBatchCommitter { .current_version .expect("Current version should not be None"); - // commit jellyfish merkle nodes let _timer = OTHER_TIMERS_SECONDS .with_label_values(&["commit_jellyfish_merkle_nodes"]) .start_timer(); + + self.state_db + .state_merkle_db + .metadata_db() + .put::( + &NodeKey::new_empty_path(current_version), + &Node::new_leaf( + root_hash, + root_hash, + (StateKey::raw(b"root"), current_version), + ), + ) + .unwrap(); + + /* + // commit jellyfish merkle nodes self.state_db .state_merkle_db .commit(current_version, top_levels_batch, batches_for_shards) @@ -79,6 +93,7 @@ impl StateMerkleBatchCommitter { cache.maybe_evict_version(self.state_db.state_merkle_db.lru_cache()) }); } + */ info!( version = current_version, base_version = state_delta.base_version, @@ -86,12 +101,14 @@ impl StateMerkleBatchCommitter { "State snapshot committed." ); LATEST_SNAPSHOT_VERSION.set(current_version as i64); + /* self.state_db .state_merkle_pruner .maybe_set_pruner_target_db_version(current_version); self.state_db .epoch_snapshot_pruner .maybe_set_pruner_target_db_version(current_version); + */ self.check_usage_consistency(&state_delta).unwrap(); @@ -117,6 +134,7 @@ impl StateMerkleBatchCommitter { .ok_or_else(|| anyhow!("Committing without version."))?; let usage_from_ledger_db = self.state_db.ledger_db.metadata_db().get_usage(version)?; + /* let leaf_count_from_jmt = self .state_db .state_merkle_db @@ -131,6 +149,7 @@ impl StateMerkleBatchCommitter { usage_from_ledger_db.items(), leaf_count_from_jmt, ); + */ let usage_from_smt = state_delta.current.usage(); if !usage_from_smt.is_untracked() { diff --git a/storage/aptosdb/src/state_store/state_snapshot_committer.rs b/storage/aptosdb/src/state_store/state_snapshot_committer.rs index fa608ff32c2ea5..2fcec8e503a219 100644 --- a/storage/aptosdb/src/state_store/state_snapshot_committer.rs +++ b/storage/aptosdb/src/state_store/state_snapshot_committer.rs @@ -4,7 +4,6 @@ //! This file defines the state snapshot committer running in background thread within StateStore. use crate::{ - metrics::OTHER_TIMERS_SECONDS, state_store::{ buffered_state::CommitMessage, state_merkle_batch_committer::{StateMerkleBatch, StateMerkleBatchCommitter}, @@ -12,12 +11,10 @@ use crate::{ }, versioned_node_cache::VersionedNodeCache, }; -use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; use aptos_logger::trace; use aptos_scratchpad::SmtAncestors; -use aptos_storage_interface::{jmt_update_refs, jmt_updates, state_delta::StateDelta, Result}; +use aptos_storage_interface::state_delta::StateDelta; use aptos_types::state_store::state_value::StateValue; -use rayon::prelude::*; use static_assertions::const_assert; use std::{ sync::{ @@ -29,6 +26,7 @@ use std::{ }; pub(crate) struct StateSnapshotCommitter { + #[allow(dead_code)] state_db: Arc, state_snapshot_commit_receiver: Receiver>>, state_merkle_batch_commit_sender: SyncSender>, @@ -74,6 +72,7 @@ impl StateSnapshotCommitter { while let Ok(msg) = self.state_snapshot_commit_receiver.recv() { match msg { CommitMessage::Data(delta_to_commit) => { + /* let version = delta_to_commit.current_version.expect("Cannot be empty"); let base_version = delta_to_commit.base_version; let previous_epoch_ending_version = self @@ -138,12 +137,13 @@ impl StateSnapshotCommitter { ) .expect("Error calculating StateMerkleBatch for top levels.") }; + */ self.state_merkle_batch_commit_sender .send(CommitMessage::Data(StateMerkleBatch { - top_levels_batch, - batches_for_shards, - root_hash, + // top_levels_batch, + // batches_for_shards, + root_hash: delta_to_commit.current.root_hash(), state_delta: delta_to_commit, })) .unwrap(); diff --git a/storage/aptosdb/src/versioned_node_cache.rs b/storage/aptosdb/src/versioned_node_cache.rs index 8b935f1e77ab15..50edbaafe38a18 100644 --- a/storage/aptosdb/src/versioned_node_cache.rs +++ b/storage/aptosdb/src/versioned_node_cache.rs @@ -1,11 +1,10 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use crate::{lru_node_cache::LruNodeCache, metrics::OTHER_TIMERS_SECONDS, state_merkle_db::Node}; +use crate::{lru_node_cache::LruNodeCache, state_merkle_db::Node}; use aptos_infallible::RwLock; use aptos_jellyfish_merkle::node_type::NodeKey; use aptos_types::transaction::Version; -use rayon::prelude::*; use std::{ collections::{HashMap, VecDeque}, fmt, @@ -30,6 +29,7 @@ impl fmt::Debug for VersionedNodeCache { } impl VersionedNodeCache { + #[allow(dead_code)] pub(crate) const NUM_VERSIONS_TO_CACHE: usize = 2; pub fn new() -> Self { @@ -38,53 +38,13 @@ impl VersionedNodeCache { } } - pub fn add_version(&self, version: Version, nodes: NodeCache) { - let _timer = OTHER_TIMERS_SECONDS - .with_label_values(&["version_cache_add"]) - .start_timer(); - - let mut locked = self.inner.write(); - if !locked.is_empty() { - let (last_version, _) = locked.back().unwrap(); - assert!( - *last_version < version, - "Updating older version. {} vs latest:{} ", - version, - *last_version, - ); - } - locked.push_back((version, Arc::new(nodes))); + pub fn add_version(&self, _version: Version, _nodes: NodeCache) { + unimplemented!(); } - pub fn maybe_evict_version(&self, lru_cache: &LruNodeCache) { - let _timer = OTHER_TIMERS_SECONDS - .with_label_values(&["version_cache_evict"]) - .start_timer(); - - let to_evict = { - let locked = self.inner.read(); - if locked.len() > Self::NUM_VERSIONS_TO_CACHE { - locked - .front() - .map(|(version, cache)| (*version, cache.clone())) - } else { - None - } - }; - - if let Some((version, cache)) = to_evict { - cache - .iter() - .collect::>() - .into_par_iter() - .with_min_len(100) - .for_each(|(node_key, node)| { - lru_cache.put(node_key.clone(), node.clone()); - }); - - let evicted = self.inner.write().pop_front(); - assert_eq!(evicted, Some((version, cache))); - } + #[allow(dead_code)] + pub fn maybe_evict_version(&self, _lru_cache: &LruNodeCache) { + unimplemented!(); } pub fn get_version(&self, version: Version) -> Option> { diff --git a/storage/scratchpad/Cargo.toml b/storage/scratchpad/Cargo.toml index 132cbe2001043e..cef97684a85b1a 100644 --- a/storage/scratchpad/Cargo.toml +++ b/storage/scratchpad/Cargo.toml @@ -14,12 +14,15 @@ rust-version = { workspace = true } [dependencies] aptos-crypto = { workspace = true } +aptos-crypto-derive = { workspace = true } aptos-drop-helper = { workspace = true } +aptos-experimental-layered-map = { workspace = true } aptos-experimental-runtimes = { workspace = true } aptos-infallible = { workspace = true } aptos-metrics-core = { workspace = true } aptos-types = { workspace = true } bitvec = { workspace = true } +bcs = { workspace = true } criterion = { workspace = true, optional = true } itertools = { workspace = true } once_cell = { workspace = true } @@ -27,6 +30,10 @@ proptest = { workspace = true, optional = true } rayon = { workspace = true } thiserror = { workspace = true } +fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto.git" } +bincode = "1.3.3" +serde = { version = "1.0.197", features = ["derive"] } + [dev-dependencies] aptos-types = { workspace = true, features = ["fuzzing"] } bitvec = { workspace = true } diff --git a/storage/scratchpad/src/sparse_merkle/inc_hash.rs b/storage/scratchpad/src/sparse_merkle/inc_hash.rs new file mode 100644 index 00000000000000..251846656447da --- /dev/null +++ b/storage/scratchpad/src/sparse_merkle/inc_hash.rs @@ -0,0 +1,100 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +// Play with Incremental Hash as a way to authenticate the state + +use crate::sparse_merkle::metrics::GENERATION; +use aptos_crypto::HashValue; +use aptos_drop_helper::ArcAsyncDrop; +use aptos_experimental_layered_map::MapLayer; +use aptos_metrics_core::IntGaugeHelper; +use aptos_types::state_store::state_storage_usage::StateStorageUsage; +use bitvec::{order::Msb0, view::BitView}; +use fastcrypto::hash::EllipticCurveMultisetHash; +use std::sync::Arc; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) struct HashAsKey(pub HashValue); + +impl aptos_experimental_layered_map::Key for HashAsKey { + fn iter_bits(&self) -> impl Iterator { + self.0.iter_bits() + } + + fn bit(&self, depth: usize) -> bool { + *self.0.as_slice().view_bits::().get(depth).unwrap() + } +} + +#[derive(Debug)] +pub(crate) struct Root { + pub inc_hash: EllipticCurveMultisetHash, + pub hash: HashValue, + pub content: MapLayer>, +} + +fn hash_inc_hash(inc_hash: &EllipticCurveMultisetHash) -> HashValue { + let mut hasher = aptos_crypto::hash::DefaultHasher::new(b"IncHash"); + hasher.update(&bcs::to_bytes(inc_hash).unwrap()); + hasher.finish() +} + +impl Root { + pub fn new( + inc_hash: EllipticCurveMultisetHash, + content: MapLayer>, + ) -> Self { + let hash = hash_inc_hash(&inc_hash); + + Root { + inc_hash, + hash, + content, + } + } + + pub fn hash(&self) -> HashValue { + self.hash + } +} + +#[derive(Debug)] +pub(crate) struct AuthByIncHash { + pub root: Root, + pub usage: StateStorageUsage, +} + +impl AuthByIncHash { + pub fn new(usage: StateStorageUsage) -> Self { + let root = Root::new( + EllipticCurveMultisetHash::default(), + MapLayer::new_family("AuthByIncHash::new"), + ); + + AuthByIncHash { root, usage } + } + + pub fn spawn(&self, child_root: Root, child_usage: StateStorageUsage) -> Arc { + Self { + root: child_root, + usage: child_usage, + } + .into() + } + + pub fn root(&self) -> &Root { + &self.root + } + + pub fn generation(&self) -> u64 { + self.root.content.layer() + } + + pub fn is_family(&self, other: &Self) -> bool { + self.root.content.is_family(&other.root.content) + } + + pub fn log_generation(&self, name: &'static str) { + GENERATION.set_with(&[name], self.root.content.layer() as i64); + } +} diff --git a/storage/scratchpad/src/sparse_merkle/mod.rs b/storage/scratchpad/src/sparse_merkle/mod.rs index 6b9f35e1454390..0b8ef39a2035e0 100644 --- a/storage/scratchpad/src/sparse_merkle/mod.rs +++ b/storage/scratchpad/src/sparse_merkle/mod.rs @@ -69,24 +69,25 @@ #![allow(clippy::let_and_return)] // See https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=795cd4f459f1d4a0005a99650726834b #![allow(clippy::while_let_loop)] +#![allow(dead_code)] pub mod ancestors; mod dropper; +mod inc_hash; mod metrics; mod node; -#[cfg(test)] -mod sparse_merkle_test; +// #[cfg(test)] +// mod sparse_merkle_test; #[cfg(any(test, feature = "bench", feature = "fuzzing"))] pub mod test_utils; -mod updater; +// mod updater; pub mod utils; use crate::sparse_merkle::{ dropper::SUBTREE_DROPPER, - metrics::{GENERATION, TIMER}, - node::{NodeInner, SubTree}, - updater::SubTreeUpdater, - utils::get_state_shard_id, + inc_hash::{AuthByIncHash, HashAsKey, Root}, + metrics::GENERATION, + node::SubTree, }; use aptos_crypto::{ hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH}, @@ -96,10 +97,11 @@ use aptos_drop_helper::ArcAsyncDrop; use aptos_infallible::Mutex; use aptos_metrics_core::IntGaugeHelper; use aptos_types::{ - nibble::{nibble_path::NibblePath, Nibble}, - proof::SparseMerkleProofExt, + nibble::nibble_path::NibblePath, proof::SparseMerkleLeafNode, state_store::state_storage_usage::StateStorageUsage, }; +use fastcrypto::hash::{EllipticCurveMultisetHash, MultisetHash}; +use rayon::prelude::*; use std::{ collections::{BTreeMap, HashMap}, sync::Arc, @@ -187,9 +189,17 @@ impl Inner { } /// The Sparse Merkle Tree implementation. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct SparseMerkleTree { - inner: Arc>, + inner: Arc>, +} + +impl Clone for SparseMerkleTree { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } } impl SparseMerkleTree @@ -199,16 +209,9 @@ where /// Constructs a Sparse Merkle Tree with a root hash. This is often used when we restart and /// the scratch pad and the storage have identical state, so we use a single root hash to /// represent the entire state. - pub fn new(root_hash: HashValue, usage: StateStorageUsage) -> Self { - let root = if root_hash != *SPARSE_MERKLE_PLACEHOLDER_HASH { - SubTree::new_unknown(root_hash) - } else { - assert!(usage.is_untracked() || usage == StateStorageUsage::zero()); - SubTree::new_empty() - }; - + pub fn new(_root_hash: HashValue, usage: StateStorageUsage) -> Self { Self { - inner: Inner::new(root, usage), + inner: Arc::new(AuthByIncHash::new(usage)), } } @@ -218,9 +221,7 @@ where } pub fn new_empty() -> Self { - Self { - inner: Inner::new(SubTree::new_empty(), StateStorageUsage::zero()), - } + Self::new(*SPARSE_MERKLE_PLACEHOLDER_HASH, StateStorageUsage::zero()) } pub fn has_same_root_hash(&self, other: &Self) -> bool { @@ -245,14 +246,12 @@ where } #[cfg(test)] - fn new_with_root(root: SubTree) -> Self { - Self { - inner: Inner::new(root, StateStorageUsage::new_untracked()), - } + fn new_with_root(_root: SubTree) -> Self { + unimplemented!() } fn root_weak(&self) -> SubTree { - self.inner.root().weak() + unimplemented!() } /// Returns the root hash of this tree. @@ -261,7 +260,7 @@ where } fn generation(&self) -> u64 { - self.inner.generation + self.inner.generation() } pub fn is_the_same(&self, other: &Self) -> bool { @@ -269,7 +268,7 @@ where } pub fn is_family(&self, other: &Self) -> bool { - self.inner.family == other.inner.family + self.inner.is_family(&other.inner) } pub fn usage(&self) -> StateStorageUsage { @@ -281,107 +280,20 @@ where /// Assumes 16 shards in total. pub fn new_node_hashes_since( &self, - since_smt: &Self, - shard_id: u8, + _since_smt: &Self, + _shard_id: u8, ) -> HashMap { - let _timer = TIMER - .with_label_values(&["new_node_hashes_since"]) - .start_timer(); - - assert!(since_smt.is_family(self)); - - let mut node_hashes = HashMap::new(); - let mut subtree = self.root_weak(); - let mut pos = NodePosition::with_capacity(HashValue::LENGTH_IN_BITS); - let since_generation = since_smt.generation() + 1; - // Assume 16 shards here. - // We check the top 4 levels first, if there is any leaf node belongs to the shard we are - // requesting, we collect that node and return earlier (because there is no nodes below - // this point). - // Otherwise, once we reach the 5th level (the level of the root of each shard), all nodes - // at or below it belongs to the requested shard. - for i in (0..4).rev() { - if let Some(node) = subtree.get_node_if_in_mem(since_generation) { - match node.inner() { - NodeInner::Internal(internal_node) => { - subtree = match (shard_id >> i) & 1 { - 0 => { - pos.push(false); - internal_node.left.weak() - }, - 1 => { - pos.push(true); - internal_node.right.weak() - }, - _ => { - unreachable!() - }, - } - }, - NodeInner::Leaf(leaf_node) => { - if get_state_shard_id(leaf_node.key) == shard_id { - let mut nibble_path = NibblePath::new_even(vec![]); - nibble_path.push(Nibble::from(shard_id)); - node_hashes.insert(nibble_path, subtree.hash()); - } - return node_hashes; - }, - } - } else { - return node_hashes; - } - } - Self::new_node_hashes_since_impl( - subtree, - since_smt.generation() + 1, - &mut pos, - &mut node_hashes, - ); - node_hashes + unimplemented!() } /// Recursively generate the partial node update batch of jellyfish merkle fn new_node_hashes_since_impl( - subtree: SubTree, - since_generation: u64, - pos: &mut NodePosition, - node_hashes: &mut HashMap, + _subtree: SubTree, + _since_generation: u64, + _pos: &mut NodePosition, + _node_hashes: &mut HashMap, ) { - if let Some(node) = subtree.get_node_if_in_mem(since_generation) { - let is_nibble = if let Some(path) = Self::maybe_to_nibble_path(pos) { - node_hashes.insert(path, subtree.hash()); - true - } else { - false - }; - match node.inner() { - NodeInner::Internal(internal_node) => { - let depth = pos.len(); - pos.push(false); - Self::new_node_hashes_since_impl( - internal_node.left.weak(), - since_generation, - pos, - node_hashes, - ); - *pos.get_mut(depth).unwrap() = true; - Self::new_node_hashes_since_impl( - internal_node.right.weak(), - since_generation, - pos, - node_hashes, - ); - pos.pop(); - }, - NodeInner::Leaf(leaf_node) => { - let mut path = NibblePath::new_even(leaf_node.key.to_vec()); - if !is_nibble { - path.truncate(pos.len() / BITS_IN_NIBBLE + 1); - node_hashes.insert(path, subtree.hash()); - } - }, - } - } + unimplemented!() } fn maybe_to_nibble_path(pos: &NodePosition) -> Option { @@ -413,17 +325,14 @@ where { pub fn batch_update( &self, - updates: Vec<(HashValue, Option<&V>)>, - proof_reader: &impl ProofRead, + _updates: Vec<(HashValue, Option<&V>)>, + _proof_reader: &impl ProofRead, ) -> Result { - self.clone() - .freeze(self) - .batch_update(updates, StateStorageUsage::Untracked, proof_reader) - .map(FrozenSparseMerkleTree::unfreeze) + unimplemented!() } - pub fn get(&self, key: HashValue) -> StateStoreStatus { - self.clone().freeze(self).get(key) + pub fn get(&self, _key: HashValue) -> StateStoreStatus { + unimplemented!() } } @@ -467,7 +376,7 @@ impl FrozenSparseMerkleTree where V: Clone + CryptoHash + ArcAsyncDrop, { - fn spawn(&self, child_root: SubTree, child_usage: StateStorageUsage) -> Self { + fn spawn(&self, child_root: Root, child_usage: StateStorageUsage) -> Self { let smt = SparseMerkleTree { inner: self.smt.inner.spawn(child_root, child_usage), }; @@ -500,73 +409,81 @@ where ) -> Result { // Flatten, dedup and sort the updates with a btree map since the updates between different // versions may overlap on the same address in which case the latter always overwrites. - let kvs = updates + let updates = updates .into_iter() .collect::>() .into_iter() + .map(|(k, v)| (HashAsKey(k), Some(v.cloned()))) .collect::>(); - if kvs.is_empty() { + if updates.is_empty() { if !usage.is_untracked() { assert_eq!(self.smt.inner.usage, usage); } - Ok(self.clone()) - } else { - let current_root = self.smt.root_weak(); - let root = SubTreeUpdater::update( - current_root, - &kvs[..], - proof_reader, - self.smt.inner.generation + 1, - )?; - Ok(self.spawn(root, usage)) + return Ok(self.clone()); } + + let inc_hash_diff = updates + .par_iter() + .fold( + EllipticCurveMultisetHash::default, + |mut inc_hash, (key, val_opt)| { + if let Some(old_val) = proof_reader.get_proof(key.0) { + let old_hash = SparseMerkleLeafNode::new(key.0, old_val) + .hash() + .into_inner(); + inc_hash.remove(old_hash); + } + if let Some(Some(new_val)) = val_opt { + let new_hash = SparseMerkleLeafNode::new(key.0, new_val.hash()) + .hash() + .into_inner(); + inc_hash.insert(new_hash); + } + inc_hash + }, + ) + .reduce( + EllipticCurveMultisetHash::default, + |mut inc_hash, other_inc_hash| { + inc_hash.union(&other_inc_hash); + inc_hash + }, + ); + let mut inc_hash = self.smt.inner.root().inc_hash.clone(); + inc_hash.union(&inc_hash_diff); + + let content = self + .smt + .inner + .root() + .content + .view_layers_since(&self.base_smt.inner.root().content) + .new_layer(&updates[..]); + + let root = Root::new(inc_hash, content); + + Ok(self.spawn(root, usage)) } /// Queries a `key` in this `SparseMerkleTree`. pub fn get(&self, key: HashValue) -> StateStoreStatus { - let mut subtree = self.smt.root_weak(); - let mut bits = key.iter_bits(); - let mut next_depth = 0; - - loop { - next_depth += 1; - match subtree { - SubTree::Empty => return StateStoreStatus::DoesNotExist, - SubTree::NonEmpty { hash, root: _ } => { - match subtree.get_node_if_in_mem(self.base_generation) { - None => { - return StateStoreStatus::UnknownSubtreeRoot { - hash, - depth: next_depth - 1, - } - }, - Some(node) => match node.inner() { - NodeInner::Internal(internal_node) => { - subtree = if bits.next().expect("Tree is too deep.") { - internal_node.right.weak() - } else { - internal_node.left.weak() - }; - continue; - }, // end NodeInner::Internal - NodeInner::Leaf(leaf_node) => { - return if leaf_node.key == key { - match &leaf_node.value.data.get_if_in_mem() { - Some(value) => StateStoreStatus::ExistsInScratchPad( - value.as_ref().clone(), - ), - None => StateStoreStatus::UnknownValue, - } - } else { - StateStoreStatus::DoesNotExist - }; - }, // end NodeInner::Leaf - }, // end Some(node) got from mem - } - }, // end SubTree::NonEmpty - } - } // end loop + use StateStoreStatus::*; + + match self + .smt + .inner + .root + .content + .view_layers_since(&self.base_smt.inner.root.content) + .get(&HashAsKey(key)) + { + Some(val_opt) => match val_opt { + Some(val) => ExistsInScratchPad(val), + None => DoesNotExist, + }, + None => UnknownValue, + } } pub fn usage(&self) -> StateStorageUsage { @@ -577,7 +494,9 @@ where /// A type that implements `ProofRead` can provide proof for keys in persistent storage. pub trait ProofRead: Sync { /// Gets verified proof for this key in persistent storage. - fn get_proof(&self, key: HashValue) -> Option<&SparseMerkleProofExt>; + + // HACK: reuse ProofRead to return value hash on base version + fn get_proof(&self, key: HashValue) -> Option; } /// All errors `update` can possibly return. diff --git a/storage/scratchpad/src/sparse_merkle/test_utils/naive_smt.rs b/storage/scratchpad/src/sparse_merkle/test_utils/naive_smt.rs index dc86fe5b9ff5a9..b7e1015a0ed481 100644 --- a/storage/scratchpad/src/sparse_merkle/test_utils/naive_smt.rs +++ b/storage/scratchpad/src/sparse_merkle/test_utils/naive_smt.rs @@ -7,9 +7,7 @@ use aptos_crypto::{ hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH}, HashValue, }; -use aptos_types::proof::{ - definition::NodeInProof, SparseMerkleInternalNode, SparseMerkleLeafNode, SparseMerkleProofExt, -}; +use aptos_types::proof::{definition::NodeInProof, SparseMerkleInternalNode, SparseMerkleLeafNode}; use bitvec::prelude::*; use std::collections::{BTreeMap, HashMap}; @@ -148,14 +146,8 @@ impl NaiveSmt { } } - pub fn get_proof(&mut self, key: &HashValue) -> SparseMerkleProofExt { - let root = NaiveSubTree { - leaves: &self.leaves, - depth: 0, - }; - - let (leaf, siblings) = root.get_proof(key, &mut self.cache); - SparseMerkleProofExt::new(leaf, siblings) + pub fn get_proof(&mut self, _key: &HashValue) -> Option { + unimplemented!() } pub fn get_root_hash(&mut self) -> HashValue { diff --git a/storage/scratchpad/src/sparse_merkle/test_utils/proof_reader.rs b/storage/scratchpad/src/sparse_merkle/test_utils/proof_reader.rs index 9a5195acd73648..0fc58e5a355478 100644 --- a/storage/scratchpad/src/sparse_merkle/test_utils/proof_reader.rs +++ b/storage/scratchpad/src/sparse_merkle/test_utils/proof_reader.rs @@ -4,20 +4,19 @@ use crate::ProofRead; use aptos_crypto::HashValue; -use aptos_types::proof::SparseMerkleProofExt; use std::collections::HashMap; #[derive(Default)] -pub struct ProofReader(HashMap); +pub struct ProofReader(HashMap>); impl ProofReader { - pub fn new(key_with_proof: Vec<(HashValue, SparseMerkleProofExt)>) -> Self { + pub fn new(key_with_proof: Vec<(HashValue, Option)>) -> Self { ProofReader(key_with_proof.into_iter().collect()) } } impl ProofRead for ProofReader { - fn get_proof(&self, key: HashValue) -> Option<&SparseMerkleProofExt> { - self.0.get(&key) + fn get_proof(&self, key: HashValue) -> Option { + *self.0.get(&key).unwrap() } } diff --git a/storage/scratchpad/src/sparse_merkle/test_utils/proptest_helpers.rs b/storage/scratchpad/src/sparse_merkle/test_utils/proptest_helpers.rs index 0cea1a3a60f8fa..447c46ebec9c91 100644 --- a/storage/scratchpad/src/sparse_merkle/test_utils/proptest_helpers.rs +++ b/storage/scratchpad/src/sparse_merkle/test_utils/proptest_helpers.rs @@ -131,7 +131,7 @@ trait AssertNoExternalStrongRef { impl AssertNoExternalStrongRef for SparseMerkleTree { fn assert_no_external_strong_ref(&self) { - assert_subtree_sole_strong_ref(self.inner.root()); + unimplemented!() } } diff --git a/storage/storage-interface/Cargo.toml b/storage/storage-interface/Cargo.toml index 6b2cb638242b17..e04c1901b38522 100644 --- a/storage/storage-interface/Cargo.toml +++ b/storage/storage-interface/Cargo.toml @@ -24,7 +24,7 @@ aptos-types = { workspace = true } aptos-vm = { workspace = true } bcs = { workspace = true } crossbeam-channel = { workspace = true } -dashmap = { workspace = true } +dashmap = { workspace = true, features = ["rayon"] } once_cell = { workspace = true } parking_lot = { workspace = true } proptest = { workspace = true } diff --git a/storage/storage-interface/src/cached_state_view.rs b/storage/storage-interface/src/cached_state_view.rs index 9bde8daf493a3e..bef4c949e105c0 100644 --- a/storage/storage-interface/src/cached_state_view.rs +++ b/storage/storage-interface/src/cached_state_view.rs @@ -6,9 +6,9 @@ use crate::{ }; use aptos_crypto::{hash::CryptoHash, HashValue}; use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; +use aptos_logger::info; use aptos_scratchpad::{FrozenSparseMerkleTree, SparseMerkleTree, StateStoreStatus}; use aptos_types::{ - proof::SparseMerkleProofExt, state_store::{ errors::StateviewError, state_key::StateKey, state_storage_usage::StateStorageUsage, state_value::StateValue, StateViewId, TStateView, @@ -20,7 +20,7 @@ use core::fmt; use dashmap::DashMap; use once_cell::sync::Lazy; use parking_lot::RwLock; -use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator}; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use std::{ collections::{HashMap, HashSet}, fmt::{Debug, Formatter}, @@ -78,6 +78,10 @@ impl ShardedStateCache { pub fn par_iter(&self) -> impl IndexedParallelIterator { self.shards.par_iter() } + + pub fn iter(&self) -> impl Iterator { + self.shards.iter() + } } /// `CachedStateView` is like a snapshot of the global state comprised of state view at two @@ -134,7 +138,9 @@ pub struct CachedStateView { /// the corresponding key has been deleted. This is a temporary hack until we support deletion /// in JMT node. sharded_state_cache: ShardedStateCache, - proof_fetcher: Arc, + + /// db + reader: Arc, } impl Debug for CachedStateView { @@ -152,7 +158,7 @@ impl CachedStateView { reader: Arc, next_version: Version, speculative_state: SparseMerkleTree, - proof_fetcher: Arc, + _proof_fetcher: Arc, ) -> Result { // n.b. Freeze the state before getting the state snapshot, otherwise it's possible that // after we got the snapshot, in-mem trees newer than it gets dropped before being frozen, @@ -162,27 +168,23 @@ impl CachedStateView { let snapshot = reader .get_state_snapshot_before(next_version) .map_err(Into::::into)?; + info!(snapshot = snapshot, "alden alden alden."); - Ok(Self::new_impl( - id, - snapshot, - speculative_state, - proof_fetcher, - )) + Ok(Self::new_impl(id, snapshot, speculative_state, reader)) } pub fn new_impl( id: StateViewId, snapshot: Option<(Version, HashValue)>, speculative_state: FrozenSparseMerkleTree, - proof_fetcher: Arc, + reader: Arc, ) -> Self { Self { id, snapshot, speculative_state, sharded_state_cache: ShardedStateCache::default(), - proof_fetcher, + reader, } } @@ -207,10 +209,27 @@ impl CachedStateView { } pub fn into_state_cache(self) -> StateCache { + let proofs = self + .sharded_state_cache + .par_iter() + .map(|shard| { + shard + .par_iter() + .map(|dashmap_ref| { + let (key, (_val_ver_opt, val_opt)) = dashmap_ref.pair(); + (key.hash(), val_opt.as_ref().map(CryptoHash::hash)) + }) + .collect::>() + }) + .collect::>() + .into_iter() + .flatten() + .collect(); + StateCache { frozen_base: self.speculative_state, sharded_state_cache: self.sharded_state_cache, - proofs: self.proof_fetcher.get_proof_cache(), + proofs, } } @@ -223,39 +242,28 @@ impl CachedStateView { match self.speculative_state.get(key_hash) { StateStoreStatus::ExistsInScratchPad(value) => Ok((None, Some(value))), StateStoreStatus::DoesNotExist => Ok((None, None)), - // Part of the tree is unknown, need to request proof for later usage (updating the tree) - StateStoreStatus::UnknownSubtreeRoot { - hash: subtree_root_hash, - depth: subtree_root_depth, - } => self.fetch_value_and_maybe_proof_in_snapshot( - state_key, - Some((subtree_root_hash, subtree_root_depth)), - ), // Tree is known, but we only know the hash of the value, need to request the actual // StateValue. StateStoreStatus::UnknownValue => { self.fetch_value_and_maybe_proof_in_snapshot(state_key, None) }, + StateStoreStatus::UnknownSubtreeRoot { .. } => unreachable!(), } } fn fetch_value_and_maybe_proof_in_snapshot( &self, state_key: &StateKey, - fetch_proof: Option<(HashValue, usize)>, + _fetch_proof: Option<(HashValue, usize)>, ) -> Result<(Option, Option)> { let version_and_value_opt = match self.snapshot { None => None, - Some((version, _root_hash)) => match fetch_proof { - None => self.proof_fetcher.fetch_state_value(state_key, version)?, - Some((subtree_root_hash, subtree_depth)) => self - .proof_fetcher - .fetch_state_value_with_version_and_schedule_proof_read( - state_key, - version, - subtree_depth, - Some(subtree_root_hash), - )?, + Some((version, _root_hash)) => { + let _timer = TIMER + .with_label_values(&["async_proof_fetcher_fetch"]) + .start_timer(); + self.reader + .get_state_value_with_version_by_version(state_key, version)? }, }; Ok(match version_and_value_opt { @@ -268,7 +276,7 @@ impl CachedStateView { pub struct StateCache { pub frozen_base: FrozenSparseMerkleTree, pub sharded_state_cache: ShardedStateCache, - pub proofs: HashMap, + pub proofs: HashMap>, } impl TStateView for CachedStateView {