Skip to content

Commit 073eb44

Browse files
fix: implement jmt (#7036)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for reading versioned values, allowing retrieval of the latest value for a given key. - **Bug Fixes** - Improved value lookup logic to ensure the most recent data is returned when querying by key. - **Chores** - Enhanced logging for output fetching and spend status determination. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: SW van Heerden <swvheerden@gmail.com>
1 parent 2dfcfbe commit 073eb44

File tree

3 files changed

+57
-17
lines changed

3 files changed

+57
-17
lines changed

base_layer/core/src/chain_storage/blockchain_database.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,12 @@ where B: BlockchainBackend
477477
for hash in hashes {
478478
let output = db.fetch_output(&hash)?;
479479

480+
trace!(
481+
target: LOG_TARGET,
482+
"fetch_outputs_with_spend_status_at_tip: hash: {}, output: {:?}",
483+
hash.to_hex(),
484+
output
485+
);
480486
if let Some(mined_info) = output {
481487
let smt_key = KeyHash(
482488
mined_info
@@ -490,7 +496,13 @@ where B: BlockchainBackend
490496
let spent = smt
491497
.get(smt_key, tip)
492498
.map_err(ChainStorageError::JellyfishMerkleTreeError)?
493-
.is_some();
499+
.is_none();
500+
trace!(
501+
target: LOG_TARGET,
502+
"fetch_outputs_with_spend_status_at_tip: smt_key: {:?}, spent: {}",
503+
smt_key,
504+
spent
505+
);
494506
result.push(Some((mined_info.output, spent)));
495507
} else {
496508
result.push(None);

base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ impl LMDBDatabase {
989989
self.delete_block_inputs_outputs(write_txn, block_hash.as_slice())?;
990990

991991
let new_tip_header = self.fetch_chain_header_by_height(prev_height)?;
992-
let reader = LmdbTreeReader::new(write_txn, self.jmt_node_data.clone());
992+
let reader = LmdbTreeReader::new(write_txn, self.jmt_node_data.clone(), self.jmt_unique_key_data.clone());
993993
let jmt = JellyfishMerkleTree::<_, SmtHasher>::new(&reader);
994994

995995
let root = jmt
@@ -1252,7 +1252,7 @@ impl LMDBDatabase {
12521252
// smt_writer: &mut LmdbTreeWriter,
12531253
) -> Result<(), ChainStorageError> {
12541254
// let smt_reader = LmdbTreeReader::new();
1255-
let smt_reader = LmdbTreeReader::new(txn, self.jmt_node_data.clone());
1255+
let smt_reader = LmdbTreeReader::new(txn, self.jmt_node_data.clone(), self.jmt_unique_key_data.clone());
12561256
let output_smt = JellyfishMerkleTree::<_, SmtHasher>::new(&smt_reader);
12571257
if self.fetch_block_accumulated_data(txn, header.height + 1)?.is_some() {
12581258
return Err(ChainStorageError::InvalidOperation(format!(
@@ -1889,7 +1889,8 @@ fn acquire_exclusive_file_lock(db_path: &Path) -> Result<File, ChainStorageError
18891889
impl BlockchainBackend for LMDBDatabase {
18901890
fn create_smt_reader(&self) -> Result<OwnedLmdbTreeReader<'_>, ChainStorageError> {
18911891
let read_tx = self.read_transaction()?;
1892-
let smt_reader = OwnedLmdbTreeReader::new(read_tx, self.jmt_node_data.clone());
1892+
let smt_reader =
1893+
OwnedLmdbTreeReader::new(read_tx, self.jmt_node_data.clone(), self.jmt_unique_key_data.clone());
18931894

18941895
Ok(smt_reader)
18951896
}

base_layer/core/src/chain_storage/lmdb_db/lmdb_tree_reader.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,29 @@ use std::ops::Deref;
2525
use borsh::BorshSerialize;
2626
use jmt::storage::TreeReader;
2727
use lmdb_zero::{ConstTransaction, ReadTransaction};
28+
use log::warn;
2829
use tari_storage::lmdb_store::DatabaseRef;
2930

30-
use crate::chain_storage::lmdb_db::lmdb::lmdb_get;
31+
use crate::chain_storage::lmdb_db::lmdb::{lmdb_fetch_matching_after, lmdb_get};
32+
33+
pub const LOG_TARGET: &str = "c::cs::lmdb_db::lmdb_db";
3134

3235
pub struct LmdbTreeReader<'a> {
3336
txn: &'a ConstTransaction<'a>,
3437
node_db: DatabaseRef,
38+
unique_key_db: DatabaseRef,
3539
}
3640

3741
impl<'a> LmdbTreeReader<'a> {
38-
pub fn new<T: Deref<Target = ConstTransaction<'a>>>(txn: &'a T, node_db: DatabaseRef) -> Self {
42+
pub fn new<T: Deref<Target = ConstTransaction<'a>>>(
43+
txn: &'a T,
44+
node_db: DatabaseRef,
45+
unique_key_db: DatabaseRef,
46+
) -> Self {
3947
Self {
4048
txn: txn.deref(),
4149
node_db,
50+
unique_key_db,
4251
}
4352
}
4453
}
@@ -54,12 +63,24 @@ impl TreeReader for LmdbTreeReader<'_> {
5463

5564
fn get_value_option(
5665
&self,
57-
_max_version: jmt::Version,
58-
_key_hash: jmt::KeyHash,
66+
max_version: jmt::Version,
67+
key_hash: jmt::KeyHash,
5968
) -> anyhow::Result<Option<jmt::OwnedValue>> {
60-
todo!()
61-
// TODO: implement after saving
62-
// Ok(None)
69+
// see if there are any values already.
70+
let existing_values: Vec<(Vec<u8>, Option<Vec<u8>>)> =
71+
lmdb_fetch_matching_after(self.txn, &self.unique_key_db, &key_hash.0)?;
72+
let mut existing_history = vec![];
73+
for (key, x) in existing_values {
74+
let version = u64::from_be_bytes(key[32..].try_into().unwrap());
75+
existing_history.push((version, x));
76+
warn!(target: LOG_TARGET, "found version {} for key {:?}", version, key);
77+
}
78+
// sort by version
79+
existing_history.sort_by(|a, b| a.0.cmp(&b.0));
80+
81+
let latest_value = existing_history.last().and_then(|x| x.1.clone());
82+
83+
Ok(latest_value)
6384
}
6485

6586
fn get_rightmost_leaf(&self) -> anyhow::Result<Option<(jmt::storage::NodeKey, jmt::storage::LeafNode)>> {
@@ -71,26 +92,32 @@ impl TreeReader for LmdbTreeReader<'_> {
7192
pub struct OwnedLmdbTreeReader<'a> {
7293
txn: ReadTransaction<'a>,
7394
node_db: DatabaseRef,
95+
unique_key_db: DatabaseRef,
7496
}
7597

7698
impl<'a> OwnedLmdbTreeReader<'a> {
77-
pub fn new(txn: ReadTransaction<'a>, node_db: DatabaseRef) -> Self {
78-
Self { txn, node_db }
99+
pub fn new(txn: ReadTransaction<'a>, node_db: DatabaseRef, unique_key_db: DatabaseRef) -> Self {
100+
Self {
101+
txn,
102+
node_db,
103+
unique_key_db,
104+
}
79105
}
80106
}
81107

82108
impl TreeReader for OwnedLmdbTreeReader<'_> {
83109
fn get_node_option(&self, node_key: &jmt::storage::NodeKey) -> anyhow::Result<Option<jmt::storage::Node>> {
84-
let inner = LmdbTreeReader::new(&self.txn, self.node_db.clone());
110+
let inner = LmdbTreeReader::new(&self.txn, self.node_db.clone(), self.unique_key_db.clone());
85111
inner.get_node_option(node_key)
86112
}
87113

88114
fn get_value_option(
89115
&self,
90-
_max_version: jmt::Version,
91-
_key_hash: jmt::KeyHash,
116+
max_version: jmt::Version,
117+
key_hash: jmt::KeyHash,
92118
) -> anyhow::Result<Option<jmt::OwnedValue>> {
93-
todo!()
119+
let inner = LmdbTreeReader::new(&self.txn, self.node_db.clone(), self.unique_key_db.clone());
120+
inner.get_value_option(max_version, key_hash)
94121
}
95122

96123
fn get_rightmost_leaf(&self) -> anyhow::Result<Option<(jmt::storage::NodeKey, jmt::storage::LeafNode)>> {

0 commit comments

Comments
 (0)