Skip to content

Commit 74ac33f

Browse files
committed
feat: get data from hash
1 parent 71cad36 commit 74ac33f

File tree

5 files changed

+138
-2
lines changed

5 files changed

+138
-2
lines changed

clarity/src/vm/database/clarity_store.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::path::PathBuf;
1818

1919
#[cfg(feature = "canonical")]
2020
use rusqlite::Connection;
21-
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId, VRFSeed};
21+
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId, TrieHash, VRFSeed};
2222
use stacks_common::util::hash::{hex_bytes, to_hex, Hash160, Sha512Trunc256Sum};
2323

2424
use crate::vm::analysis::AnalysisDatabase;
@@ -67,6 +67,10 @@ pub trait ClarityBackingStore {
6767
/// fetch K-V out of the committed datastore, along with the byte representation
6868
/// of the Merkle proof for that key-value pair
6969
fn get_data_with_proof(&mut self, key: &str) -> Result<Option<(String, Vec<u8>)>>;
70+
fn get_data_with_proof_from_path(
71+
&mut self,
72+
hash: &TrieHash,
73+
) -> Result<Option<(String, Vec<u8>)>>;
7074
fn has_entry(&mut self, key: &str) -> Result<bool> {
7175
Ok(self.get_data(key)?.is_some())
7276
}
@@ -213,6 +217,13 @@ impl ClarityBackingStore for NullBackingStore {
213217
panic!("NullBackingStore can't retrieve data")
214218
}
215219

220+
fn get_data_with_proof_from_path(
221+
&mut self,
222+
_hash: &TrieHash,
223+
) -> Result<Option<(String, Vec<u8>)>> {
224+
panic!("NullBackingStore can't retrieve data")
225+
}
226+
216227
#[cfg(feature = "canonical")]
217228
fn get_side_store(&mut self) -> &Connection {
218229
panic!("NullBackingStore has no side store")

clarity/src/vm/database/sqlite.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rusqlite::{
1919
params, Connection, Error as SqliteError, ErrorCode as SqliteErrorCode, OptionalExtension, Row,
2020
Savepoint,
2121
};
22-
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId};
22+
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId, TrieHash};
2323
use stacks_common::types::sqlite::NO_PARAMS;
2424
use stacks_common::util::db_common::tx_busy_handler;
2525
use stacks_common::util::hash::Sha512Trunc256Sum;
@@ -328,6 +328,13 @@ impl ClarityBackingStore for MemoryBackingStore {
328328
Ok(SqliteConnection::get(self.get_side_store(), key)?.map(|x| (x, vec![])))
329329
}
330330

331+
fn get_data_with_proof_from_path(
332+
&mut self,
333+
hash: &TrieHash,
334+
) -> Result<Option<(String, Vec<u8>)>> {
335+
self.get_data_with_proof(&hash.to_string())
336+
}
337+
331338
fn get_side_store(&mut self) -> &Connection {
332339
&self.side_store
333340
}

stackslib/src/chainstate/stacks/index/marf.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ pub trait MarfConnection<T: MarfTrieId> {
142142
})
143143
}
144144

145+
fn get_with_proof_from_hash(
146+
&mut self,
147+
block_hash: &T,
148+
hash: &TrieHash,
149+
) -> Result<Option<(MARFValue, TrieMerkleProof<T>)>, Error> {
150+
self.with_conn(|conn| {
151+
let path = TriePath::from_bytes(hash.as_bytes()).ok_or(Error::BadSeekValue)?;
152+
let marf_value = match MARF::get_by_path(conn, block_hash, &path)? {
153+
None => return Ok(None),
154+
Some(x) => x,
155+
};
156+
let proof = TrieMerkleProof::from_path(conn, &path, &marf_value, block_hash)?;
157+
Ok(Some((marf_value, proof)))
158+
})
159+
}
160+
145161
fn get_block_at_height(&mut self, height: u32, tip: &T) -> Result<Option<T>, Error> {
146162
self.with_conn(|c| MARF::get_block_at_height(c, height, tip))
147163
}
@@ -1123,6 +1139,33 @@ impl<T: MarfTrieId> MARF<T> {
11231139
Ok(MARF::from_storage(file_storage))
11241140
}
11251141

1142+
pub fn get_by_path(
1143+
storage: &mut TrieStorageConnection<T>,
1144+
block_hash: &T,
1145+
path: &TriePath,
1146+
) -> Result<Option<MARFValue>, Error> {
1147+
let (cur_block_hash, cur_block_id) = storage.get_cur_block_and_id();
1148+
1149+
let result = MARF::get_path(storage, block_hash, &path).or_else(|e| match e {
1150+
Error::NotFoundError => Ok(None),
1151+
_ => Err(e),
1152+
});
1153+
1154+
// restore
1155+
storage
1156+
.open_block_maybe_id(&cur_block_hash, cur_block_id)
1157+
.map_err(|e| {
1158+
warn!(
1159+
"Failed to re-open {} {:?}: {:?}",
1160+
&cur_block_hash, cur_block_id, &e
1161+
);
1162+
warn!("Result of failed path lookup '{}': {:?}", path, &result);
1163+
e
1164+
})?;
1165+
1166+
result.map(|option_result| option_result.map(|leaf| leaf.data))
1167+
}
1168+
11261169
pub fn get_by_key(
11271170
storage: &mut TrieStorageConnection<T>,
11281171
block_hash: &T,
@@ -1320,6 +1363,21 @@ impl<T: MarfTrieId> MARF<T> {
13201363
Ok(Some((marf_value, proof)))
13211364
}
13221365

1366+
pub fn get_with_proof_from_hash(
1367+
&mut self,
1368+
block_hash: &T,
1369+
hash: &TrieHash,
1370+
) -> Result<Option<(MARFValue, TrieMerkleProof<T>)>, Error> {
1371+
let mut conn = self.storage.connection();
1372+
let path = TriePath::from_bytes(hash.as_bytes()).ok_or(Error::BadSeekValue)?;
1373+
let marf_value = match MARF::get_by_path(&mut conn, block_hash, &path)? {
1374+
None => return Ok(None),
1375+
Some(x) => x,
1376+
};
1377+
let proof = TrieMerkleProof::from_path(&mut conn, &path, &marf_value, block_hash)?;
1378+
Ok(Some((marf_value, proof)))
1379+
}
1380+
13231381
pub fn get_bhh_at_height(&mut self, block_hash: &T, height: u32) -> Result<Option<T>, Error> {
13241382
MARF::get_block_at_height(&mut self.storage.connection(), height, block_hash)
13251383
}

stackslib/src/clarity_vm/database/marf.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use stacks_common::codec::StacksMessageCodec;
2020
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId, TrieHash};
2121

2222
use crate::chainstate::stacks::index::marf::{MARFOpenOpts, MarfConnection, MarfTransaction, MARF};
23+
use crate::chainstate::stacks::index::node::TriePath;
2324
use crate::chainstate::stacks::index::{
2425
ClarityMarfTrieId, Error, MARFValue, MarfTrieId, TrieMerkleProof,
2526
};
@@ -422,6 +423,31 @@ impl<'a> ClarityBackingStore for ReadOnlyMarfStore<'a> {
422423
.transpose()
423424
}
424425

426+
fn get_data_with_proof_from_path(
427+
&mut self,
428+
hash: &TrieHash,
429+
) -> InterpreterResult<Option<(String, Vec<u8>)>> {
430+
self.marf
431+
.get_with_proof_from_hash(&self.chain_tip, hash)
432+
.or_else(|e| match e {
433+
Error::NotFoundError => Ok(None),
434+
_ => Err(e),
435+
})
436+
.map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))?
437+
.map(|(marf_value, proof)| {
438+
let side_key = marf_value.to_hex();
439+
let data =
440+
SqliteConnection::get(self.get_side_store(), &side_key)?.ok_or_else(|| {
441+
InterpreterError::Expect(format!(
442+
"ERROR: MARF contained value_hash not found in side storage: {}",
443+
side_key
444+
))
445+
})?;
446+
Ok((data, proof.serialize_to_vec()))
447+
})
448+
.transpose()
449+
}
450+
425451
fn get_data(&mut self, key: &str) -> InterpreterResult<Option<String>> {
426452
trace!("MarfedKV get: {:?} tip={}", key, &self.chain_tip);
427453
self.marf
@@ -653,6 +679,31 @@ impl<'a> ClarityBackingStore for WritableMarfStore<'a> {
653679
.transpose()
654680
}
655681

682+
fn get_data_with_proof_from_path(
683+
&mut self,
684+
hash: &TrieHash,
685+
) -> InterpreterResult<Option<(String, Vec<u8>)>> {
686+
self.marf
687+
.get_with_proof_from_hash(&self.chain_tip, hash)
688+
.or_else(|e| match e {
689+
Error::NotFoundError => Ok(None),
690+
_ => Err(e),
691+
})
692+
.map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))?
693+
.map(|(marf_value, proof)| {
694+
let side_key = marf_value.to_hex();
695+
let data =
696+
SqliteConnection::get(self.marf.sqlite_tx(), &side_key)?.ok_or_else(|| {
697+
InterpreterError::Expect(format!(
698+
"ERROR: MARF contained value_hash not found in side storage: {}",
699+
side_key
700+
))
701+
})?;
702+
Ok((data, proof.serialize_to_vec()))
703+
})
704+
.transpose()
705+
}
706+
656707
fn get_side_store(&mut self) -> &Connection {
657708
self.marf.sqlite_tx()
658709
}

stackslib/src/clarity_vm/database/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::ops::{Deref, DerefMut};
22

3+
use clarity::types::chainstate::TrieHash;
34
use clarity::util::hash::Sha512Trunc256Sum;
45
use clarity::vm::analysis::AnalysisDatabase;
56
use clarity::vm::database::sqlite::{
@@ -1138,6 +1139,14 @@ impl ClarityBackingStore for MemoryBackingStore {
11381139
Ok(SqliteConnection::get(self.get_side_store(), key)?.map(|x| (x, vec![])))
11391140
}
11401141

1142+
fn get_data_with_proof_from_path(
1143+
&mut self,
1144+
key: &TrieHash,
1145+
) -> InterpreterResult<Option<(String, Vec<u8>)>> {
1146+
// Ok(SqliteConnection::get(self.get_side_store(), )?.map(|x| (x, vec![])))
1147+
Ok(SqliteConnection::get(self.get_side_store(), key)?.map(|x| (x, vec![])))
1148+
}
1149+
11411150
fn get_side_store(&mut self) -> &Connection {
11421151
&self.side_store
11431152
}

0 commit comments

Comments
 (0)