add slot_hashes to bank, remove phony slot_hashes_from_vote_instruction (#4401)

This commit is contained in:
Rob Walker
2019-05-22 19:07:56 -07:00
committed by GitHub
parent b8f6c17dee
commit 7ada8510c4
4 changed files with 98 additions and 45 deletions

View File

@ -10,6 +10,7 @@ use solana_metrics::datapoint_warn;
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError}; use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::syscall::slot_hashes;
use solana_sdk::system_instruction; use solana_sdk::system_instruction;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
@ -93,7 +94,10 @@ pub fn vote(
authorized_voter_id: &Pubkey, authorized_voter_id: &Pubkey,
recent_votes: Vec<Vote>, recent_votes: Vec<Vote>,
) -> Instruction { ) -> Instruction {
let account_metas = metas_for_authorized_signer(from_id, vote_id, authorized_voter_id); let mut account_metas = metas_for_authorized_signer(from_id, vote_id, authorized_voter_id);
// request slot_hashes syscall account after vote_id
account_metas.insert(2, AccountMeta::new(slot_hashes::id(), false));
Instruction::new(id(), &VoteInstruction::Vote(recent_votes), account_metas) Instruction::new(id(), &VoteInstruction::Vote(recent_votes), account_metas)
} }
@ -114,7 +118,7 @@ pub fn process_instruction(
} }
// 0th index is the guy who paid for the transaction // 0th index is the guy who paid for the transaction
let (me, other_signers) = &mut keyed_accounts.split_at_mut(2); let (me, rest) = &mut keyed_accounts.split_at_mut(2);
let me = &mut me[1]; let me = &mut me[1];
// TODO: data-driven unpack and dispatch of KeyedAccounts // TODO: data-driven unpack and dispatch of KeyedAccounts
@ -123,33 +127,13 @@ pub fn process_instruction(
vote_state::initialize_account(me, &node_id, commission) vote_state::initialize_account(me, &node_id, commission)
} }
VoteInstruction::AuthorizeVoter(voter_id) => { VoteInstruction::AuthorizeVoter(voter_id) => {
vote_state::authorize_voter(me, other_signers, &voter_id) vote_state::authorize_voter(me, rest, &voter_id)
} }
VoteInstruction::Vote(votes) => { VoteInstruction::Vote(votes) => {
datapoint_warn!("vote-native", ("count", 1, i64)); datapoint_warn!("vote-native", ("count", 1, i64));
// TODO: remove me when Bank does this let (slot_hashes, other_signers) = rest.split_at_mut(1);
let valid_votes = votes let slot_hashes = &mut slot_hashes[0];
.iter() vote_state::process_votes(me, slot_hashes, other_signers, &votes)
.map(|vote| (vote.slot, vote.hash))
.collect::<Vec<_>>();
use bincode::serialized_size;
use solana_sdk::account::Account;
use solana_sdk::account_utils::State;
use solana_sdk::syscall::slot_hashes;
let mut valid_votes_account = Account::new(
0,
serialized_size(&valid_votes).unwrap() as usize,
&Pubkey::default(),
);
valid_votes_account.set_state(&valid_votes).unwrap();
// END TODO: remove me when Bank does this
vote_state::process_votes(
me,
&mut KeyedAccount::new(&slot_hashes::id(), false, &mut valid_votes_account),
other_signers,
&votes,
)
} }
} }
} }

View File

@ -24,6 +24,7 @@ use solana_sdk::hash::{extend_and_hash, Hash};
use solana_sdk::native_loader; use solana_sdk::native_loader;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signature}; use solana_sdk::signature::{Keypair, Signature};
use solana_sdk::syscall::slot_hashes::{self, SlotHashes};
use solana_sdk::system_transaction; use solana_sdk::system_transaction;
use solana_sdk::timing::{duration_as_ms, duration_as_us, MAX_RECENT_BLOCKHASHES}; use solana_sdk::timing::{duration_as_ms, duration_as_us, MAX_RECENT_BLOCKHASHES};
use solana_sdk::transaction::{Result, Transaction, TransactionError}; use solana_sdk::transaction::{Result, Transaction, TransactionError};
@ -198,7 +199,19 @@ impl Bank {
*self.hash.read().unwrap() != Hash::default() *self.hash.read().unwrap() != Hash::default()
} }
pub fn freeze(&self) { fn update_slot_hashes(&self) {
let mut account = self
.get_account(&slot_hashes::id())
.unwrap_or_else(|| slot_hashes::create_account(1));
let mut slot_hashes = SlotHashes::from(&account).unwrap();
slot_hashes.add(self.slot(), self.hash());
slot_hashes.to(&mut account).unwrap();
self.store(&slot_hashes::id(), &account);
}
fn set_hash(&self) {
let mut hash = self.hash.write().unwrap(); let mut hash = self.hash.write().unwrap();
if *hash == Hash::default() { if *hash == Hash::default() {
@ -207,6 +220,11 @@ impl Bank {
} }
} }
pub fn freeze(&self) {
self.set_hash();
self.update_slot_hashes();
}
pub fn epoch_schedule(&self) -> &EpochSchedule { pub fn epoch_schedule(&self) -> &EpochSchedule {
&self.epoch_schedule &self.epoch_schedule
} }
@ -1467,17 +1485,22 @@ mod tests {
fn test_bank_hash_internal_state_squash() { fn test_bank_hash_internal_state_squash() {
let collector_id = Pubkey::default(); let collector_id = Pubkey::default();
let bank0 = Arc::new(Bank::new(&create_genesis_block(10).0)); let bank0 = Arc::new(Bank::new(&create_genesis_block(10).0));
let hash0 = bank0.hash_internal_state();
// save hash0 because new_from_parent
// updates syscall entries
let bank1 = Bank::new_from_parent(&bank0, &collector_id, 1); let bank1 = Bank::new_from_parent(&bank0, &collector_id, 1);
// no delta in bank1, hashes match // no delta in bank1, hashes match
assert_eq!(bank0.hash_internal_state(), bank1.hash_internal_state()); assert_eq!(hash0, bank1.hash_internal_state());
// remove parent // remove parent
bank1.squash(); bank1.squash();
assert!(bank1.parents().is_empty()); assert!(bank1.parents().is_empty());
// hash should still match // hash should still match,
assert_eq!(bank0.hash(), bank1.hash()); // can't use hash_internal_state() after a freeze()...
assert_eq!(hash0, bank1.hash());
} }
/// Verifies that last ids and accounts are correctly referenced from parent /// Verifies that last ids and accounts are correctly referenced from parent

View File

@ -6,13 +6,17 @@ pub mod slot_hashes;
/// "Sysca11111111111111111111111111111111111111" /// "Sysca11111111111111111111111111111111111111"
/// owner pubkey for syscall accounts /// owner pubkey for syscall accounts
const SYSCALL_PROGRAM_ID: [u8; 32] = [ const ID: [u8; 32] = [
6, 167, 211, 138, 69, 216, 137, 185, 198, 189, 33, 204, 111, 12, 217, 220, 229, 201, 34, 52, 6, 167, 211, 138, 69, 216, 137, 185, 198, 189, 33, 204, 111, 12, 217, 220, 229, 201, 34, 52,
253, 202, 87, 144, 232, 16, 195, 192, 0, 0, 0, 0, 253, 202, 87, 144, 232, 16, 195, 192, 0, 0, 0, 0,
]; ];
pub fn id() -> Pubkey { pub fn id() -> Pubkey {
Pubkey::new(&SYSCALL_PROGRAM_ID) Pubkey::new(&ID)
}
pub fn check_id(id: &Pubkey) -> bool {
id.as_ref() == ID
} }
#[cfg(test)] #[cfg(test)]
@ -26,5 +30,6 @@ mod tests {
// dbg!((name, bs58::decode(name).into_vec().unwrap())); // dbg!((name, bs58::decode(name).into_vec().unwrap()));
// }); // });
assert!(ids.iter().all(|(name, id)| *name == id.to_string())); assert!(ids.iter().all(|(name, id)| *name == id.to_string()));
assert!(check_id(&id()));
} }
} }

View File

@ -3,56 +3,97 @@
//! this account carries the Bank's most recent blockhashes for some N parents //! this account carries the Bank's most recent blockhashes for some N parents
//! //!
use crate::account::Account; use crate::account::Account;
use crate::account_utils::State;
use crate::hash::Hash; use crate::hash::Hash;
use crate::pubkey::Pubkey; use crate::pubkey::Pubkey;
use crate::syscall;
use bincode::serialized_size;
use std::ops::Deref;
/// "Sysca11SlotHashes11111111111111111111111111" /// "Sysca11SlotHashes11111111111111111111111111"
/// slot hashes account pubkey /// slot hashes account pubkey
const SYSCALL_SLOT_HASHES_ID: [u8; 32] = [ const ID: [u8; 32] = [
6, 167, 211, 138, 69, 219, 186, 157, 48, 170, 46, 66, 2, 146, 193, 59, 39, 59, 245, 188, 30, 6, 167, 211, 138, 69, 219, 186, 157, 48, 170, 46, 66, 2, 146, 193, 59, 39, 59, 245, 188, 30,
60, 130, 78, 86, 27, 113, 191, 208, 0, 0, 0, 60, 130, 78, 86, 27, 113, 191, 208, 0, 0, 0,
]; ];
pub fn id() -> Pubkey { pub fn id() -> Pubkey {
Pubkey::new(&SYSCALL_SLOT_HASHES_ID) Pubkey::new(&ID)
} }
pub fn check_id(pubkey: &Pubkey) -> bool { pub fn check_id(pubkey: &Pubkey) -> bool {
pubkey.as_ref() == SYSCALL_SLOT_HASHES_ID pubkey.as_ref() == ID
} }
use crate::account_utils::State; pub const MAX_SLOT_HASHES: usize = 512; // 512 slots to get your vote in
use std::ops::{Deref, DerefMut};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct SlotHashes(Vec<(u64, Hash)>); pub struct SlotHashes {
// non-pub to keep control of size
inner: Vec<(u64, Hash)>,
}
impl SlotHashes { impl SlotHashes {
pub fn from(account: &Account) -> Option<Self> { pub fn from(account: &Account) -> Option<Self> {
account.state().ok() account.state().ok()
} }
pub fn to(&self, account: &mut Account) -> Option<()> {
account.set_state(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&SlotHashes {
inner: vec![(0, Hash::default()); MAX_SLOT_HASHES],
})
.unwrap() as usize
}
pub fn add(&mut self, slot: u64, hash: Hash) {
self.inner.insert(0, (slot, hash));
self.inner.truncate(MAX_SLOT_HASHES);
}
} }
impl Deref for SlotHashes { impl Deref for SlotHashes {
type Target = Vec<(u64, Hash)>; type Target = Vec<(u64, Hash)>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.inner
} }
} }
impl DerefMut for SlotHashes {
fn deref_mut(&mut self) -> &mut Self::Target { pub fn create_account(lamports: u64) -> Account {
&mut self.0 Account::new(lamports, SlotHashes::size_of(), &syscall::id())
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::hash::hash;
#[test] #[test]
fn test_syscall_ids() { fn test_slot_hashes_id() {
let ids = [("Sysca11S1otHashes11111111111111111111111111", id())]; let ids = [("Sysca11S1otHashes11111111111111111111111111", id())];
// to get the bytes above: // to get the bytes above:
// ids.iter().for_each(|(name, _)| { // ids.iter().for_each(|(name, _)| {
// dbg!((name, bs58::decode(name).into_vec().unwrap())); // dbg!((name, bs58::decode(name).into_vec().unwrap()));
// }); // });
assert!(ids.iter().all(|(name, id)| *name == id.to_string())); assert!(ids.iter().all(|(name, id)| *name == id.to_string()));
assert!(check_id(&id()));
}
#[test]
fn test_slot_hashes_create_account() {
let lamports = 42;
let account = create_account(lamports);
let slot_hashes = SlotHashes::from(&account);
assert_eq!(slot_hashes, Some(SlotHashes { inner: vec![] }));
let mut slot_hashes = slot_hashes.unwrap();
for i in 0..MAX_SLOT_HASHES + 1 {
slot_hashes.add(
i as u64,
hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]),
);
}
assert_eq!(slot_hashes[0].0, MAX_SLOT_HASHES as u64);
assert_eq!(slot_hashes.len(), MAX_SLOT_HASHES);
} }
} }