@ -194,7 +194,7 @@ mod tests {
|
||||
.iter()
|
||||
.map(|meta| {
|
||||
if syscall::current::check_id(&meta.pubkey) {
|
||||
syscall::current::create_account(1, 0, 0, 0)
|
||||
syscall::current::create_account(1, 0, 0, 0, 0)
|
||||
} else if syscall::rewards::check_id(&meta.pubkey) {
|
||||
syscall::rewards::create_account(1, 0.0, 0.0)
|
||||
} else {
|
||||
@ -288,7 +288,7 @@ mod tests {
|
||||
KeyedAccount::new(
|
||||
&syscall::current::id(),
|
||||
false,
|
||||
&mut syscall::current::create_account(1, 0, 0, 0)
|
||||
&mut syscall::current::create_account(1, 0, 0, 0, 0)
|
||||
),
|
||||
],
|
||||
&serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
|
||||
|
@ -3,12 +3,6 @@ pub mod storage_contract;
|
||||
pub mod storage_instruction;
|
||||
pub mod storage_processor;
|
||||
|
||||
pub const SLOTS_PER_SEGMENT: u64 = 16;
|
||||
|
||||
pub fn get_segment_from_slot(slot: u64) -> usize {
|
||||
((slot + (SLOTS_PER_SEGMENT - 1)) / SLOTS_PER_SEGMENT) as usize
|
||||
}
|
||||
|
||||
const STORAGE_PROGRAM_ID: [u8; 32] = [
|
||||
6, 162, 25, 123, 127, 68, 233, 59, 131, 151, 21, 152, 162, 120, 90, 37, 154, 88, 86, 5, 156,
|
||||
221, 182, 201, 142, 103, 151, 112, 0, 0, 0, 0,
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::get_segment_from_slot;
|
||||
use log::*;
|
||||
use num_derive::FromPrimitive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@ -68,8 +67,8 @@ pub struct Proof {
|
||||
pub blockhash: Hash,
|
||||
/// The resulting sampled state
|
||||
pub sha_state: Hash,
|
||||
/// The start index of the segment proof is for
|
||||
pub segment_index: usize,
|
||||
/// The segment this proof is for
|
||||
pub segment_index: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -78,13 +77,13 @@ pub enum StorageContract {
|
||||
|
||||
ValidatorStorage {
|
||||
owner: Pubkey,
|
||||
// Most recently advertised slot
|
||||
slot: u64,
|
||||
// Most recently advertised segment
|
||||
segment: u64,
|
||||
// Most recently advertised blockhash
|
||||
hash: Hash,
|
||||
// Lockouts and Rewards are per segment per replicator. It needs to remain this way until
|
||||
// the challenge stage is added.
|
||||
lockout_validations: BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
lockout_validations: BTreeMap<u64, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
// Used to keep track of ongoing credits
|
||||
credits: Credits,
|
||||
},
|
||||
@ -93,10 +92,10 @@ pub enum StorageContract {
|
||||
owner: Pubkey,
|
||||
// TODO what to do about duplicate proofs across segments? - Check the blockhashes
|
||||
// Map of Proofs per segment, in a Vec
|
||||
proofs: BTreeMap<usize, Vec<Proof>>,
|
||||
proofs: BTreeMap<u64, Vec<Proof>>,
|
||||
// Map of Rewards per segment, in a BTreeMap based on the validator account that verified
|
||||
// the proof. This can be used for challenge stage when its added
|
||||
validations: BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
validations: BTreeMap<u64, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
// Used to keep track of ongoing credits
|
||||
credits: Credits,
|
||||
},
|
||||
@ -111,7 +110,7 @@ pub fn create_validator_storage_account(owner: Pubkey, lamports: u64) -> Account
|
||||
storage_account
|
||||
.set_state(&StorageContract::ValidatorStorage {
|
||||
owner,
|
||||
slot: 0,
|
||||
segment: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: BTreeMap::new(),
|
||||
credits: Credits::default(),
|
||||
@ -151,7 +150,7 @@ impl<'a> StorageAccount<'a> {
|
||||
if let StorageContract::Uninitialized = storage_contract {
|
||||
*storage_contract = StorageContract::ValidatorStorage {
|
||||
owner,
|
||||
slot: 0,
|
||||
segment: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: BTreeMap::new(),
|
||||
credits: Credits::default(),
|
||||
@ -165,7 +164,7 @@ impl<'a> StorageAccount<'a> {
|
||||
pub fn submit_mining_proof(
|
||||
&mut self,
|
||||
sha_state: Hash,
|
||||
segment_index: usize,
|
||||
segment_index: u64,
|
||||
signature: Signature,
|
||||
blockhash: Hash,
|
||||
current: syscall::current::Current,
|
||||
@ -178,7 +177,7 @@ impl<'a> StorageAccount<'a> {
|
||||
..
|
||||
} = &mut storage_contract
|
||||
{
|
||||
let current_segment = get_segment_from_slot(current.slot);
|
||||
let current_segment = current.segment;
|
||||
|
||||
// clean up the account
|
||||
// TODO check for time correctness - storage seems to run at a delay of about 3
|
||||
@ -242,32 +241,29 @@ impl<'a> StorageAccount<'a> {
|
||||
pub fn advertise_storage_recent_blockhash(
|
||||
&mut self,
|
||||
hash: Hash,
|
||||
slot: u64,
|
||||
segment: u64,
|
||||
current: syscall::current::Current,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::ValidatorStorage {
|
||||
slot: state_slot,
|
||||
segment: state_segment,
|
||||
hash: state_hash,
|
||||
lockout_validations,
|
||||
credits,
|
||||
..
|
||||
} = &mut storage_contract
|
||||
{
|
||||
let current_segment = get_segment_from_slot(current.slot);
|
||||
let original_segment = get_segment_from_slot(*state_slot);
|
||||
let segment = get_segment_from_slot(slot);
|
||||
debug!(
|
||||
"advertise new segment: {} orig: {}",
|
||||
segment, current_segment
|
||||
segment, current.segment
|
||||
);
|
||||
if segment < original_segment || segment >= current_segment {
|
||||
if segment < *state_segment || segment > current.segment {
|
||||
return Err(InstructionError::CustomError(
|
||||
StorageError::InvalidSegment as u32,
|
||||
));
|
||||
}
|
||||
|
||||
*state_slot = slot;
|
||||
*state_segment = segment;
|
||||
*state_hash = hash;
|
||||
|
||||
// storage epoch updated, move the lockout_validations to credits
|
||||
@ -285,21 +281,18 @@ impl<'a> StorageAccount<'a> {
|
||||
&mut self,
|
||||
me: &Pubkey,
|
||||
current: syscall::current::Current,
|
||||
segment: u64,
|
||||
segment_index: u64,
|
||||
proofs_per_account: Vec<Vec<ProofStatus>>,
|
||||
replicator_accounts: &mut [StorageAccount],
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = &mut self.account.state()?;
|
||||
if let StorageContract::ValidatorStorage {
|
||||
slot: state_slot,
|
||||
segment: state_segment,
|
||||
lockout_validations,
|
||||
..
|
||||
} = &mut storage_contract
|
||||
{
|
||||
let segment_index = segment as usize;
|
||||
let state_segment = get_segment_from_slot(*state_slot);
|
||||
|
||||
if segment_index > state_segment {
|
||||
if segment_index > *state_segment {
|
||||
return Err(InstructionError::CustomError(
|
||||
StorageError::InvalidSegment as u32,
|
||||
));
|
||||
@ -460,7 +453,7 @@ fn store_validation_result(
|
||||
me: &Pubkey,
|
||||
current: &syscall::current::Current,
|
||||
storage_account: &mut StorageAccount,
|
||||
segment: usize,
|
||||
segment: u64,
|
||||
proof_mask: &[ProofStatus],
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut storage_contract = storage_account.account.state()?;
|
||||
@ -494,7 +487,7 @@ fn store_validation_result(
|
||||
}
|
||||
|
||||
fn count_valid_proofs(
|
||||
validations: &BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
validations: &BTreeMap<u64, BTreeMap<Pubkey, Vec<ProofStatus>>>,
|
||||
) -> (u64, u64) {
|
||||
let proofs = validations
|
||||
.iter()
|
||||
@ -537,7 +530,7 @@ mod tests {
|
||||
|
||||
contract = StorageContract::ValidatorStorage {
|
||||
owner: Pubkey::default(),
|
||||
slot: 0,
|
||||
segment: 0,
|
||||
hash: Hash::default(),
|
||||
lockout_validations: BTreeMap::new(),
|
||||
credits: Credits::default(),
|
||||
@ -569,7 +562,7 @@ mod tests {
|
||||
executable: false,
|
||||
},
|
||||
};
|
||||
let segment_index = 0_usize;
|
||||
let segment_index = 0;
|
||||
let proof = Proof {
|
||||
segment_index,
|
||||
..Proof::default()
|
||||
|
@ -23,13 +23,13 @@ pub enum StorageInstruction {
|
||||
|
||||
SubmitMiningProof {
|
||||
sha_state: Hash,
|
||||
segment_index: usize,
|
||||
segment_index: u64,
|
||||
signature: Signature,
|
||||
blockhash: Hash,
|
||||
},
|
||||
AdvertiseStorageRecentBlockhash {
|
||||
hash: Hash,
|
||||
slot: u64,
|
||||
segment: u64,
|
||||
},
|
||||
/// Redeem storage reward credits
|
||||
///
|
||||
@ -132,7 +132,7 @@ pub fn create_replicator_storage_account(
|
||||
pub fn mining_proof(
|
||||
storage_pubkey: &Pubkey,
|
||||
sha_state: Hash,
|
||||
segment_index: usize,
|
||||
segment_index: u64,
|
||||
signature: Signature,
|
||||
blockhash: Hash,
|
||||
) -> Instruction {
|
||||
@ -152,11 +152,11 @@ pub fn mining_proof(
|
||||
pub fn advertise_recent_blockhash(
|
||||
storage_pubkey: &Pubkey,
|
||||
storage_hash: Hash,
|
||||
slot: u64,
|
||||
segment: u64,
|
||||
) -> Instruction {
|
||||
let storage_instruction = StorageInstruction::AdvertiseStorageRecentBlockhash {
|
||||
hash: storage_hash,
|
||||
slot,
|
||||
segment,
|
||||
};
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*storage_pubkey, true),
|
||||
|
@ -51,13 +51,13 @@ pub fn process_instruction(
|
||||
current,
|
||||
)
|
||||
}
|
||||
StorageInstruction::AdvertiseStorageRecentBlockhash { hash, slot } => {
|
||||
StorageInstruction::AdvertiseStorageRecentBlockhash { hash, segment } => {
|
||||
if me_unsigned || rest.len() != 1 {
|
||||
// This instruction must be signed by `me`
|
||||
Err(InstructionError::InvalidArgument)?;
|
||||
}
|
||||
let current = syscall::current::from_keyed_account(&rest[0])?;
|
||||
storage_account.advertise_storage_recent_blockhash(hash, slot, current)
|
||||
storage_account.advertise_storage_recent_blockhash(hash, segment, current)
|
||||
}
|
||||
StorageInstruction::ClaimStorageReward => {
|
||||
if rest.len() != 4 {
|
||||
|
@ -16,17 +16,18 @@ use solana_sdk::syscall::current::Current;
|
||||
use solana_sdk::syscall::rewards::Rewards;
|
||||
use solana_sdk::syscall::{current, rewards};
|
||||
use solana_sdk::system_instruction;
|
||||
use solana_sdk::timing::DEFAULT_TICKS_PER_SLOT;
|
||||
use solana_sdk::timing::{
|
||||
get_segment_from_slot, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT,
|
||||
};
|
||||
use solana_storage_api::id;
|
||||
use solana_storage_api::storage_contract::StorageAccount;
|
||||
use solana_storage_api::storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE};
|
||||
use solana_storage_api::storage_instruction;
|
||||
use solana_storage_api::storage_processor::process_instruction;
|
||||
use solana_storage_api::SLOTS_PER_SEGMENT;
|
||||
use solana_storage_api::{get_segment_from_slot, id};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
const TICKS_IN_SEGMENT: u64 = SLOTS_PER_SEGMENT * DEFAULT_TICKS_PER_SLOT;
|
||||
const TICKS_IN_SEGMENT: u64 = DEFAULT_SLOTS_PER_SEGMENT * DEFAULT_TICKS_PER_SLOT;
|
||||
|
||||
fn test_instruction(
|
||||
ix: &Instruction,
|
||||
@ -125,10 +126,11 @@ fn test_proof_bounds() {
|
||||
Hash::default(),
|
||||
);
|
||||
// the proof is for segment 0, need to move the slot into segment 2
|
||||
let mut current_account = current::create_account(1, 0, 0, 0);
|
||||
let mut current_account = current::create_account(1, 0, 0, 0, 0);
|
||||
Current::to(
|
||||
&Current {
|
||||
slot: SLOTS_PER_SEGMENT * 2,
|
||||
slot: DEFAULT_SLOTS_PER_SEGMENT * 2,
|
||||
segment: 2,
|
||||
epoch: 0,
|
||||
stakers_epoch: 0,
|
||||
},
|
||||
@ -155,15 +157,11 @@ fn test_serialize_overflow() {
|
||||
let current_id = current::id();
|
||||
let mut keyed_accounts = Vec::new();
|
||||
let mut user_account = Account::default();
|
||||
let mut current_account = current::create_account(1, 0, 0, 0);
|
||||
let mut current_account = current::create_account(1, 0, 0, 0, 0);
|
||||
keyed_accounts.push(KeyedAccount::new(&pubkey, true, &mut user_account));
|
||||
keyed_accounts.push(KeyedAccount::new(¤t_id, false, &mut current_account));
|
||||
|
||||
let ix = storage_instruction::advertise_recent_blockhash(
|
||||
&pubkey,
|
||||
Hash::default(),
|
||||
SLOTS_PER_SEGMENT,
|
||||
);
|
||||
let ix = storage_instruction::advertise_recent_blockhash(&pubkey, Hash::default(), 1);
|
||||
|
||||
assert_eq!(
|
||||
process_instruction(&id(), &mut keyed_accounts, &ix.data),
|
||||
@ -184,10 +182,11 @@ fn test_invalid_accounts_len() {
|
||||
Hash::default(),
|
||||
);
|
||||
// move tick height into segment 1
|
||||
let mut current_account = current::create_account(1, 0, 0, 0);
|
||||
let mut current_account = current::create_account(1, 0, 0, 0, 0);
|
||||
Current::to(
|
||||
&Current {
|
||||
slot: 16,
|
||||
segment: 1,
|
||||
epoch: 0,
|
||||
stakers_epoch: 0,
|
||||
},
|
||||
@ -243,10 +242,11 @@ fn test_submit_mining_ok() {
|
||||
Hash::default(),
|
||||
);
|
||||
// move slot into segment 1
|
||||
let mut current_account = current::create_account(1, 0, 0, 0);
|
||||
let mut current_account = current::create_account(1, 0, 0, 0, 0);
|
||||
Current::to(
|
||||
&Current {
|
||||
slot: SLOTS_PER_SEGMENT,
|
||||
slot: DEFAULT_SLOTS_PER_SEGMENT,
|
||||
segment: 1,
|
||||
epoch: 0,
|
||||
stakers_epoch: 0,
|
||||
},
|
||||
@ -300,7 +300,7 @@ fn test_validate_mining() {
|
||||
let bank = Arc::new(Bank::new_from_parent(
|
||||
&bank,
|
||||
&Pubkey::default(),
|
||||
SLOTS_PER_SEGMENT * 2,
|
||||
DEFAULT_SLOTS_PER_SEGMENT * 2,
|
||||
));
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
@ -309,7 +309,7 @@ fn test_validate_mining() {
|
||||
vec![storage_instruction::advertise_recent_blockhash(
|
||||
&validator_storage_id,
|
||||
Hash::default(),
|
||||
SLOTS_PER_SEGMENT,
|
||||
1,
|
||||
)],
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
@ -344,17 +344,17 @@ fn test_validate_mining() {
|
||||
vec![storage_instruction::advertise_recent_blockhash(
|
||||
&validator_storage_id,
|
||||
Hash::default(),
|
||||
SLOTS_PER_SEGMENT * 2,
|
||||
2,
|
||||
)],
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
|
||||
// move banks into the next segment
|
||||
let proof_segment = get_segment_from_slot(bank.slot());
|
||||
let proof_segment = get_segment_from_slot(bank.slot(), bank.slots_per_segment());
|
||||
let bank = Arc::new(Bank::new_from_parent(
|
||||
&bank,
|
||||
&Pubkey::default(),
|
||||
SLOTS_PER_SEGMENT + bank.slot(),
|
||||
DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
|
||||
));
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
@ -381,7 +381,7 @@ fn test_validate_mining() {
|
||||
vec![storage_instruction::advertise_recent_blockhash(
|
||||
&validator_storage_id,
|
||||
Hash::default(),
|
||||
SLOTS_PER_SEGMENT * 3,
|
||||
3,
|
||||
)],
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
@ -390,7 +390,7 @@ fn test_validate_mining() {
|
||||
let bank = Arc::new(Bank::new_from_parent(
|
||||
&bank,
|
||||
&Pubkey::default(),
|
||||
SLOTS_PER_SEGMENT + bank.slot(),
|
||||
DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
|
||||
));
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
@ -505,21 +505,21 @@ fn init_storage_accounts(
|
||||
client.send_message(&[mint], message).unwrap();
|
||||
}
|
||||
|
||||
fn get_storage_slot<C: SyncClient>(client: &C, account: &Pubkey) -> u64 {
|
||||
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 { slot, .. } => {
|
||||
return slot;
|
||||
StorageContract::ValidatorStorage { segment, .. } => {
|
||||
return segment;
|
||||
}
|
||||
_ => info!("error in reading slot"),
|
||||
_ => info!("error in reading segment"),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
info!("error in reading slot");
|
||||
info!("error in reading segment");
|
||||
}
|
||||
}
|
||||
0
|
||||
@ -536,7 +536,7 @@ fn submit_proof(
|
||||
vec![storage_instruction::mining_proof(
|
||||
&storage_keypair.pubkey(),
|
||||
sha_state,
|
||||
segment_index as usize,
|
||||
segment_index,
|
||||
Signature::default(),
|
||||
bank_client.get_recent_blockhash().unwrap().0,
|
||||
)],
|
||||
@ -584,7 +584,11 @@ fn test_bank_storage() {
|
||||
let bank = Bank::new(&genesis_block);
|
||||
// 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(), SLOTS_PER_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;
|
||||
@ -615,7 +619,7 @@ fn test_bank_storage() {
|
||||
vec![storage_instruction::advertise_recent_blockhash(
|
||||
&validator_pubkey,
|
||||
storage_blockhash,
|
||||
SLOTS_PER_SEGMENT as u64,
|
||||
1,
|
||||
)],
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
@ -641,10 +645,7 @@ fn test_bank_storage() {
|
||||
Ok(_)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
get_storage_slot(&bank_client, &validator_pubkey),
|
||||
SLOTS_PER_SEGMENT
|
||||
);
|
||||
assert_eq!(get_storage_segment(&bank_client, &validator_pubkey), 1);
|
||||
assert_eq!(
|
||||
get_storage_blockhash(&bank_client, &validator_pubkey),
|
||||
storage_blockhash
|
||||
|
@ -168,7 +168,7 @@ mod tests {
|
||||
.iter()
|
||||
.map(|meta| {
|
||||
if syscall::current::check_id(&meta.pubkey) {
|
||||
syscall::current::create_account(1, 0, 0, 0)
|
||||
syscall::current::create_account(1, 0, 0, 0, 0)
|
||||
} else if syscall::slot_hashes::check_id(&meta.pubkey) {
|
||||
syscall::slot_hashes::create_account(1, &[])
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user