use crate::storage_contract::{ProofStatus, STORAGE_ACCOUNT_SPACE};
use crate::{id, rewards_pools};
use serde_derive::{Deserialize, Serialize};
use solana_sdk::hash::Hash;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signature;
use solana_sdk::system_instruction;
use solana_sdk::sysvar::{clock, rewards};
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
pub enum StorageAccountType {
Archiver,
Validator,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum StorageInstruction {
InitializeStorage {
owner: Pubkey,
account_type: StorageAccountType,
},
SubmitMiningProof {
sha_state: Hash,
segment_index: u64,
signature: Signature,
blockhash: Hash,
},
AdvertiseStorageRecentBlockhash {
hash: Hash,
segment: u64,
},
ClaimStorageReward,
ProofValidation {
segment: u64,
proofs: Vec<Vec<ProofStatus>>,
},
}
fn get_ratios() -> (u64, u64) {
static MAX_BYTES: u64 = 900;
let account_meta_size: u64 =
bincode::serialized_size(&AccountMeta::new(Pubkey::new_rand(), false)).unwrap_or(0);
let proof_size: u64 = bincode::serialized_size(&ProofStatus::default()).unwrap_or(0);
let ratio = (account_meta_size + proof_size - 1) / proof_size;
let bytes = (MAX_BYTES + ratio - 1) / ratio;
(ratio, bytes)
}
pub fn validation_account_limit(proof_mask_max: usize) -> u64 {
let (ratio, bytes) = get_ratios();
bytes / (ratio + proof_mask_max as u64)
}
pub fn proof_mask_limit() -> u64 {
let (ratio, bytes) = get_ratios();
bytes - ratio
}
pub fn create_storage_account(
from_pubkey: &Pubkey,
storage_owner: &Pubkey,
storage_pubkey: &Pubkey,
lamports: u64,
account_type: StorageAccountType,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
from_pubkey,
storage_pubkey,
lamports,
STORAGE_ACCOUNT_SPACE,
&id(),
),
Instruction::new(
id(),
&StorageInstruction::InitializeStorage {
owner: *storage_owner,
account_type,
},
vec![AccountMeta::new(*storage_pubkey, false)],
),
]
}
pub fn mining_proof(
storage_pubkey: &Pubkey,
sha_state: Hash,
segment_index: u64,
signature: Signature,
blockhash: Hash,
) -> Instruction {
let storage_instruction = StorageInstruction::SubmitMiningProof {
sha_state,
segment_index,
signature,
blockhash,
};
let account_metas = vec![
AccountMeta::new(*storage_pubkey, true),
AccountMeta::new(clock::id(), false),
];
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn advertise_recent_blockhash(
storage_pubkey: &Pubkey,
storage_hash: Hash,
segment: u64,
) -> Instruction {
let storage_instruction = StorageInstruction::AdvertiseStorageRecentBlockhash {
hash: storage_hash,
segment,
};
let account_metas = vec![
AccountMeta::new(*storage_pubkey, true),
AccountMeta::new(clock::id(), false),
];
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn proof_validation(
storage_pubkey: &Pubkey,
segment: u64,
checked_proofs: Vec<(Pubkey, Vec<ProofStatus>)>,
) -> Instruction {
let mut account_metas = vec![
AccountMeta::new(*storage_pubkey, true),
AccountMeta::new(clock::id(), false),
];
let mut proofs = vec![];
checked_proofs.into_iter().for_each(|(id, p)| {
proofs.push(p);
account_metas.push(AccountMeta::new(id, false))
});
let storage_instruction = StorageInstruction::ProofValidation { segment, proofs };
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn claim_reward(owner_pubkey: &Pubkey, storage_pubkey: &Pubkey) -> Instruction {
let storage_instruction = StorageInstruction::ClaimStorageReward;
let account_metas = vec![
AccountMeta::new(*storage_pubkey, false),
AccountMeta::new(clock::id(), false),
AccountMeta::new(rewards::id(), false),
AccountMeta::new(rewards_pools::random_id(), false),
AccountMeta::new(*owner_pubkey, false),
];
Instruction::new(id(), &storage_instruction, account_metas)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_size() {
assert_eq!(validation_account_limit(50), 1);
}
}