From 7eb09b909969d536137d6d26f7a38b052d789860 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 14 Oct 2024 01:30:08 +0200 Subject: [PATCH] incipient position hash --- piecrust/src/store.rs | 93 ++++++++++++++++++++++++++++------- piecrust/src/store/session.rs | 1 + piecrust/src/store/tree.rs | 14 ++++++ 3 files changed, 89 insertions(+), 19 deletions(-) diff --git a/piecrust/src/store.rs b/piecrust/src/store.rs index 67a9a7a1..f58da859 100644 --- a/piecrust/src/store.rs +++ b/piecrust/src/store.rs @@ -29,7 +29,7 @@ use tree::{Hash, NewContractIndex}; use crate::store::tree::{ position_from_contract, BaseInfo, ContractIndexElement, ContractsMerkle, - PageTree, + PageTree, PosHash, }; pub use bytecode::Bytecode; pub use memory::{Memory, PAGE_SIZE}; @@ -42,6 +42,7 @@ const BYTECODE_DIR: &str = "bytecode"; const MEMORY_DIR: &str = "memory"; const LEAF_DIR: &str = "leaf"; const MERKLE_FILE: &str = "merkle"; +const POS_HASH_FILE: &str = "pos_hash"; const BASE_FILE: &str = "base"; const ELEMENT_FILE: &str = "element"; const OBJECTCODE_EXTENSION: &str = "a"; @@ -251,6 +252,16 @@ fn merkle_path_main, S: AsRef>( Ok(dir.join(MERKLE_FILE)) } +fn pos_hash_path_main, S: AsRef>( + main_dir: P, + commit_id: S, +) -> io::Result { + let commit_id = commit_id.as_ref(); + let dir = main_dir.as_ref().join(commit_id); + fs::create_dir_all(&dir)?; + Ok(dir.join(POS_HASH_FILE)) +} + fn base_path_main, S: AsRef>( main_dir: P, commit_id: S, @@ -303,11 +314,13 @@ fn commit_from_dir>( let maybe_hash = commit_id.as_ref().map(commit_id_to_hash); let contracts_merkle_path = dir.join(MERKLE_FILE); + let pos_hash_path = dir.join(POS_HASH_FILE); let leaf_dir = main_dir.join(LEAF_DIR); - let (index, contracts_merkle) = index_merkle_from_path( + let (index, contracts_merkle, pos_hash) = index_merkle_pos_hash_from_path( main_dir, contracts_merkle_path, leaf_dir, + pos_hash_path, &maybe_hash, )?; @@ -368,16 +381,24 @@ fn commit_from_dir>( index, contracts_merkle, maybe_hash, + pos_hash, }) } -fn index_merkle_from_path, P2: AsRef, P3: AsRef>( +fn index_merkle_pos_hash_from_path< + P1: AsRef, + P2: AsRef, + P3: AsRef, + P4: AsRef, +>( main_path: P1, merkle_path: P2, leaf_dir: P3, + pos_hash_path: P4, maybe_commit_id: &Option, -) -> io::Result<(NewContractIndex, ContractsMerkle)> { +) -> io::Result<(NewContractIndex, ContractsMerkle, PosHash)> { let merkle_path = merkle_path.as_ref(); + let pos_hash_path = pos_hash_path.as_ref(); let leaf_dir = leaf_dir.as_ref(); let mut index: NewContractIndex = NewContractIndex::new(); @@ -396,21 +417,19 @@ fn index_merkle_from_path, P2: AsRef, P3: AsRef>( .unwrap_or(contract_leaf_path.join(ELEMENT_FILE)); if element_path.is_file() { let element_bytes = fs::read(element_path.clone())?; - let element: ContractIndexElement = rkyv::from_bytes( - &element_bytes, - ) - .map_err(|err| { - tracing::trace!( - "deserializing element file failed {}", - err - ); - io::Error::new( - io::ErrorKind::InvalidData, - format!( + let element: ContractIndexElement = + rkyv::from_bytes(&element_bytes).map_err(|err| { + tracing::trace!( + "deserializing element file failed {}", + err + ); + io::Error::new( + io::ErrorKind::InvalidData, + format!( "Invalid element file \"{element_path:?}\": {err}" ), - ) - })?; + ) + })?; index.insert_contract_index(&contract_id, element) } } @@ -429,7 +448,22 @@ fn index_merkle_from_path, P2: AsRef, P3: AsRef>( })?; tracing::trace!("deserializing contracts merkle file finished"); - Ok((index, merkle)) + let pos_hash = if pos_hash_path.is_file() { + let pos_hash_bytes = fs::read(pos_hash_path)?; + rkyv::from_bytes(&pos_hash_bytes).map_err(|err| { + tracing::trace!("deserializing position hash file failed {}", err); + io::Error::new( + io::ErrorKind::InvalidData, + format!( + "Invalid position hash file \"{pos_hash_path:?}\": {err}" + ), + ) + })? + } else { + PosHash::new() + }; + + Ok((index, merkle, pos_hash)) } fn base_from_path>(path: P) -> io::Result { @@ -451,6 +485,7 @@ pub(crate) struct Commit { index: NewContractIndex, contracts_merkle: ContractsMerkle, maybe_hash: Option, + pos_hash: PosHash, } impl Commit { @@ -459,6 +494,7 @@ impl Commit { index: NewContractIndex::new(), contracts_merkle: ContractsMerkle::default(), maybe_hash: None, + pos_hash: PosHash::new(), } } @@ -733,10 +769,14 @@ fn write_commit>( base.as_ref().map_or(ContractsMerkle::default(), |base| { base.contracts_merkle.clone() }); + let pos_hash = base + .as_ref() + .map_or(PosHash::new(), |base| base.pos_hash.clone()); let mut commit = Commit { index, contracts_merkle, maybe_hash: base.as_ref().map_or(None, |base| base.maybe_hash), + pos_hash, }; for (contract_id, contract_data) in &commit_contracts { @@ -856,6 +896,8 @@ fn write_commit_inner, S: AsRef>( let merkle_main_path = merkle_path_main(directories.main_dir.clone(), commit_id.as_ref())?; + let pos_hash_main_path = + pos_hash_path_main(directories.main_dir.clone(), commit_id.as_ref())?; for (contract_id, element) in commit.index.iter() { if commit_contracts.contains_key(contract_id) { @@ -883,7 +925,7 @@ fn write_commit_inner, S: AsRef>( .map_err(|err| { io::Error::new( io::ErrorKind::InvalidData, - format!("Failed serializing contracts merkle file file: {err}"), + format!("Failed serializing contracts merkle file: {err}"), ) })?; tracing::trace!("serializing contracts merkle file finished"); @@ -902,6 +944,15 @@ fn write_commit_inner, S: AsRef>( })?; fs::write(base_main_path.clone(), base_info_bytes)?; + let pos_hash_bytes = + rkyv::to_bytes::<_, 128>(&commit.pos_hash).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("Failed serializing position hash file: {err}"), + ) + })?; + fs::write(pos_hash_main_path.clone(), pos_hash_bytes)?; + Ok(()) } @@ -982,6 +1033,10 @@ fn finalize_commit>( let dst_merkle_path = main_dir.join(MERKLE_FILE); fs::rename(merkle_path.clone(), dst_merkle_path.clone())?; + let pos_hash_path = commit_path.join(POS_HASH_FILE); + let dst_pos_hash_path = main_dir.join(POS_HASH_FILE); + fs::rename(pos_hash_path.clone(), dst_pos_hash_path.clone())?; + fs::remove_file(base_info_path)?; fs::remove_dir(commit_path.clone())?; diff --git a/piecrust/src/store/session.rs b/piecrust/src/store/session.rs index 21520e5f..ba7d3818 100644 --- a/piecrust/src/store/session.rs +++ b/piecrust/src/store/session.rs @@ -143,6 +143,7 @@ impl ContractSession { index: c.index.clone(), contracts_merkle: c.contracts_merkle.clone(), maybe_hash: c.maybe_hash, + pos_hash: c.pos_hash.clone(), }); mem::swap(&mut self.contracts, &mut contracts); diff --git a/piecrust/src/store/tree.rs b/piecrust/src/store/tree.rs index 1ed38588..7a532711 100644 --- a/piecrust/src/store/tree.rs +++ b/piecrust/src/store/tree.rs @@ -75,6 +75,20 @@ impl PageTree { pub type Tree = dusk_merkle::Tree; +#[derive(Debug, Clone, Archive, Deserialize, Serialize)] +#[archive_attr(derive(CheckBytes))] +pub struct PosHash { + pos_hash: BTreeMap, +} + +impl PosHash { + pub fn new() -> Self { + Self { + pos_hash: BTreeMap::new(), + } + } +} + #[derive(Debug, Clone, Archive, Deserialize, Serialize)] #[archive_attr(derive(CheckBytes))] pub struct NewContractIndex {