Add tick height syscall (#4497)
* Remove tick_height from entrypoint signature * Impl tick_height syscall and use in storage program * Properly remove tick height from bpf handling
This commit is contained in:
@ -29,7 +29,6 @@ fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
_keyed_accounts: &mut [KeyedAccount],
|
||||
_data: &[u8],
|
||||
_tick_height: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, Signature};
|
||||
use solana_sdk::syscall::fees::{self, Fees};
|
||||
use solana_sdk::syscall::slot_hashes::{self, SlotHashes};
|
||||
use solana_sdk::syscall::tick_height::{self, TickHeight};
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::timing::{duration_as_ms, duration_as_us, MAX_RECENT_BLOCKHASHES};
|
||||
use solana_sdk::transaction::{Result, Transaction, TransactionError};
|
||||
@ -365,6 +366,16 @@ impl Bank {
|
||||
self.store(&fees::id(), &account);
|
||||
}
|
||||
|
||||
fn update_tick_height(&self) {
|
||||
let mut account = self
|
||||
.get_account(&tick_height::id())
|
||||
.unwrap_or_else(|| tick_height::create_account(1));
|
||||
|
||||
TickHeight::to(self.tick_height(), &mut account).unwrap();
|
||||
|
||||
self.store(&tick_height::id(), &account);
|
||||
}
|
||||
|
||||
fn set_hash(&self) -> bool {
|
||||
let mut hash = self.hash.write().unwrap();
|
||||
|
||||
@ -566,6 +577,8 @@ impl Bank {
|
||||
};
|
||||
inc_new_counter_debug!("bank-register_tick-registered", 1);
|
||||
|
||||
self.update_tick_height();
|
||||
|
||||
// Register a new block hash if at the last tick in the slot
|
||||
if current_tick_height % self.ticks_per_slot == self.ticks_per_slot - 1 {
|
||||
self.blockhash_queue.write().unwrap().register_hash(hash);
|
||||
@ -804,21 +817,20 @@ impl Bank {
|
||||
&mut error_counters,
|
||||
);
|
||||
let mut loaded_accounts = self.load_accounts(txs, sig_results, &mut error_counters);
|
||||
let tick_height = self.tick_height();
|
||||
|
||||
let load_elapsed = now.elapsed();
|
||||
let now = Instant::now();
|
||||
let executed: Vec<Result<()>> =
|
||||
loaded_accounts
|
||||
.iter_mut()
|
||||
.zip(txs.iter())
|
||||
.map(|(accs, tx)| match accs {
|
||||
Err(e) => Err(e.clone()),
|
||||
Ok((ref mut accounts, ref mut loaders)) => self
|
||||
.message_processor
|
||||
.process_message(tx.message(), loaders, accounts, tick_height),
|
||||
})
|
||||
.collect();
|
||||
let executed: Vec<Result<()>> = loaded_accounts
|
||||
.iter_mut()
|
||||
.zip(txs.iter())
|
||||
.map(|(accs, tx)| match accs {
|
||||
Err(e) => Err(e.clone()),
|
||||
Ok((ref mut accounts, ref mut loaders)) => {
|
||||
self.message_processor
|
||||
.process_message(tx.message(), loaders, accounts)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let execution_elapsed = now.elapsed();
|
||||
|
||||
@ -2172,6 +2184,21 @@ mod tests {
|
||||
assert_eq!(fees.fee_calculator.lamports_per_signature, 12345);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_tick_height_account() {
|
||||
let (genesis_block, _) = create_genesis_block(1);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
|
||||
for i in 0..10 {
|
||||
bank.register_tick(&hash::hash(format!("hashing {}", i).as_bytes()));
|
||||
}
|
||||
|
||||
let tick_account = bank.get_account(&tick_height::id()).unwrap();
|
||||
let tick_height = TickHeight::from(&tick_account).unwrap();
|
||||
assert_eq!(bank.tick_height(), tick_height);
|
||||
assert_eq!(tick_height, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_delta_with_no_committables() {
|
||||
let (genesis_block, mint_keypair) = create_genesis_block(8000);
|
||||
|
@ -82,7 +82,7 @@ fn verify_instruction(
|
||||
}
|
||||
|
||||
pub type ProcessInstruction =
|
||||
fn(&Pubkey, &mut [KeyedAccount], &[u8], u64) -> Result<(), InstructionError>;
|
||||
fn(&Pubkey, &mut [KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
||||
|
||||
pub type SymbolCache = RwLock<HashMap<Vec<u8>, Symbol<instruction_processor_utils::Entrypoint>>>;
|
||||
|
||||
@ -127,7 +127,6 @@ impl MessageProcessor {
|
||||
instruction: &CompiledInstruction,
|
||||
executable_accounts: &mut [(Pubkey, Account)],
|
||||
program_accounts: &mut [&mut Account],
|
||||
tick_height: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
|
||||
@ -151,7 +150,6 @@ impl MessageProcessor {
|
||||
&program_id,
|
||||
&mut keyed_accounts[1..],
|
||||
&instruction.data,
|
||||
tick_height,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -160,7 +158,6 @@ impl MessageProcessor {
|
||||
&program_id,
|
||||
&mut keyed_accounts,
|
||||
&instruction.data,
|
||||
tick_height,
|
||||
&self.symbol_cache,
|
||||
)
|
||||
}
|
||||
@ -175,7 +172,6 @@ impl MessageProcessor {
|
||||
instruction: &CompiledInstruction,
|
||||
executable_accounts: &mut [(Pubkey, Account)],
|
||||
program_accounts: &mut [&mut Account],
|
||||
tick_height: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
// TODO: the runtime should be checking read/write access to memory
|
||||
@ -186,13 +182,7 @@ impl MessageProcessor {
|
||||
.map(|a| (a.owner, a.lamports, a.data.clone()))
|
||||
.collect();
|
||||
|
||||
self.process_instruction(
|
||||
message,
|
||||
instruction,
|
||||
executable_accounts,
|
||||
program_accounts,
|
||||
tick_height,
|
||||
)?;
|
||||
self.process_instruction(message, instruction, executable_accounts, program_accounts)?;
|
||||
|
||||
// Verify the instruction
|
||||
for ((pre_program_id, pre_lamports, pre_data), post_account) in
|
||||
@ -222,7 +212,6 @@ impl MessageProcessor {
|
||||
message: &Message,
|
||||
loaders: &mut [Vec<(Pubkey, Account)>],
|
||||
accounts: &mut [Account],
|
||||
tick_height: u64,
|
||||
) -> Result<(), TransactionError> {
|
||||
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
||||
let executable_index = message
|
||||
@ -239,7 +228,6 @@ impl MessageProcessor {
|
||||
instruction,
|
||||
executable_accounts,
|
||||
&mut program_accounts,
|
||||
tick_height,
|
||||
)
|
||||
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ pub fn entrypoint(
|
||||
program_id: &Pubkey,
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
ix_data: &[u8],
|
||||
tick_height: u64,
|
||||
symbol_cache: &SymbolCache,
|
||||
) -> Result<(), InstructionError> {
|
||||
if keyed_accounts[0].account.executable {
|
||||
@ -68,7 +67,7 @@ pub fn entrypoint(
|
||||
let name_vec = &names[0].account.data;
|
||||
if let Some(entrypoint) = symbol_cache.read().unwrap().get(name_vec) {
|
||||
unsafe {
|
||||
return entrypoint(program_id, params, ix_data, tick_height);
|
||||
return entrypoint(program_id, params, ix_data);
|
||||
}
|
||||
}
|
||||
let name = match str::from_utf8(name_vec) {
|
||||
@ -95,7 +94,7 @@ pub fn entrypoint(
|
||||
return Err(InstructionError::GenericError);
|
||||
}
|
||||
};
|
||||
let ret = entrypoint(program_id, params, ix_data, tick_height);
|
||||
let ret = entrypoint(program_id, params, ix_data);
|
||||
symbol_cache
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -70,7 +70,6 @@ pub fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
data: &[u8],
|
||||
_tick_height: u64,
|
||||
) -> Result<(), InstructionError> {
|
||||
if let Ok(instruction) = bincode::deserialize(data) {
|
||||
trace!("process_instruction: {:?}", instruction);
|
||||
@ -246,7 +245,7 @@ mod tests {
|
||||
program_id: another_program_owner,
|
||||
};
|
||||
let data = serialize(&instruction).unwrap();
|
||||
let result = process_instruction(&system_program::id(), &mut keyed_accounts, &data, 0);
|
||||
let result = process_instruction(&system_program::id(), &mut keyed_accounts, &data);
|
||||
assert_eq!(result, Err(InstructionError::IncorrectProgramId));
|
||||
assert_eq!(from_account.owner, new_program_owner);
|
||||
}
|
||||
|
Reference in New Issue
Block a user