add slot_hashes to bank, remove phony slot_hashes_from_vote_instruction (#4401)
This commit is contained in:
@ -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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user