We should abstract away the storage layer in order to simplify work on it. Currently the storage logic is scattered across the codebase which makes it difficult to reason about and work on. We should consolidate it all into a single module / type with a more high-level API, roughly like this:
// For operations on local replica (as reader/writer)
fn locate_block(branch_id: &PublicKey, encoded_locator: &Hash) -> Result<BlockId>;
fn link_block(branch_id: &PublicKey, encoded_locator: &Hash, block_id: &BlockId) -> Result<()>;
fn read_block(block_id: &BlockId) -> Result<(BlockContent, BlockNonce)>;
fn write_block(content: BlockContent, nonce: BlockNonce) -> Result<()>;
// For syncing with other replicas
fn load_root_node(branch_id: &PublicKey) -> Result<RootNode>;
fn load_inner_nodes(parent_hash: &Hash) -> Result<InnerNodes>;
fn load_leaf_nodes(parent_hash: &Hash) -> Result<LeafNodes>;
fn save_root_node(node: RootNode) -> Result<()>;
fn save_inner_nodes(nodes: InnerNodes) -> Result<()>;
fn save_leaf_nodes(nodes: LeafNodes) -> Result<()>;
fn save_block(content: BlockContent, nonce: BlockNonce) -> Result<()> // maybe this is the same as `write_block`?
// For garbage collection
fn unlink_block(branch_id: &PublicKey, encoded_locator: &Hash);
fn remove_block(block_id: &BlockId) -> Result<()>;
fn remove_branch(branch_id: &PublicKey) -> Result<()>;
fn remove_old_snapshots(branch_id: &PublicKey) -> Result<()>;
We should abstract away the storage layer in order to simplify work on it. Currently the storage logic is scattered across the codebase which makes it difficult to reason about and work on. We should consolidate it all into a single module / type with a more high-level API, roughly like this:
We also need some kind of transaction support.