Repository navigation
feat: subtree dump/restore primitives #752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
1162b50
feat: expose ingest_subtree_sst + replace_commitment_tree_subtree_root
shumkov 04f2d42
feat: expose raw_storage() on GroveDb
shumkov 48a000b
feat(commitment-tree): frontier-less bulk seeding for sync/scale testing
QuantumExplorer 3fd3990
fix(commitment-tree): reject frontier-less seeding on a non-empty fro…
QuantumExplorer b7b2090
refactor(commitment-tree): rename feature to test-seeding-ct; drop op…
QuantumExplorer d3adb02
test(commitment-tree): cover frontier-less seeding error paths for pa…
QuantumExplorer 5e4761b
perf(bulk-append-tree): cache MMR root so append is O(1), not O(N) pe…
QuantumExplorer 60d1219
bench(commitment-tree): add 1M frontier-less seeding throughput bench…
QuantumExplorer fa7a230
feat(commitment-tree): batched append_many_raw — replace _without_fro…
QuantumExplorer bdc0d6e
docs(commitment-tree): add --features server to seeding bench example…
QuantumExplorer 5eb7a53
fix(commitment-tree): don't commit_mmr inside append_many_raw
QuantumExplorer 4cedf18
Merge remote-tracking branch 'origin/develop' into feat/snapshot-appl…
shumkov bd36a1d
style: cargo fmt --all
shumkov 67acdbc
chore: drop vestigial BulkAppendTree::append_many helper
shumkov 2e9dff5
feat: gate snapshot-bootstrap surface behind `unsafe-dump-load` feature
shumkov c7f6dc3
style: cargo fmt (cfg-gated import order)
shumkov 62e1296
test(grovedb): unsafe-dump-load subtree roundtrip + non-tree rejection
shumkov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| //! Caller-driven subtree-root replacement. | ||
| //! | ||
| //! Replaces a subtree leaf's child hash + element data inside its parent | ||
| //! Merk with caller-provided values, **without** re-reading the subtree to | ||
| //! compute the hash. This is the tail of every `*_insert` operation | ||
| //! (commitment_tree, mmr_tree, bulk_append_tree, dense_tree) factored out as | ||
| //! a single generic helper, intended for **snapshot-based bootstrap** only. | ||
| //! | ||
| //! # Safety contract | ||
| //! | ||
| //! The caller is responsible for ensuring `new_combined_root` actually | ||
| //! matches the subtree's underlying storage state. Intended pattern: | ||
| //! | ||
| //! 1. Ingest the subtree's raw storage out-of-band (typically via | ||
| //! [`grovedb_storage::rocksdb_storage::RocksDbStorage::ingest_subtree_sst`]). | ||
| //! 2. Open a `StorageContext` at the subtree path and reconstruct the | ||
| //! appropriate typed tree (CommitmentTree / Mmr / BulkAppend / Dense). | ||
| //! 3. Compute the post-ingest combined root via that tree's own root fn. | ||
| //! 4. Call [`GroveDb::replace_subtree_root`] with the verified hash and a | ||
| //! correctly-constructed [`Element`] (e.g. `Element::new_commitment_tree`). | ||
| //! | ||
| //! Mismatches between `new_combined_root` and what re-reading the subtree | ||
| //! would compute produce an inconsistent Merk tree (the parent's recorded | ||
| //! child hash diverges from actual subtree state). This method does NOT | ||
| //! detect such mismatches at runtime; misuse is silent corruption. | ||
| //! | ||
| //! Gated behind the `unsafe-dump-load` Cargo feature. | ||
|
|
||
| use std::collections::HashMap; | ||
|
|
||
| use grovedb_costs::{ | ||
| cost_return_on_error, cost_return_on_error_into, CostResult, CostsExt, OperationCost, | ||
| }; | ||
| use grovedb_merk::element::{ | ||
| insert::ElementInsertToStorageExtensions, tree_type::ElementTreeTypeExtensions, | ||
| }; | ||
| use grovedb_path::SubtreePath; | ||
| use grovedb_storage::{Storage, StorageBatch}; | ||
| use grovedb_version::version::GroveVersion; | ||
|
|
||
| use crate::{util::TxRef, Element, Error, GroveDb, TransactionArg}; | ||
|
|
||
| impl GroveDb { | ||
| /// Replace the child hash + element data of a subtree leaf in its parent | ||
| /// Merk with caller-provided values. See the | ||
| /// [module-level docs](self) for the safety contract. | ||
| pub fn replace_subtree_root<'b, B, P>( | ||
| &self, | ||
| path: P, | ||
| key: &[u8], | ||
| new_element: Element, | ||
| new_combined_root: [u8; 32], | ||
| transaction: TransactionArg, | ||
| grove_version: &GroveVersion, | ||
| ) -> CostResult<(), Error> | ||
| where | ||
| B: AsRef<[u8]> + 'b, | ||
| P: Into<SubtreePath<'b, B>>, | ||
| { | ||
| let mut cost = OperationCost::default(); | ||
|
|
||
| // Cheap sanity check: must be a tree-shaped Element (Item / Reference | ||
| // have no child hash slot). Caller still owns hash-vs-state | ||
| // correctness. | ||
| if new_element.tree_type().is_none() { | ||
| return Err(Error::InvalidInput( | ||
| "replace_subtree_root: element is not a tree variant", | ||
| )) | ||
| .wrap_with_cost(cost); | ||
| } | ||
|
|
||
| let path: SubtreePath<B> = path.into(); | ||
| let tx = TxRef::new(&self.db, transaction); | ||
| let batch = StorageBatch::new(); | ||
|
|
||
| let mut parent_merk = cost_return_on_error!( | ||
| &mut cost, | ||
| self.open_transactional_merk_at_path( | ||
| path.clone(), | ||
| tx.as_ref(), | ||
| Some(&batch), | ||
| grove_version, | ||
| ) | ||
| ); | ||
|
|
||
| cost_return_on_error_into!( | ||
| &mut cost, | ||
| new_element.insert_subtree( | ||
| &mut parent_merk, | ||
| key, | ||
| new_combined_root, | ||
| None, | ||
| grove_version, | ||
| ) | ||
| ); | ||
|
|
||
| let mut merk_cache = HashMap::new(); | ||
| merk_cache.insert(path.clone(), parent_merk); | ||
|
|
||
| cost_return_on_error!( | ||
| &mut cost, | ||
| self.propagate_changes_with_transaction( | ||
| merk_cache, | ||
| path, | ||
| tx.as_ref(), | ||
| &batch, | ||
| grove_version, | ||
| ) | ||
| ); | ||
|
|
||
| cost_return_on_error!( | ||
| &mut cost, | ||
| self.db | ||
| .commit_multi_context_batch(batch, Some(tx.as_ref())) | ||
| .map_err(Into::into) | ||
| ); | ||
|
|
||
| tx.commit_local().wrap_with_cost(cost) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.