Change replicators to slot-based (#4118)

This commit is contained in:
Sagar Dhawan
2019-05-03 16:27:53 -07:00
committed by GitHub
parent 5bb75a5894
commit a7b695c27a
17 changed files with 255 additions and 484 deletions

View File

@ -4,10 +4,10 @@ pub mod storage_processor;
use solana_sdk::pubkey::Pubkey;
pub const ENTRIES_PER_SEGMENT: u64 = 16;
pub const SLOTS_PER_SEGMENT: u64 = 2;
pub fn get_segment_from_entry(entry_height: u64) -> usize {
(entry_height / ENTRIES_PER_SEGMENT) as usize
pub fn get_segment_from_slot(slot: u64) -> usize {
(slot / SLOTS_PER_SEGMENT) as usize
}
const STORAGE_PROGRAM_ID: [u8; 32] = [

View File

@ -1,4 +1,4 @@
use crate::{get_segment_from_entry, ENTRIES_PER_SEGMENT};
use crate::get_segment_from_slot;
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::account::Account;
@ -44,7 +44,7 @@ pub enum StorageContract {
Default,
ValidatorStorage {
entry_height: u64,
slot: u64,
hash: Hash,
lockout_validations: Vec<Vec<CheckedProof>>,
reward_validations: Vec<Vec<CheckedProof>>,
@ -68,7 +68,7 @@ impl<'a> StorageAccount<'a> {
&mut self,
id: Pubkey,
sha_state: Hash,
entry_height: u64,
slot: u64,
signature: Signature,
) -> Result<(), InstructionError> {
let mut storage_contract = &mut self.account.state()?;
@ -80,7 +80,7 @@ impl<'a> StorageAccount<'a> {
};
if let StorageContract::ReplicatorStorage { proofs, .. } = &mut storage_contract {
let segment_index = get_segment_from_entry(entry_height);
let segment_index = get_segment_from_slot(slot);
if segment_index > proofs.len() || proofs.is_empty() {
proofs.resize(cmp::max(1, segment_index), Proof::default());
}
@ -91,8 +91,8 @@ impl<'a> StorageAccount<'a> {
}
debug!(
"Mining proof submitted with contract {:?} entry_height: {}",
sha_state, entry_height
"Mining proof submitted with contract {:?} slot: {}",
sha_state, slot
);
let proof_info = Proof {
@ -110,12 +110,12 @@ impl<'a> StorageAccount<'a> {
pub fn advertise_storage_recent_blockhash(
&mut self,
hash: Hash,
entry_height: u64,
slot: u64,
) -> Result<(), InstructionError> {
let mut storage_contract = &mut self.account.state()?;
if let StorageContract::Default = storage_contract {
*storage_contract = StorageContract::ValidatorStorage {
entry_height: 0,
slot: 0,
hash: Hash::default(),
lockout_validations: vec![],
reward_validations: vec![],
@ -123,14 +123,14 @@ impl<'a> StorageAccount<'a> {
};
if let StorageContract::ValidatorStorage {
entry_height: state_entry_height,
slot: state_slot,
hash: state_hash,
reward_validations,
lockout_validations,
} = &mut storage_contract
{
let original_segments = *state_entry_height / ENTRIES_PER_SEGMENT;
let segments = entry_height / ENTRIES_PER_SEGMENT;
let original_segments = get_segment_from_slot(*state_slot);
let segments = get_segment_from_slot(slot);
debug!(
"advertise new last id segments: {} orig: {}",
segments, original_segments
@ -139,7 +139,7 @@ impl<'a> StorageAccount<'a> {
return Err(InstructionError::InvalidArgument);
}
*state_entry_height = entry_height;
*state_slot = slot;
*state_hash = hash;
// move lockout_validations to reward_validations
@ -154,14 +154,14 @@ impl<'a> StorageAccount<'a> {
pub fn proof_validation(
&mut self,
entry_height: u64,
slot: u64,
proofs: Vec<CheckedProof>,
replicator_accounts: &mut [StorageAccount],
) -> Result<(), InstructionError> {
let mut storage_contract = &mut self.account.state()?;
if let StorageContract::Default = storage_contract {
*storage_contract = StorageContract::ValidatorStorage {
entry_height: 0,
slot: 0,
hash: Hash::default(),
lockout_validations: vec![],
reward_validations: vec![],
@ -169,16 +169,16 @@ impl<'a> StorageAccount<'a> {
};
if let StorageContract::ValidatorStorage {
entry_height: current_entry_height,
slot: current_slot,
lockout_validations,
..
} = &mut storage_contract
{
if entry_height >= *current_entry_height {
if slot >= *current_slot {
return Err(InstructionError::InvalidArgument);
}
let segment_index = get_segment_from_entry(entry_height);
let segment_index = get_segment_from_slot(slot);
let mut previous_proofs = replicator_accounts
.iter_mut()
.filter_map(|account| {
@ -224,7 +224,7 @@ impl<'a> StorageAccount<'a> {
pub fn claim_storage_reward(
&mut self,
entry_height: u64,
slot: u64,
tick_height: u64,
) -> Result<(), InstructionError> {
let mut storage_contract = &mut self.account.state()?;
@ -236,7 +236,7 @@ impl<'a> StorageAccount<'a> {
reward_validations, ..
} = &mut storage_contract
{
let claims_index = get_segment_from_entry(entry_height);
let claims_index = get_segment_from_slot(slot);
let _num_validations = count_valid_proofs(&reward_validations[claims_index]);
// TODO can't just create lamports out of thin air
// self.account.lamports += TOTAL_VALIDATOR_REWARDS * num_validations;
@ -248,8 +248,8 @@ impl<'a> StorageAccount<'a> {
{
// if current tick height is a full segment away? then allow reward collection
// storage needs to move to tick heights too, until then this makes little sense
let current_index = get_segment_from_entry(tick_height);
let claims_index = get_segment_from_entry(entry_height);
let current_index = get_segment_from_slot(tick_height);
let claims_index = get_segment_from_slot(slot);
if current_index <= claims_index || claims_index >= reward_validations.len() {
debug!(
"current {:?}, claim {:?}, rewards {:?}",
@ -348,7 +348,7 @@ mod tests {
}
contract = StorageContract::ValidatorStorage {
entry_height: 0,
slot: 0,
hash: Hash::default(),
lockout_validations: vec![],
reward_validations: vec![],

View File

@ -11,18 +11,18 @@ use solana_sdk::signature::Signature;
pub enum StorageInstruction {
SubmitMiningProof {
sha_state: Hash,
entry_height: u64,
slot: u64,
signature: Signature,
},
AdvertiseStorageRecentBlockhash {
hash: Hash,
entry_height: u64,
slot: u64,
},
ClaimStorageReward {
entry_height: u64,
slot: u64,
},
ProofValidation {
entry_height: u64,
slot: u64,
proofs: Vec<CheckedProof>,
},
}
@ -30,12 +30,12 @@ pub enum StorageInstruction {
pub fn mining_proof(
from_pubkey: &Pubkey,
sha_state: Hash,
entry_height: u64,
slot: u64,
signature: Signature,
) -> Instruction {
let storage_instruction = StorageInstruction::SubmitMiningProof {
sha_state,
entry_height,
slot,
signature,
};
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
@ -45,34 +45,27 @@ pub fn mining_proof(
pub fn advertise_recent_blockhash(
from_pubkey: &Pubkey,
storage_hash: Hash,
entry_height: u64,
slot: u64,
) -> Instruction {
let storage_instruction = StorageInstruction::AdvertiseStorageRecentBlockhash {
hash: storage_hash,
entry_height,
slot,
};
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn proof_validation(
from_pubkey: &Pubkey,
entry_height: u64,
proofs: Vec<CheckedProof>,
) -> Instruction {
pub fn proof_validation(from_pubkey: &Pubkey, slot: u64, proofs: Vec<CheckedProof>) -> Instruction {
let mut account_metas = vec![AccountMeta::new(*from_pubkey, true)];
proofs.iter().for_each(|checked_proof| {
account_metas.push(AccountMeta::new(checked_proof.proof.id, false))
});
let storage_instruction = StorageInstruction::ProofValidation {
entry_height,
proofs,
};
let storage_instruction = StorageInstruction::ProofValidation { slot, proofs };
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn reward_claim(from_pubkey: &Pubkey, entry_height: u64) -> Instruction {
let storage_instruction = StorageInstruction::ClaimStorageReward { entry_height };
pub fn reward_claim(from_pubkey: &Pubkey, slot: u64) -> Instruction {
let storage_instruction = StorageInstruction::ClaimStorageReward { slot };
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
Instruction::new(id(), &storage_instruction, account_metas)
}

View File

@ -37,44 +37,36 @@ pub fn process_instruction(
match bincode::deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
StorageInstruction::SubmitMiningProof {
sha_state,
entry_height,
slot,
signature,
} => {
if num_keyed_accounts != 1 {
Err(InstructionError::InvalidArgument)?;
}
storage_account.submit_mining_proof(
storage_account_pubkey,
sha_state,
entry_height,
signature,
)
storage_account.submit_mining_proof(storage_account_pubkey, sha_state, slot, signature)
}
StorageInstruction::AdvertiseStorageRecentBlockhash { hash, entry_height } => {
StorageInstruction::AdvertiseStorageRecentBlockhash { hash, slot } => {
if num_keyed_accounts != 1 {
// keyed_accounts[0] should be the main storage key
// to access its data
Err(InstructionError::InvalidArgument)?;
}
storage_account.advertise_storage_recent_blockhash(hash, entry_height)
storage_account.advertise_storage_recent_blockhash(hash, slot)
}
StorageInstruction::ClaimStorageReward { entry_height } => {
StorageInstruction::ClaimStorageReward { slot } => {
if num_keyed_accounts != 1 {
// keyed_accounts[0] should be the main storage key
// to access its data
Err(InstructionError::InvalidArgument)?;
}
storage_account.claim_storage_reward(entry_height, tick_height)
storage_account.claim_storage_reward(slot, tick_height)
}
StorageInstruction::ProofValidation {
entry_height,
proofs,
} => {
StorageInstruction::ProofValidation { slot, proofs } => {
if num_keyed_accounts == 1 {
// have to have at least 1 replicator to do any verification
Err(InstructionError::InvalidArgument)?;
}
storage_account.proof_validation(entry_height, proofs, &mut rest)
storage_account.proof_validation(slot, proofs, &mut rest)
}
}
}
@ -85,7 +77,7 @@ mod tests {
use crate::id;
use crate::storage_contract::{CheckedProof, Proof, ProofStatus, StorageContract};
use crate::storage_instruction;
use crate::ENTRIES_PER_SEGMENT;
use crate::SLOTS_PER_SEGMENT;
use bincode::deserialize;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
@ -134,7 +126,7 @@ mod tests {
let ix = storage_instruction::advertise_recent_blockhash(
&pubkey,
Hash::default(),
ENTRIES_PER_SEGMENT,
SLOTS_PER_SEGMENT,
);
assert_eq!(
@ -158,7 +150,7 @@ mod tests {
}
#[test]
fn test_submit_mining_invalid_entry_height() {
fn test_submit_mining_invalid_slot() {
solana_logger::setup();
let pubkey = Pubkey::new_rand();
let mut accounts = [Account::default(), Account::default()];
@ -197,7 +189,7 @@ mod tests {
let mut bank = Bank::new(&genesis_block);
bank.add_instruction_processor(id(), process_instruction);
let entry_height = 0;
let slot = 0;
let bank_client = BankClient::new(bank);
let ix = system_instruction::create_account(&mint_pubkey, &validator, 10, 4 * 1042, &id());
@ -209,7 +201,7 @@ mod tests {
let ix = storage_instruction::advertise_recent_blockhash(
&validator,
Hash::default(),
ENTRIES_PER_SEGMENT,
SLOTS_PER_SEGMENT,
);
bank_client
@ -219,7 +211,7 @@ mod tests {
let ix = storage_instruction::mining_proof(
&replicator,
Hash::default(),
entry_height,
slot,
Signature::default(),
);
bank_client
@ -229,7 +221,7 @@ mod tests {
let ix = storage_instruction::advertise_recent_blockhash(
&validator,
Hash::default(),
ENTRIES_PER_SEGMENT * 2,
SLOTS_PER_SEGMENT * 2,
);
bank_client
.send_instruction(&validator_keypair, ix)
@ -237,7 +229,7 @@ mod tests {
let ix = storage_instruction::proof_validation(
&validator,
entry_height,
slot,
vec![CheckedProof {
proof: Proof {
id: replicator,
@ -254,13 +246,13 @@ mod tests {
let ix = storage_instruction::advertise_recent_blockhash(
&validator,
Hash::default(),
ENTRIES_PER_SEGMENT * 3,
SLOTS_PER_SEGMENT * 3,
);
bank_client
.send_instruction(&validator_keypair, ix)
.unwrap();
let ix = storage_instruction::reward_claim(&validator, entry_height);
let ix = storage_instruction::reward_claim(&validator, slot);
bank_client
.send_instruction(&validator_keypair, ix)
.unwrap();
@ -274,7 +266,7 @@ mod tests {
// bank.register_tick(&bank.last_blockhash());
//}
let ix = storage_instruction::reward_claim(&replicator, entry_height);
let ix = storage_instruction::reward_claim(&replicator, slot);
bank_client
.send_instruction(&replicator_keypair, ix)
.unwrap();
@ -283,21 +275,21 @@ mod tests {
// assert_eq!(bank_client.get_balance(&replicator).unwrap(), TOTAL_REPLICATOR_REWARDS);
}
fn get_storage_entry_height<C: SyncClient>(client: &C, account: &Pubkey) -> u64 {
fn get_storage_slot<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 { entry_height, .. } => {
return entry_height;
StorageContract::ValidatorStorage { slot, .. } => {
return slot;
}
_ => info!("error in reading entry_height"),
_ => info!("error in reading slot"),
}
}
}
None => {
info!("error in reading entry_height");
info!("error in reading slot");
}
}
0
@ -357,18 +349,18 @@ mod tests {
let ix = storage_instruction::advertise_recent_blockhash(
&validator_pubkey,
storage_blockhash,
ENTRIES_PER_SEGMENT,
SLOTS_PER_SEGMENT,
);
bank_client
.send_instruction(&validator_keypair, ix)
.unwrap();
let entry_height = 0;
let slot = 0;
let ix = storage_instruction::mining_proof(
&replicator_pubkey,
Hash::default(),
entry_height,
slot,
Signature::default(),
);
let _result = bank_client
@ -376,8 +368,8 @@ mod tests {
.unwrap();
assert_eq!(
get_storage_entry_height(&bank_client, &validator_pubkey),
ENTRIES_PER_SEGMENT
get_storage_slot(&bank_client, &validator_pubkey),
SLOTS_PER_SEGMENT
);
assert_eq!(
get_storage_blockhash(&bank_client, &validator_pubkey),