Remove archiver and storage program (#9992)

automerge
This commit is contained in:
Jack May
2020-05-14 18:22:47 -07:00
committed by GitHub
parent 9ef9969d29
commit eb1acaf927
117 changed files with 383 additions and 7735 deletions

View File

@ -34,7 +34,6 @@ solana-metrics = { path = "../metrics", version = "1.2.0" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.2.0" }
solana-sdk = { path = "../sdk", version = "1.2.0" }
solana-stake-program = { path = "../programs/stake", version = "1.2.0" }
solana-storage-program = { path = "../programs/storage", version = "1.2.0" }
solana-vote-program = { path = "../programs/vote", version = "1.2.0" }
tempfile = "3.1.0"
thiserror = "1.0"

View File

@ -429,10 +429,7 @@ impl Accounts {
AccountAddressFilter::Exclude => !filter_by_address.contains(&pubkey),
AccountAddressFilter::Include => filter_by_address.contains(&pubkey),
};
should_include_pubkey
&& account.lamports != 0
&& !(account.lamports == std::u64::MAX
&& account.owner == solana_storage_program::id())
should_include_pubkey && account.lamports != 0
})
.map(|(pubkey, account, _slot)| (*pubkey, account.lamports))
{

View File

@ -19,8 +19,6 @@ use crate::{
},
stakes::Stakes,
status_cache::{SlotDelta, StatusCache},
storage_utils,
storage_utils::StorageAccounts,
system_instruction_processor::{self, get_system_account_kind, SystemAccountKind},
transaction_batch::TransactionBatch,
transaction_utils::OrderedIterator,
@ -37,8 +35,8 @@ use solana_metrics::{
use solana_sdk::{
account::Account,
clock::{
get_segment_from_slot, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp,
DEFAULT_TICKS_PER_SECOND, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
},
epoch_schedule::EpochSchedule,
fee_calculator::{FeeCalculator, FeeRateGovernor},
@ -237,6 +235,13 @@ impl HashAgeKind {
}
}
#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize)]
struct UnusedAccounts {
unused1: HashSet<Pubkey>,
unused2: HashSet<Pubkey>,
unused3: HashMap<Pubkey, u64>,
}
/// Manager for the state of all accounts and programs after processing its entries.
#[derive(Default, Deserialize, Serialize)]
pub struct Bank {
@ -303,8 +308,8 @@ pub struct Bank {
/// The number of slots per year, used for inflation
slots_per_year: f64,
/// The number of slots per Storage segment
slots_per_segment: u64,
/// Unused
unused: u64,
/// Bank slot (i.e. block)
slot: Slot,
@ -346,8 +351,8 @@ pub struct Bank {
/// cache of vote_account and stake_account state for this fork
stakes: RwLock<Stakes>,
/// cache of validator and archiver storage accounts for this fork
storage_accounts: RwLock<StorageAccounts>,
/// unused
unused_accounts: RwLock<UnusedAccounts>,
/// staked nodes on epoch boundaries, saved off when a bank.slot() is at
/// a leader schedule calculation boundary
@ -466,7 +471,7 @@ impl Bank {
ticks_per_slot: parent.ticks_per_slot,
ns_per_slot: parent.ns_per_slot,
genesis_creation_time: parent.genesis_creation_time,
slots_per_segment: parent.slots_per_segment,
unused: parent.unused,
slots_per_year: parent.slots_per_year,
epoch_schedule,
collected_rent: AtomicU64::new(0),
@ -480,7 +485,7 @@ impl Bank {
transaction_count: AtomicU64::new(parent.transaction_count()),
stakes: RwLock::new(parent.stakes.read().unwrap().clone_with_epoch(epoch)),
epoch_stakes: parent.epoch_stakes.clone(),
storage_accounts: RwLock::new(parent.storage_accounts.read().unwrap().clone()),
unused_accounts: RwLock::new(parent.unused_accounts.read().unwrap().clone()),
parent_hash: parent.hash(),
parent_slot: parent.slot(),
collector_id: *collector_id,
@ -595,7 +600,7 @@ impl Bank {
pub fn clock(&self) -> sysvar::clock::Clock {
sysvar::clock::Clock {
slot: self.slot,
segment: get_segment_from_slot(self.slot, self.slots_per_segment),
unused: 0,
epoch: self.epoch_schedule.get_epoch(self.slot),
leader_schedule_epoch: self.epoch_schedule.get_leader_schedule_epoch(self.slot),
unix_timestamp: self.unix_timestamp(),
@ -716,35 +721,26 @@ impl Bank {
// years_elapsed = slots_elapsed / slots/year
let period = self.epoch_schedule.get_slots_in_epoch(epoch) as f64 / self.slots_per_year;
let (validator_rewards, storage_rewards) = {
let validator_rewards = {
let inflation = self.inflation.read().unwrap();
(
(*inflation).validator(year) * self.capitalization() as f64 * period,
(*inflation).storage(year) * self.capitalization() as f64 * period,
)
(*inflation).validator(year) * self.capitalization() as f64 * period
};
let validator_points = self.stakes.write().unwrap().claim_points();
let storage_points = self.storage_accounts.write().unwrap().claim_points();
let (validator_point_value, storage_point_value) = self.check_point_values(
validator_rewards / validator_points as f64,
storage_rewards / storage_points as f64,
);
let validator_point_value =
self.check_point_value(validator_rewards / validator_points as f64);
self.update_sysvar_account(&sysvar::rewards::id(), |account| {
sysvar::rewards::create_account(
self.inherit_sysvar_account_balance(account),
validator_point_value,
storage_point_value,
)
});
let validator_rewards = self.pay_validator_rewards(validator_point_value);
self.capitalization.fetch_add(
validator_rewards + storage_rewards as u64,
Ordering::Relaxed,
);
self.capitalization
.fetch_add(validator_rewards as u64, Ordering::Relaxed);
}
/// iterate over all stakes, redeem vote credits for each stake we can
@ -815,24 +811,17 @@ impl Bank {
// If the point values are not `normal`, bring them back into range and
// set them to the last value or 0.
fn check_point_values(
&self,
mut validator_point_value: f64,
mut storage_point_value: f64,
) -> (f64, f64) {
fn check_point_value(&self, mut validator_point_value: f64) -> f64 {
let rewards = sysvar::rewards::Rewards::from_account(
&self
.get_account(&sysvar::rewards::id())
.unwrap_or_else(|| sysvar::rewards::create_account(1, 0.0, 0.0)),
.unwrap_or_else(|| sysvar::rewards::create_account(1, 0.0)),
)
.unwrap_or_else(Default::default);
if !validator_point_value.is_normal() {
validator_point_value = rewards.validator_point_value;
}
if !storage_point_value.is_normal() {
storage_point_value = rewards.storage_point_value
}
(validator_point_value, storage_point_value)
validator_point_value
}
fn collect_fees(&self) {
@ -945,7 +934,7 @@ impl Bank {
self.ns_per_slot = genesis_config.poh_config.target_tick_duration.as_nanos()
* genesis_config.ticks_per_slot as u128;
self.genesis_creation_time = genesis_config.creation_time;
self.slots_per_segment = genesis_config.slots_per_segment;
self.unused = genesis_config.unused;
self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
self.slots_per_year = years_as_slots(
1.0,
@ -2063,11 +2052,6 @@ impl Bank {
if Stakes::is_stake(account) {
self.stakes.write().unwrap().store(pubkey, account);
} else if storage_utils::is_storage(account) {
self.storage_accounts
.write()
.unwrap()
.store(pubkey, account);
}
}
@ -2369,11 +2353,6 @@ impl Bank {
self.slots_per_year
}
/// Return the number of slots per segment
pub fn slots_per_segment(&self) -> u64 {
self.slots_per_segment
}
/// Return the number of ticks since genesis.
pub fn tick_height(&self) -> u64 {
self.tick_height.load(Ordering::Relaxed)
@ -2384,7 +2363,7 @@ impl Bank {
*self.inflation.read().unwrap()
}
/// Return the total capititalization of the Bank
/// Return the total capitalization of the Bank
pub fn capitalization(&self) -> u64 {
self.capitalization.load(Ordering::Relaxed)
}
@ -2431,31 +2410,19 @@ impl Bank {
let message = &tx.message();
let acc = raccs.as_ref().unwrap();
for (pubkey, account) in
message
.account_keys
.iter()
.zip(acc.0.iter())
.filter(|(_key, account)| {
(Stakes::is_stake(account)) || storage_utils::is_storage(account)
})
for (pubkey, account) in message
.account_keys
.iter()
.zip(acc.0.iter())
.filter(|(_key, account)| (Stakes::is_stake(account)))
{
if Stakes::is_stake(account) {
self.stakes.write().unwrap().store(pubkey, account);
} else if storage_utils::is_storage(account) {
self.storage_accounts
.write()
.unwrap()
.store(pubkey, account);
}
}
}
}
pub fn storage_accounts(&self) -> StorageAccounts {
self.storage_accounts.read().unwrap().clone()
}
/// current stake delegations for this bank
/// Note: this method is exposed publicly for external usage
pub fn stake_delegations(&self) -> HashMap<Pubkey, Delegation> {
@ -2833,35 +2800,6 @@ mod tests {
assert_eq!(bank1.capitalization(), 42 * 42);
}
#[test]
fn test_bank_inflation() {
let key = Pubkey::default();
let bank = Arc::new(Bank::new(&GenesisConfig {
accounts: (0..42)
.into_iter()
.map(|_| (Pubkey::new_rand(), Account::new(42, 0, &key)))
.collect(),
..GenesisConfig::default()
}));
assert_eq!(bank.capitalization(), 42 * 42);
// With inflation
bank.set_entered_epoch_callback(Box::new(move |bank: &mut Bank| {
let mut inflation = Inflation::default();
inflation.initial = 1_000_000.0;
bank.set_inflation(inflation)
}));
let bank1 = Bank::new_from_parent(&bank, &key, MINIMUM_SLOTS_PER_EPOCH + 1);
assert_ne!(bank.capitalization(), bank1.capitalization());
// Without inflation
bank.set_entered_epoch_callback(Box::new(move |bank: &mut Bank| {
bank.set_inflation(Inflation::new_disabled())
}));
let bank2 = Bank::new_from_parent(&bank, &key, MINIMUM_SLOTS_PER_EPOCH * 2 + 1);
assert_eq!(bank.capitalization(), bank2.capitalization());
}
#[test]
fn test_credit_debit_rent_no_side_effect_on_hash() {
let (mut genesis_config, _mint_keypair) = create_genesis_config(10);
@ -4158,13 +4096,8 @@ mod tests {
let ((vote_id, mut vote_account), (stake_id, stake_account)) =
crate::stakes::tests::create_staked_node_accounts(1_0000);
let ((validator_id, validator_account), (archiver_id, archiver_account)) =
crate::storage_utils::tests::create_storage_accounts_with_credits(100);
// set up stakes, vote, and storage accounts
// set up accounts
bank.store_account(&stake_id, &stake_account);
bank.store_account(&validator_id, &validator_account);
bank.store_account(&archiver_id, &archiver_account);
// generate some rewards
let mut vote_state = Some(VoteState::from(&vote_account).unwrap());
@ -4185,7 +4118,6 @@ mod tests {
bank.store_account(&vote_id, &vote_account);
let validator_points = bank.stakes.read().unwrap().points();
let storage_points = bank.storage_accounts.read().unwrap().points();
// put a child bank in epoch 1, which calls update_rewards()...
let bank1 = Bank::new_from_parent(
@ -4215,15 +4147,11 @@ mod tests {
// verify the rewards are the right size
assert!(
((rewards.validator_point_value * validator_points as f64
+ rewards.storage_point_value * storage_points as f64)
- inflation as f64)
.abs()
((rewards.validator_point_value * validator_points as f64) - inflation as f64).abs()
< 1.0 // rounding, truncating
);
// verify validator rewards show up in bank1.rewards vector
// (currently storage rewards will not show up)
assert_eq!(
bank1.rewards,
Some(vec![(
@ -5900,25 +5828,19 @@ mod tests {
}
#[test]
fn test_check_point_values() {
fn test_check_point_value() {
let (genesis_config, _) = create_genesis_config(500);
let bank = Arc::new(Bank::new(&genesis_config));
// check that point values are 0 if no previous value was known and current values are not normal
assert_eq!(
bank.check_point_values(std::f64::INFINITY, std::f64::NAN),
(0.0, 0.0)
);
assert_eq!(bank.check_point_value(std::f64::INFINITY), 0.0);
bank.store_account(
&sysvar::rewards::id(),
&sysvar::rewards::create_account(1, 1.0, 1.0),
&sysvar::rewards::create_account(1, 1.0),
);
// check that point values are the previous value if current values are not normal
assert_eq!(
bank.check_point_values(std::f64::INFINITY, std::f64::NAN),
(1.0, 1.0)
);
assert_eq!(bank.check_point_value(std::f64::INFINITY), 1.0);
}
#[test]

View File

@ -150,7 +150,6 @@ pub fn create_genesis_config_with_leader_ex(
};
solana_stake_program::add_genesis_accounts(&mut genesis_config);
solana_storage_program::rewards_pools::add_genesis_accounts(&mut genesis_config);
GenesisConfigInfo {
genesis_config,

View File

@ -16,7 +16,6 @@ pub mod rent_collector;
mod serde_utils;
pub mod stakes;
pub mod status_cache;
pub mod storage_utils;
mod system_instruction_processor;
pub mod transaction_batch;
pub mod transaction_utils;

View File

@ -1,248 +0,0 @@
use crate::bank::Bank;
use solana_sdk::{account::Account, account_utils::StateMut, pubkey::Pubkey};
use solana_storage_program::storage_contract::StorageContract;
use std::collections::{HashMap, HashSet};
#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct StorageAccounts {
/// validator storage accounts and their credits
validator_accounts: HashSet<Pubkey>,
/// archiver storage accounts and their credits
archiver_accounts: HashSet<Pubkey>,
/// unclaimed points.
// 1 point == 1 storage account credit
points: HashMap<Pubkey, u64>,
}
pub fn is_storage(account: &Account) -> bool {
solana_storage_program::check_id(&account.owner)
}
impl StorageAccounts {
pub fn store(&mut self, pubkey: &Pubkey, account: &Account) {
if let Ok(storage_state) = account.state() {
if let StorageContract::ArchiverStorage { credits, .. } = storage_state {
if account.lamports == 0 {
self.archiver_accounts.remove(pubkey);
} else {
self.archiver_accounts.insert(*pubkey);
self.points.insert(*pubkey, credits.current_epoch);
}
} else if let StorageContract::ValidatorStorage { credits, .. } = storage_state {
if account.lamports == 0 {
self.validator_accounts.remove(pubkey);
} else {
self.validator_accounts.insert(*pubkey);
self.points.insert(*pubkey, credits.current_epoch);
}
}
};
}
/// currently unclaimed points
pub fn points(&self) -> u64 {
self.points.values().sum()
}
/// "claims" points, resets points to 0
pub fn claim_points(&mut self) -> u64 {
let points = self.points();
self.points.clear();
points
}
}
pub fn validator_accounts(bank: &Bank) -> HashMap<Pubkey, Account> {
bank.storage_accounts()
.validator_accounts
.iter()
.filter_map(|account_id| {
bank.get_account(account_id)
.map(|account| (*account_id, account))
})
.collect()
}
pub fn archiver_accounts(bank: &Bank) -> HashMap<Pubkey, Account> {
bank.storage_accounts()
.archiver_accounts
.iter()
.filter_map(|account_id| {
bank.get_account(account_id)
.map(|account| (*account_id, account))
})
.collect()
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::bank_client::BankClient;
use solana_sdk::{
client::SyncClient,
genesis_config::create_genesis_config,
message::Message,
signature::{Keypair, Signer},
};
use solana_storage_program::{
storage_contract::{StorageAccount, STORAGE_ACCOUNT_SPACE},
storage_instruction::{self, StorageAccountType},
storage_processor,
};
use std::{rc::Rc, sync::Arc};
#[test]
fn test_store_and_recover() {
let (mut genesis_config, mint_keypair) = create_genesis_config(1000);
genesis_config.rent.lamports_per_byte_year = 0;
let mint_pubkey = mint_keypair.pubkey();
let archiver_keypair = Keypair::new();
let archiver_pubkey = archiver_keypair.pubkey();
let validator_keypair = Keypair::new();
let validator_pubkey = validator_keypair.pubkey();
let mut bank = Bank::new(&genesis_config);
bank.add_static_program(
"storage_program",
solana_storage_program::id(),
storage_processor::process_instruction,
);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&archiver_pubkey,
11,
StorageAccountType::Archiver,
));
bank_client
.send_message(&[&mint_keypair, &archiver_keypair], message)
.unwrap();
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&validator_pubkey,
11,
StorageAccountType::Validator,
));
bank_client
.send_message(&[&mint_keypair, &validator_keypair], message)
.unwrap();
assert_eq!(validator_accounts(bank.as_ref()).len(), 1);
assert_eq!(archiver_accounts(bank.as_ref()).len(), 1);
}
#[test]
fn test_points() {
// note: storage_points == storage_credits
let credits = 42;
let mut storage_accounts = StorageAccounts::default();
assert_eq!(storage_accounts.points(), 0);
assert_eq!(storage_accounts.claim_points(), 0);
// create random validator and archiver accounts with `credits`
let ((validator_pubkey, validator_account), (archiver_pubkey, archiver_account)) =
create_storage_accounts_with_credits(credits);
storage_accounts.store(&validator_pubkey, &validator_account);
storage_accounts.store(&archiver_pubkey, &archiver_account);
// check that 2x credits worth of points are available
assert_eq!(storage_accounts.points(), credits * 2);
let ((validator_pubkey, validator_account), (archiver_pubkey, mut archiver_account)) =
create_storage_accounts_with_credits(credits);
storage_accounts.store(&validator_pubkey, &validator_account);
storage_accounts.store(&archiver_pubkey, &archiver_account);
// check that 4x credits worth of points are available
assert_eq!(storage_accounts.points(), credits * 2 * 2);
storage_accounts.store(&validator_pubkey, &validator_account);
storage_accounts.store(&archiver_pubkey, &archiver_account);
// check that storing again has no effect
assert_eq!(storage_accounts.points(), credits * 2 * 2);
let storage_contract = &mut archiver_account.state().unwrap();
if let StorageContract::ArchiverStorage {
credits: account_credits,
..
} = storage_contract
{
account_credits.current_epoch += 1;
}
archiver_account.set_state(storage_contract).unwrap();
storage_accounts.store(&archiver_pubkey, &archiver_account);
// check that incremental store increases credits
assert_eq!(storage_accounts.points(), credits * 2 * 2 + 1);
assert_eq!(storage_accounts.claim_points(), credits * 2 * 2 + 1);
// check that once redeemed, the points are gone
assert_eq!(storage_accounts.claim_points(), 0);
}
pub fn create_storage_accounts_with_credits(
credits: u64,
) -> ((Pubkey, Account), (Pubkey, Account)) {
let validator_pubkey = Pubkey::new_rand();
let archiver_pubkey = Pubkey::new_rand();
let validator_account = Account::new_ref(
1,
STORAGE_ACCOUNT_SPACE as usize,
&solana_storage_program::id(),
);
let archiver_account = Account::new_ref(
1,
STORAGE_ACCOUNT_SPACE as usize,
&solana_storage_program::id(),
);
{
StorageAccount::new(validator_pubkey, &mut validator_account.borrow_mut())
.initialize_storage(validator_pubkey, StorageAccountType::Validator)
.unwrap();
let storage_contract = &mut validator_account.borrow().state().unwrap();
if let StorageContract::ValidatorStorage {
credits: account_credits,
..
} = storage_contract
{
account_credits.current_epoch = credits;
}
validator_account
.borrow_mut()
.set_state(storage_contract)
.unwrap();
StorageAccount::new(archiver_pubkey, &mut archiver_account.borrow_mut())
.initialize_storage(archiver_pubkey, StorageAccountType::Archiver)
.unwrap();
let storage_contract = &mut archiver_account.borrow().state().unwrap();
if let StorageContract::ArchiverStorage {
credits: account_credits,
..
} = storage_contract
{
account_credits.current_epoch = credits;
}
archiver_account
.borrow_mut()
.set_state(storage_contract)
.unwrap();
}
(
(
validator_pubkey,
Rc::try_unwrap(validator_account).unwrap().into_inner(),
),
(
archiver_pubkey,
Rc::try_unwrap(archiver_account).unwrap().into_inner(),
),
)
}
}

View File

@ -1,482 +0,0 @@
use assert_matches::assert_matches;
use bincode::deserialize;
use log::*;
use solana_runtime::{
bank::Bank,
bank_client::BankClient,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
};
use solana_sdk::{
account_utils::StateMut,
client::SyncClient,
clock::{get_segment_from_slot, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
hash::{hash, Hash},
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
system_instruction,
sysvar::{
rewards::{self, Rewards},
Sysvar,
},
};
use solana_storage_program::{
id,
storage_contract::{ProofStatus, StorageContract},
storage_instruction::{self, StorageAccountType},
storage_processor::process_instruction,
};
use std::{collections::HashMap, sync::Arc};
const TICKS_IN_SEGMENT: u64 = DEFAULT_SLOTS_PER_SEGMENT * DEFAULT_TICKS_PER_SLOT;
#[test]
fn test_account_owner() {
let account_owner = Pubkey::new_rand();
let validator_storage_keypair = Keypair::new();
let validator_storage_pubkey = validator_storage_keypair.pubkey();
let archiver_storage_keypair = Keypair::new();
let archiver_storage_pubkey = archiver_storage_keypair.pubkey();
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(1000);
let mut bank = Bank::new(&genesis_config);
let mint_pubkey = mint_keypair.pubkey();
bank.add_static_program("storage_program", id(), process_instruction);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&account_owner,
&validator_storage_pubkey,
1,
StorageAccountType::Validator,
));
bank_client
.send_message(&[&mint_keypair, &validator_storage_keypair], message)
.expect("failed to create account");
let account = bank
.get_account(&validator_storage_pubkey)
.expect("account not found");
let storage_contract = account.state().expect("couldn't unpack account data");
if let StorageContract::ValidatorStorage { owner, .. } = storage_contract {
assert_eq!(owner, account_owner);
} else {
assert!(false, "wrong account type found")
}
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&account_owner,
&archiver_storage_pubkey,
1,
StorageAccountType::Archiver,
));
bank_client
.send_message(&[&mint_keypair, &archiver_storage_keypair], message)
.expect("failed to create account");
let account = bank
.get_account(&archiver_storage_pubkey)
.expect("account not found");
let storage_contract = account.state().expect("couldn't unpack account data");
if let StorageContract::ArchiverStorage { owner, .. } = storage_contract {
assert_eq!(owner, account_owner);
} else {
assert!(false, "wrong account type found")
}
}
#[test]
fn test_validate_mining() {
solana_logger::setup();
let GenesisConfigInfo {
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(100_000_000_000);
genesis_config
.native_instruction_processors
.push(solana_storage_program::solana_storage_program!());
let mint_pubkey = mint_keypair.pubkey();
// 1 owner for all archiver and validator accounts for the test
let owner_pubkey = Pubkey::new_rand();
let archiver_1_storage_keypair = Keypair::new();
let archiver_1_storage_id = archiver_1_storage_keypair.pubkey();
let archiver_2_storage_keypair = Keypair::new();
let archiver_2_storage_id = archiver_2_storage_keypair.pubkey();
let validator_storage_keypair = Keypair::new();
let validator_storage_id = validator_storage_keypair.pubkey();
let bank = Bank::new(&genesis_config);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
init_storage_accounts(
&owner_pubkey,
&bank_client,
&mint_keypair,
&[&validator_storage_keypair],
&[&archiver_1_storage_keypair, &archiver_2_storage_keypair],
10,
);
// create a new bank in segment 2
let bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
DEFAULT_SLOTS_PER_SEGMENT * 2,
));
let bank_client = BankClient::new_shared(&bank);
// advertise for storage segment 1
let message = Message::new_with_payer(
&[storage_instruction::advertise_recent_blockhash(
&validator_storage_id,
Hash::default(),
1,
)],
Some(&mint_pubkey),
);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
Ok(_)
);
// submit proofs 5 proofs for each archiver for segment 0
let mut checked_proofs: HashMap<_, Vec<_>> = HashMap::new();
for _ in 0..5 {
checked_proofs
.entry(archiver_1_storage_id)
.or_default()
.push(submit_proof(
&mint_keypair,
&archiver_1_storage_keypair,
&bank_client,
0,
));
checked_proofs
.entry(archiver_2_storage_id)
.or_default()
.push(submit_proof(
&mint_keypair,
&archiver_2_storage_keypair,
&bank_client,
0,
));
}
let message = Message::new_with_payer(
&[storage_instruction::advertise_recent_blockhash(
&validator_storage_id,
Hash::default(),
2,
)],
Some(&mint_pubkey),
);
// move banks into the next segment
let proof_segment = get_segment_from_slot(bank.slot(), bank.slots_per_segment());
let bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
));
let bank_client = BankClient::new_shared(&bank);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
Ok(_)
);
let message = Message::new_with_payer(
&[storage_instruction::proof_validation(
&validator_storage_id,
proof_segment as u64,
checked_proofs.into_iter().map(|entry| entry).collect(),
)],
Some(&mint_pubkey),
);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
Ok(_)
);
let message = Message::new_with_payer(
&[storage_instruction::advertise_recent_blockhash(
&validator_storage_id,
Hash::default(),
3,
)],
Some(&mint_pubkey),
);
// move banks into the next segment
let bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
));
let bank_client = BankClient::new_shared(&bank);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
Ok(_)
);
assert_eq!(bank_client.get_balance(&validator_storage_id).unwrap(), 10);
let bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
bank.slot() + bank.epoch_schedule().slots_per_epoch,
));
let bank_client = BankClient::new_shared(&bank);
let rewards = bank
.get_account(&rewards::id())
.map(|account| Rewards::from_account(&account).unwrap())
.unwrap();
let message = Message::new_with_payer(
&[storage_instruction::claim_reward(
&owner_pubkey,
&validator_storage_id,
)],
Some(&mint_pubkey),
);
assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
assert_eq!(
bank_client.get_balance(&owner_pubkey).unwrap(),
1 + ((rewards.storage_point_value * 10_f64) as u64)
);
// tick the bank into the next storage epoch so that rewards can be claimed
for _ in 0..=TICKS_IN_SEGMENT {
bank.register_tick(&bank.last_blockhash());
}
assert_eq!(bank_client.get_balance(&archiver_1_storage_id).unwrap(), 10);
let message = Message::new_with_payer(
&[storage_instruction::claim_reward(
&owner_pubkey,
&archiver_1_storage_id,
)],
Some(&mint_pubkey),
);
assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
assert_eq!(
bank_client.get_balance(&owner_pubkey).unwrap(),
1 + ((rewards.storage_point_value * 10_f64) as u64)
+ (rewards.storage_point_value * 5_f64) as u64
);
let message = Message::new_with_payer(
&[storage_instruction::claim_reward(
&owner_pubkey,
&archiver_2_storage_id,
)],
Some(&mint_pubkey),
);
assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
assert_eq!(
bank_client.get_balance(&owner_pubkey).unwrap(),
1 + (rewards.storage_point_value * 10_f64) as u64
+ (rewards.storage_point_value * 5_f64) as u64
+ (rewards.storage_point_value * 5_f64) as u64
);
}
fn init_storage_accounts(
owner: &Pubkey,
client: &BankClient,
mint: &Keypair,
validator_accounts_to_create: &[&Keypair],
archiver_accounts_to_create: &[&Keypair],
lamports: u64,
) {
let mut signers = vec![mint];
let mut ixs: Vec<_> = vec![system_instruction::transfer(&mint.pubkey(), owner, 1)];
ixs.append(
&mut validator_accounts_to_create
.into_iter()
.flat_map(|account| {
signers.push(&account);
storage_instruction::create_storage_account(
&mint.pubkey(),
owner,
&account.pubkey(),
lamports,
StorageAccountType::Validator,
)
})
.collect(),
);
archiver_accounts_to_create.into_iter().for_each(|account| {
signers.push(&account);
ixs.append(&mut storage_instruction::create_storage_account(
&mint.pubkey(),
owner,
&account.pubkey(),
lamports,
StorageAccountType::Archiver,
))
});
let message = Message::new(&ixs);
client.send_message(&signers, message).unwrap();
}
fn get_storage_segment<C: SyncClient>(client: &C, account: &Pubkey) -> u64 {
match client.get_account_data(&account).unwrap() {
Some(storage_system_account_data) => {
let contract = deserialize(&storage_system_account_data);
if let Ok(contract) = contract {
match contract {
StorageContract::ValidatorStorage { segment, .. } => {
return segment;
}
_ => info!("error in reading segment"),
}
}
}
None => {
info!("error in reading segment");
}
}
0
}
fn submit_proof(
mint_keypair: &Keypair,
storage_keypair: &Keypair,
bank_client: &BankClient,
segment_index: u64,
) -> ProofStatus {
let sha_state = Hash::new(Pubkey::new_rand().as_ref());
let message = Message::new_with_payer(
&[storage_instruction::mining_proof(
&storage_keypair.pubkey(),
sha_state,
segment_index,
Signature::default(),
bank_client.get_recent_blockhash().unwrap().0,
)],
Some(&mint_keypair.pubkey()),
);
assert_matches!(
bank_client.send_message(&[mint_keypair, storage_keypair], message),
Ok(_)
);
ProofStatus::Valid
}
fn get_storage_blockhash<C: SyncClient>(client: &C, account: &Pubkey) -> Hash {
if let Some(storage_system_account_data) = client.get_account_data(&account).unwrap() {
let contract = deserialize(&storage_system_account_data);
if let Ok(contract) = contract {
match contract {
StorageContract::ValidatorStorage { hash, .. } => {
return hash;
}
_ => (),
}
}
}
Hash::default()
}
#[test]
fn test_bank_storage() {
let GenesisConfigInfo {
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(1000);
genesis_config
.native_instruction_processors
.push(solana_storage_program::solana_storage_program!());
let mint_pubkey = mint_keypair.pubkey();
let archiver_keypair = Keypair::new();
let archiver_pubkey = archiver_keypair.pubkey();
let validator_keypair = Keypair::new();
let validator_pubkey = validator_keypair.pubkey();
let bank = Bank::new(&genesis_config);
// tick the bank up until it's moved into storage segment 2
// create a new bank in storage segment 2
let bank = Bank::new_from_parent(
&Arc::new(bank),
&Pubkey::new_rand(),
DEFAULT_SLOTS_PER_SEGMENT * 2,
);
let bank_client = BankClient::new(bank);
let x = 42;
let x2 = x * 2;
let storage_blockhash = hash(&[x2]);
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&archiver_pubkey,
11,
StorageAccountType::Archiver,
));
bank_client
.send_message(&[&mint_keypair, &archiver_keypair], message)
.unwrap();
let message = Message::new(&storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&validator_pubkey,
1,
StorageAccountType::Validator,
));
bank_client
.send_message(&[&mint_keypair, &validator_keypair], message)
.unwrap();
let message = Message::new_with_payer(
&[storage_instruction::advertise_recent_blockhash(
&validator_pubkey,
storage_blockhash,
1,
)],
Some(&mint_pubkey),
);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &validator_keypair], message),
Ok(_)
);
let slot = 0;
let message = Message::new_with_payer(
&[storage_instruction::mining_proof(
&archiver_pubkey,
Hash::default(),
slot,
Signature::default(),
bank_client.get_recent_blockhash().unwrap().0,
)],
Some(&mint_pubkey),
);
assert_matches!(
bank_client.send_message(&[&mint_keypair, &archiver_keypair], message),
Ok(_)
);
assert_eq!(get_storage_segment(&bank_client, &validator_pubkey), 1);
assert_eq!(
get_storage_blockhash(&bank_client, &validator_pubkey),
storage_blockhash
);
}