1#![doc = include_str!("../README.md")]
2#![allow(unexpected_cfgs)]
3pub mod constants;
6pub mod error;
7pub mod instructions;
8pub mod state;
9#[cfg(test)]
10mod tests;
11
12use anchor_lang::{prelude::*, solana_program::hash};
13pub use constants::*;
14pub use instructions::*;
15pub use state::*;
16
17declare_id!("8xAuVgAygVN2sPXJzycT7AU7c9ZUJkG357HonxdFXjyc");
18
19#[program]
20pub mod blober {
21 use super::*;
22
23 pub fn initialize(ctx: Context<Initialize>, namespace: String, trusted: Pubkey) -> Result<()> {
24 initialize_handler(ctx, namespace, trusted)
25 }
26
27 pub fn declare_blob(ctx: Context<DeclareBlob>, timestamp: u64, blob_size: u32) -> Result<()> {
28 declare_blob_handler(ctx, timestamp, blob_size)
29 }
30
31 pub fn insert_chunk(ctx: Context<InsertChunk>, idx: u16, data: Vec<u8>) -> Result<()> {
32 insert_chunk_handler(ctx, idx, data)
33 }
34
35 pub fn finalize_blob(ctx: Context<FinalizeBlob>) -> Result<()> {
36 finalize_blob_handler(ctx)
37 }
38
39 pub fn discard_blob(ctx: Context<DiscardBlob>) -> Result<()> {
40 discard_blob_handler(ctx)
41 }
42
43 pub fn close(ctx: Context<Close>) -> Result<()> {
44 close_handler(ctx)
45 }
46}
47
48pub fn hash_leaf(previous_hash: [u8; 32], chunk_index: u16, chunk_data: &[u8]) -> [u8; 32] {
50 hash::hashv(&[&previous_hash, &chunk_index.to_le_bytes(), chunk_data]).to_bytes()
51}
52
53pub fn compute_blob_digest<A: AsRef<[u8]>>(chunks: &[(u16, A)]) -> [u8; 32] {
55 chunks
56 .iter()
57 .fold(initial_hash(), |hash, (chunk_index, chunk_data)| {
58 hash_leaf(hash, *chunk_index, chunk_data.as_ref())
59 })
60}
61
62pub fn find_blob_address(
64 program_id: Pubkey,
65 payer: Pubkey,
66 blober: Pubkey,
67 timestamp: u64,
68 blob_size: usize,
69) -> Pubkey {
70 Pubkey::find_program_address(
71 &[
72 SEED,
73 payer.as_ref(),
74 blober.as_ref(),
75 timestamp.to_le_bytes().as_ref(),
76 (blob_size as u32).to_le_bytes().as_ref(),
77 ],
78 &program_id,
79 )
80 .0
81}
82
83pub fn find_blober_address(program_id: Pubkey, payer: Pubkey, namespace: &str) -> Pubkey {
85 Pubkey::find_program_address(&[SEED, payer.as_ref(), namespace.as_bytes()], &program_id).0
86}
87
88pub fn hash_blob(key: &Pubkey, data: &[u8]) -> [u8; 32] {
90 hash::hashv(&[key.as_ref(), data]).to_bytes()
91}
92
93pub fn merge_hashes(current: &[u8; 32], new: &[u8; 32]) -> [u8; 32] {
96 hash::hashv(&[current, new]).to_bytes()
97}