Update storage contract to use a deterministic BTreeMap (#4763)

This commit is contained in:
Sagar Dhawan 2019-06-21 09:51:05 -07:00 committed by GitHub
parent deb83cdef6
commit a40c5cf185
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 35 additions and 24 deletions

View File

@ -9,7 +9,7 @@ use solana_sdk::hash::Hash;
use solana_sdk::instruction::InstructionError; use solana_sdk::instruction::InstructionError;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signature; use solana_sdk::signature::Signature;
use std::collections::HashMap; use std::collections::BTreeMap;
pub const VALIDATOR_REWARD: u64 = 200; pub const VALIDATOR_REWARD: u64 = 200;
pub const REPLICATOR_REWARD: u64 = 200; pub const REPLICATOR_REWARD: u64 = 200;
@ -65,7 +65,7 @@ pub enum StorageContract {
hash: Hash, hash: Hash,
// Lockouts and Rewards are per segment per replicator. It needs to remain this way until // Lockouts and Rewards are per segment per replicator. It needs to remain this way until
// the challenge stage is added. Once challenges are in rewards can just be a number // the challenge stage is added. Once challenges are in rewards can just be a number
lockout_validations: HashMap<usize, HashMap<Pubkey, Vec<ProofStatus>>>, lockout_validations: BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
// lamports that are ready to be claimed // lamports that are ready to be claimed
pending_lamports: u64, pending_lamports: u64,
}, },
@ -73,10 +73,10 @@ pub enum StorageContract {
owner: Pubkey, owner: Pubkey,
// TODO what to do about duplicate proofs across segments? - Check the blockhashes // TODO what to do about duplicate proofs across segments? - Check the blockhashes
// Map of Proofs per segment, in a Vec // Map of Proofs per segment, in a Vec
proofs: HashMap<usize, Vec<Proof>>, proofs: BTreeMap<usize, Vec<Proof>>,
// Map of Rewards per segment, in a HashMap based on the validator account that verified // 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 // the proof. This can be used for challenge stage when its added
reward_validations: HashMap<usize, HashMap<Pubkey, Vec<ProofStatus>>>, reward_validations: BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
}, },
MiningPool, MiningPool,
@ -91,7 +91,7 @@ pub fn create_validator_storage_account(owner: Pubkey, lamports: u64) -> Account
owner, owner,
slot: 0, slot: 0,
hash: Hash::default(), hash: Hash::default(),
lockout_validations: HashMap::new(), lockout_validations: BTreeMap::new(),
pending_lamports: 0, pending_lamports: 0,
}) })
.expect("set_state"); .expect("set_state");
@ -135,8 +135,8 @@ impl<'a> StorageAccount<'a> {
if let StorageContract::Uninitialized = storage_contract { if let StorageContract::Uninitialized = storage_contract {
*storage_contract = StorageContract::ReplicatorStorage { *storage_contract = StorageContract::ReplicatorStorage {
owner, owner,
proofs: HashMap::new(), proofs: BTreeMap::new(),
reward_validations: HashMap::new(), reward_validations: BTreeMap::new(),
}; };
self.account.set_state(storage_contract) self.account.set_state(storage_contract)
} else { } else {
@ -151,7 +151,7 @@ impl<'a> StorageAccount<'a> {
owner, owner,
slot: 0, slot: 0,
hash: Hash::default(), hash: Hash::default(),
lockout_validations: HashMap::new(), lockout_validations: BTreeMap::new(),
pending_lamports: 0, pending_lamports: 0,
}; };
self.account.set_state(storage_contract) self.account.set_state(storage_contract)
@ -179,8 +179,16 @@ impl<'a> StorageAccount<'a> {
// clean up the account // clean up the account
// TODO check for time correctness - storage seems to run at a delay of about 3 // TODO check for time correctness - storage seems to run at a delay of about 3
proofs.retain(|segment, _| *segment >= current_segment.saturating_sub(5)); *proofs = proofs
reward_validations.retain(|segment, _| *segment >= current_segment.saturating_sub(10)); .iter()
.filter(|(segment, _)| **segment >= current_segment.saturating_sub(5))
.map(|(segment, proofs)| (*segment, proofs.clone()))
.collect();
*reward_validations = reward_validations
.iter()
.filter(|(segment, _)| **segment >= current_segment.saturating_sub(10))
.map(|(segment, rewards)| (*segment, rewards.clone()))
.collect();
if segment_index >= current_segment { if segment_index >= current_segment {
// attempt to submit proof for unconfirmed segment // attempt to submit proof for unconfirmed segment
@ -261,15 +269,16 @@ impl<'a> StorageAccount<'a> {
// storage epoch updated, move the lockout_validations to pending_lamports // storage epoch updated, move the lockout_validations to pending_lamports
let num_validations = count_valid_proofs( let num_validations = count_valid_proofs(
&lockout_validations &lockout_validations
.drain() .iter()
.flat_map(|(_segment, mut proofs)| { .flat_map(|(_segment, proofs)| {
proofs proofs
.drain() .iter()
.flat_map(|(_, proof)| proof) .flat_map(|(_, proof)| proof.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
lockout_validations.clear();
*pending_lamports += VALIDATOR_REWARD * num_validations; *pending_lamports += VALIDATOR_REWARD * num_validations;
self.account.set_state(storage_contract) self.account.set_state(storage_contract)
} else { } else {
@ -411,14 +420,15 @@ impl<'a> StorageAccount<'a> {
} }
let checked_proofs = reward_validations let checked_proofs = reward_validations
.drain() .iter()
.flat_map(|(_, mut proofs)| { .flat_map(|(_, proofs)| {
proofs proofs
.drain() .iter()
.flat_map(|(_, proofs)| proofs) .flat_map(|(_, proofs)| proofs.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
reward_validations.clear();
let total_proofs = checked_proofs.len() as u64; let total_proofs = checked_proofs.len() as u64;
let num_validations = count_valid_proofs(&checked_proofs); let num_validations = count_valid_proofs(&checked_proofs);
let reward = num_validations * REPLICATOR_REWARD * (num_validations / total_proofs); let reward = num_validations * REPLICATOR_REWARD * (num_validations / total_proofs);
@ -477,6 +487,7 @@ fn count_valid_proofs(proofs: &[ProofStatus]) -> u64 {
mod tests { mod tests {
use super::*; use super::*;
use crate::id; use crate::id;
use std::collections::BTreeMap;
#[test] #[test]
fn test_account_data() { fn test_account_data() {
@ -497,7 +508,7 @@ mod tests {
owner: Pubkey::default(), owner: Pubkey::default(),
slot: 0, slot: 0,
hash: Hash::default(), hash: Hash::default(),
lockout_validations: HashMap::new(), lockout_validations: BTreeMap::new(),
pending_lamports: 0, pending_lamports: 0,
}; };
storage_account.account.set_state(&contract).unwrap(); storage_account.account.set_state(&contract).unwrap();
@ -506,8 +517,8 @@ mod tests {
} }
contract = StorageContract::ReplicatorStorage { contract = StorageContract::ReplicatorStorage {
owner: Pubkey::default(), owner: Pubkey::default(),
proofs: HashMap::new(), proofs: BTreeMap::new(),
reward_validations: HashMap::new(), reward_validations: BTreeMap::new(),
}; };
storage_account.account.set_state(&contract).unwrap(); storage_account.account.set_state(&contract).unwrap();
if let StorageContract::ValidatorStorage { .. } = contract { if let StorageContract::ValidatorStorage { .. } = contract {
@ -547,12 +558,12 @@ mod tests {
.resize(STORAGE_ACCOUNT_SPACE as usize, 0); .resize(STORAGE_ACCOUNT_SPACE as usize, 0);
let storage_contract = &mut account.account.state().unwrap(); let storage_contract = &mut account.account.state().unwrap();
if let StorageContract::Uninitialized = storage_contract { if let StorageContract::Uninitialized = storage_contract {
let mut proofs = HashMap::new(); let mut proofs = BTreeMap::new();
proofs.insert(0, vec![proof.clone()]); proofs.insert(0, vec![proof.clone()]);
*storage_contract = StorageContract::ReplicatorStorage { *storage_contract = StorageContract::ReplicatorStorage {
owner: Pubkey::default(), owner: Pubkey::default(),
proofs, proofs,
reward_validations: HashMap::new(), reward_validations: BTreeMap::new(),
}; };
}; };
account.account.set_state(storage_contract).unwrap(); account.account.set_state(storage_contract).unwrap();