use anyhow::Result;
use chrono::Utc;
use rand_chacha::ChaCha12Rng;
use rand_core::SeedableRng;
use std::{collections::BTreeSet, sync::Arc};
use wnfs::{
common::{BlockStore, Cid, MemoryBlockStore},
nameaccumulator::NameAccumulator,
private::{
AccessKey, PrivateDirectory, PrivateNode,
forest::{
hamt::HamtForest,
proofs::{ForestProofs, ProvingHamtForest},
traits::PrivateForest,
},
},
};
use wnfs_common::Storable;
#[async_std::main]
async fn main() -> Result<()> {
let store = &MemoryBlockStore::new();
let (old_forest_cid, access_key, allowed_write_name) = alice_actions(store).await?;
let (proofs, new_forest_cid) = bob_actions(old_forest_cid, access_key, store).await?;
persistence_service_actions(
old_forest_cid,
new_forest_cid,
proofs,
allowed_write_name,
store,
)
.await
}
async fn alice_actions(store: &impl BlockStore) -> Result<(Cid, AccessKey, NameAccumulator)> {
let rng = &mut ChaCha12Rng::from_entropy();
let forest = &mut HamtForest::new_rsa_2048_rc(rng);
let root_dir = &mut PrivateDirectory::new_rc(&forest.empty_name(), Utc::now(), rng);
let access_key = root_dir.as_node().store(forest, store, rng).await?;
let cid = forest.store(store).await?;
let allowed_name = forest.get_accumulated_name(root_dir.header.get_name());
Ok((cid, access_key, allowed_name))
}
async fn bob_actions(
old_forest_cid: Cid,
root_dir_access: AccessKey,
store: &impl BlockStore,
) -> Result<(ForestProofs, Cid)> {
let hamt_forest = HamtForest::load(&old_forest_cid, store).await?;
let mut forest = ProvingHamtForest::new(Arc::new(hamt_forest));
let rng = &mut ChaCha12Rng::from_entropy();
let mut root_node = PrivateNode::load(&root_dir_access, &forest, store, None).await?;
let root_dir = root_node.as_dir_mut()?;
root_dir
.write(
&["Some".into(), "file.txt".into()],
true,
Utc::now(),
b"Hello, Alice!".to_vec(),
&mut forest,
store,
rng,
)
.await?;
root_dir.as_node().store(&mut forest, store, rng).await?;
let ProvingHamtForest { forest, proofs } = forest;
let new_forest_cid = forest.store(store).await?;
Ok((proofs, new_forest_cid))
}
async fn persistence_service_actions(
old_forest_cid: Cid,
new_forest_cid: Cid,
proofs: ForestProofs,
allowed_access: NameAccumulator,
store: &impl BlockStore,
) -> Result<()> {
let old_forest = HamtForest::load(&old_forest_cid, store).await?;
let new_forest = HamtForest::load(&new_forest_cid, store).await?;
let forest = ProvingHamtForest::from_proofs(proofs, Arc::new(new_forest));
forest
.verify_against_previous_state(&old_forest, &BTreeSet::from([allowed_access]), store)
.await
}