Update storage contract to use a deterministic BTreeMap (#4763)
This commit is contained in:
		| @@ -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(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user