Simd 47 syscall sysvar last restart slot (#31957)
* add sysvar and logic for last restart slot * cleanup * add test for getting last restart slot from account * format code * add some basic rustdoc * copy+paste error * feature flag for last_restart_slot * add to sysvars.md * updated wording in sysvars.md * rename sol_get_last_restart_slot_sysvar > sol_get_last_restart_slot * create sbf C header for sol_get_last_restart_slot * cleanup imports * reverted hardened_unpack workaround * cleanup imports * cleanup logs + blank lines * Implementing ui changes for last restart slot, nit * Some more nit change and implementing the UI for sysvar * fixing the CI * Minor clippy fix * format changes * changes suggested by mvines and lichtso * increase timeout in local_cluster test * fix code format * use keypair for feature flag from mvines * delete test.json file * Revert "increase timeout in local_cluster test" This reverts commit a67465ae225186be5ebaa46badfe44ecac6d76a8. * last restart slot should be always less than or equal to current slot * fixing bug * changes after steviez comments * format issue fixed * fixing the comment on premature application of future hardfork * nit change in test Co-authored-by: steviez <steven@solana.com> * reverting sysvar_cache.rs because change was not necessary --------- Co-authored-by: steve-gg <grooviegermanikus@gmail.com> Co-authored-by: steviez <steven@solana.com>
This commit is contained in:
parent
987e8eeeaf
commit
2ceabd9368
|
@ -15,7 +15,7 @@ use {
|
|||
slot_hashes::SlotHashes,
|
||||
slot_history::{self, SlotHistory},
|
||||
stake_history::{StakeHistory, StakeHistoryEntry},
|
||||
sysvar::{self, rewards::Rewards},
|
||||
sysvar::{self, last_restart_slot::LastRestartSlot, rewards::Rewards},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -82,6 +82,13 @@ pub fn parse_sysvar(data: &[u8], pubkey: &Pubkey) -> Result<SysvarAccountType, P
|
|||
.collect();
|
||||
SysvarAccountType::StakeHistory(stake_history)
|
||||
})
|
||||
} else if pubkey == &sysvar::last_restart_slot::id() {
|
||||
deserialize::<LastRestartSlot>(data)
|
||||
.ok()
|
||||
.map(|last_restart_slot| {
|
||||
let last_restart_slot = last_restart_slot.last_restart_slot;
|
||||
SysvarAccountType::LastRestartSlot(UiLastRestartSlot { last_restart_slot })
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -105,6 +112,7 @@ pub enum SysvarAccountType {
|
|||
SlotHashes(Vec<UiSlotHashEntry>),
|
||||
SlotHistory(UiSlotHistory),
|
||||
StakeHistory(Vec<UiStakeHistoryEntry>),
|
||||
LastRestartSlot(UiLastRestartSlot),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
|
||||
|
@ -218,6 +226,12 @@ pub struct UiStakeHistoryEntry {
|
|||
pub stake_history: StakeHistoryEntry,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UiLastRestartSlot {
|
||||
pub last_restart_slot: Slot,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[allow(deprecated)]
|
||||
|
@ -334,5 +348,20 @@ mod test {
|
|||
|
||||
let bad_data = vec![0; 4];
|
||||
assert!(parse_sysvar(&bad_data, &sysvar::stake_history::id()).is_err());
|
||||
|
||||
let last_restart_slot = LastRestartSlot {
|
||||
last_restart_slot: 1282,
|
||||
};
|
||||
let last_restart_slot_account = create_account_for_test(&last_restart_slot);
|
||||
assert_eq!(
|
||||
parse_sysvar(
|
||||
&last_restart_slot_account.data,
|
||||
&sysvar::last_restart_slot::id()
|
||||
)
|
||||
.unwrap(),
|
||||
SysvarAccountType::LastRestartSlot(UiLastRestartSlot {
|
||||
last_restart_slot: 1282
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,4 +155,12 @@ determining whether epoch rewards distribution has finished.
|
|||
|
||||
- Address: `SysvarEpochRewards1111111111111111111111111`
|
||||
- Layout:
|
||||
[EpochRewards](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/epoch_rewards/struct.EpochRewards.html)
|
||||
[EpochRewards](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/epoch_rewards/struct.EpochRewards.html)
|
||||
|
||||
## LastRestartSlot
|
||||
|
||||
The LastRestartSlot sysvar contains the slot number of the last restart or _0_ (zero) if none ever happened.
|
||||
|
||||
- Address: `SysvarLastRestartS1ot1111111111111111111111`
|
||||
- Layout:
|
||||
[LastRestartSlot](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/last_restart_slot/struct.LastRestartSlot.html)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#[allow(deprecated)]
|
||||
use solana_sdk::sysvar::{fees::Fees, recent_blockhashes::RecentBlockhashes};
|
||||
use solana_sdk::sysvar::{
|
||||
fees::Fees, last_restart_slot::LastRestartSlot, recent_blockhashes::RecentBlockhashes,
|
||||
};
|
||||
use {
|
||||
crate::invoke_context::InvokeContext,
|
||||
solana_sdk::{
|
||||
|
@ -33,6 +35,7 @@ pub struct SysvarCache {
|
|||
#[allow(deprecated)]
|
||||
recent_blockhashes: Option<Arc<RecentBlockhashes>>,
|
||||
stake_history: Option<Arc<StakeHistory>>,
|
||||
last_restart_slot: Option<Arc<LastRestartSlot>>,
|
||||
}
|
||||
|
||||
impl SysvarCache {
|
||||
|
@ -76,6 +79,16 @@ impl SysvarCache {
|
|||
self.rent = Some(Arc::new(rent));
|
||||
}
|
||||
|
||||
pub fn get_last_restart_slot(&self) -> Result<Arc<LastRestartSlot>, InstructionError> {
|
||||
self.last_restart_slot
|
||||
.clone()
|
||||
.ok_or(InstructionError::UnsupportedSysvar)
|
||||
}
|
||||
|
||||
pub fn set_last_restart_slot(&mut self, last_restart_slot: LastRestartSlot) {
|
||||
self.last_restart_slot = Some(Arc::new(last_restart_slot));
|
||||
}
|
||||
|
||||
pub fn get_slot_hashes(&self) -> Result<Arc<SlotHashes>, InstructionError> {
|
||||
self.slot_hashes
|
||||
.clone()
|
||||
|
@ -165,6 +178,13 @@ impl SysvarCache {
|
|||
}
|
||||
});
|
||||
}
|
||||
if self.last_restart_slot.is_none() {
|
||||
get_account_data(&LastRestartSlot::id(), &mut |data: &[u8]| {
|
||||
if let Ok(last_restart_slot) = bincode::deserialize(data) {
|
||||
self.set_last_restart_slot(last_restart_slot);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
|
@ -258,4 +278,17 @@ pub mod get_sysvar_with_account_check {
|
|||
)?;
|
||||
invoke_context.get_sysvar_cache().get_stake_history()
|
||||
}
|
||||
|
||||
pub fn last_restart_slot(
|
||||
invoke_context: &InvokeContext,
|
||||
instruction_context: &InstructionContext,
|
||||
instruction_account_index: IndexOfAccount,
|
||||
) -> Result<Arc<LastRestartSlot>, InstructionError> {
|
||||
check_sysvar_account::<LastRestartSlot>(
|
||||
invoke_context.transaction_context,
|
||||
instruction_context,
|
||||
instruction_account_index,
|
||||
)?;
|
||||
invoke_context.get_sysvar_cache().get_last_restart_slot()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,6 +371,15 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
|||
get_sysvar(get_invoke_context().get_sysvar_cache().get_rent(), var_addr)
|
||||
}
|
||||
|
||||
fn sol_get_last_restart_slot(&self, var_addr: *mut u8) -> u64 {
|
||||
get_sysvar(
|
||||
get_invoke_context()
|
||||
.get_sysvar_cache()
|
||||
.get_last_restart_slot(),
|
||||
var_addr,
|
||||
)
|
||||
}
|
||||
|
||||
fn sol_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
|
||||
let (program_id, data) = get_invoke_context().transaction_context.get_return_data();
|
||||
Some((*program_id, data.to_vec()))
|
||||
|
@ -1162,4 +1171,12 @@ impl ProgramTestContext {
|
|||
self.last_blockhash = blockhash;
|
||||
Ok(blockhash)
|
||||
}
|
||||
|
||||
/// record a hard fork slot in working bank; should be in the past
|
||||
pub fn register_hard_fork(&mut self, hard_fork_slot: Slot) {
|
||||
let bank_forks = self.bank_forks.write().unwrap();
|
||||
let hard_forks = bank_forks.working_bank().hard_forks();
|
||||
let mut write = hard_forks.write().unwrap();
|
||||
write.register(hard_fork_slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
use {
|
||||
solana_program_test::{processor, ProgramTest, ProgramTestContext},
|
||||
solana_sdk::{
|
||||
account_info::AccountInfo,
|
||||
clock::Slot,
|
||||
entrypoint::ProgramResult,
|
||||
instruction::{AccountMeta, Instruction},
|
||||
msg,
|
||||
pubkey::Pubkey,
|
||||
signature::Signer,
|
||||
sysvar::{last_restart_slot, last_restart_slot::LastRestartSlot, Sysvar},
|
||||
transaction::Transaction,
|
||||
},
|
||||
};
|
||||
|
||||
// program to check both syscall and sysvar
|
||||
fn sysvar_last_restart_slot_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
input: &[u8],
|
||||
) -> ProgramResult {
|
||||
msg!("sysvar_last_restart_slot");
|
||||
assert_eq!(input.len(), 8);
|
||||
let expected_last_hardfork_slot = u64::from_le_bytes(input[0..8].try_into().unwrap());
|
||||
|
||||
let last_restart_slot = LastRestartSlot::get();
|
||||
msg!("last restart slot: {:?}", last_restart_slot);
|
||||
assert_eq!(
|
||||
last_restart_slot,
|
||||
Ok(LastRestartSlot {
|
||||
last_restart_slot: expected_last_hardfork_slot
|
||||
})
|
||||
);
|
||||
|
||||
let last_restart_slot_account = &accounts[0];
|
||||
let slot_via_account = LastRestartSlot::from_account_info(last_restart_slot_account)?;
|
||||
msg!("slot via account: {:?}", slot_via_account);
|
||||
|
||||
assert_eq!(
|
||||
slot_via_account,
|
||||
LastRestartSlot {
|
||||
last_restart_slot: expected_last_hardfork_slot
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_with_program(
|
||||
context: &mut ProgramTestContext,
|
||||
program_id: Pubkey,
|
||||
expected_last_restart_slot: u64,
|
||||
) {
|
||||
let instructions = vec![Instruction::new_with_bincode(
|
||||
program_id,
|
||||
&expected_last_restart_slot.to_le_bytes(),
|
||||
vec![AccountMeta::new(last_restart_slot::id(), false)],
|
||||
)];
|
||||
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
&instructions,
|
||||
Some(&context.payer.pubkey()),
|
||||
&[&context.payer],
|
||||
context.last_blockhash,
|
||||
);
|
||||
|
||||
context
|
||||
.banks_client
|
||||
.process_transaction(transaction)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_sysvar_last_restart_slot() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_test = ProgramTest::new(
|
||||
"sysvar_last_restart_slot_process",
|
||||
program_id,
|
||||
processor!(sysvar_last_restart_slot_process_instruction),
|
||||
);
|
||||
|
||||
let mut context = program_test.start_with_context().await;
|
||||
|
||||
check_with_program(&mut context, program_id, 0).await;
|
||||
context.warp_to_slot(40).unwrap();
|
||||
context.register_hard_fork(41 as Slot);
|
||||
check_with_program(&mut context, program_id, 0).await;
|
||||
context.warp_to_slot(41).unwrap();
|
||||
check_with_program(&mut context, program_id, 41).await;
|
||||
// check for value lower than previous hardfork
|
||||
context.register_hard_fork(40 as Slot);
|
||||
context.warp_to_slot(45).unwrap();
|
||||
check_with_program(&mut context, program_id, 41).await;
|
||||
context.register_hard_fork(43 as Slot);
|
||||
context.register_hard_fork(47 as Slot);
|
||||
context.warp_to_slot(46).unwrap();
|
||||
check_with_program(&mut context, program_id, 43).await;
|
||||
context.register_hard_fork(50 as Slot);
|
||||
context.warp_to_slot(48).unwrap();
|
||||
check_with_program(&mut context, program_id, 47).await;
|
||||
context.warp_to_slot(50).unwrap();
|
||||
check_with_program(&mut context, program_id, 50).await;
|
||||
}
|
|
@ -6,7 +6,7 @@ pub use self::{
|
|||
mem_ops::{SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
|
||||
sysvar::{
|
||||
SyscallGetClockSysvar, SyscallGetEpochScheduleSysvar, SyscallGetFeesSysvar,
|
||||
SyscallGetRentSysvar,
|
||||
SyscallGetLastRestartSlotSysvar, SyscallGetRentSysvar,
|
||||
},
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
|
@ -37,9 +37,10 @@ use {
|
|||
disable_cpi_setting_executable_and_rent_epoch, disable_deploy_of_alloc_free_syscall,
|
||||
disable_fees_sysvar, enable_alt_bn128_syscall, enable_big_mod_exp_syscall,
|
||||
enable_early_verification_of_account_modifications,
|
||||
error_on_syscall_bpf_function_hash_collisions, libsecp256k1_0_5_upgrade_enabled,
|
||||
reject_callx_r10, stop_sibling_instruction_search_at_parent,
|
||||
stop_truncating_strings_in_syscalls, switch_to_new_elf_parser,
|
||||
error_on_syscall_bpf_function_hash_collisions, last_restart_slot_sysvar,
|
||||
libsecp256k1_0_5_upgrade_enabled, reject_callx_r10,
|
||||
stop_sibling_instruction_search_at_parent, stop_truncating_strings_in_syscalls,
|
||||
switch_to_new_elf_parser,
|
||||
},
|
||||
hash::{Hasher, HASH_BYTES},
|
||||
instruction::{
|
||||
|
@ -187,6 +188,7 @@ pub fn create_program_runtime_environment<'a>(
|
|||
let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id());
|
||||
let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs
|
||||
&& feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id());
|
||||
let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id());
|
||||
|
||||
let mut result = BuiltinProgram::new_loader(config);
|
||||
|
||||
|
@ -263,6 +265,13 @@ pub fn create_program_runtime_environment<'a>(
|
|||
)?;
|
||||
result.register_function(b"sol_get_rent_sysvar", SyscallGetRentSysvar::call)?;
|
||||
|
||||
register_feature_gated_function!(
|
||||
result,
|
||||
last_restart_slot_syscall_enabled,
|
||||
b"sol_get_last_restart_slot",
|
||||
SyscallGetLastRestartSlotSysvar::call,
|
||||
)?;
|
||||
|
||||
// Memory ops
|
||||
result.register_function(b"sol_memcpy_", SyscallMemcpy::call)?;
|
||||
result.register_function(b"sol_memmove_", SyscallMemmove::call)?;
|
||||
|
|
|
@ -112,3 +112,25 @@ declare_syscall!(
|
|||
)
|
||||
}
|
||||
);
|
||||
|
||||
declare_syscall!(
|
||||
/// Get a Last Restart Slot sysvar
|
||||
SyscallGetLastRestartSlotSysvar,
|
||||
fn inner_call(
|
||||
invoke_context: &mut InvokeContext,
|
||||
var_addr: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &mut MemoryMapping,
|
||||
) -> Result<u64, Error> {
|
||||
get_sysvar(
|
||||
invoke_context.get_sysvar_cache().get_last_restart_slot(),
|
||||
var_addr,
|
||||
invoke_context.get_check_aligned(),
|
||||
memory_mapping,
|
||||
invoke_context,
|
||||
)
|
||||
}
|
||||
);
|
||||
|
|
|
@ -156,7 +156,7 @@ use {
|
|||
slot_history::{Check, SlotHistory},
|
||||
stake::state::Delegation,
|
||||
system_transaction,
|
||||
sysvar::{self, Sysvar, SysvarId},
|
||||
sysvar::{self, last_restart_slot::LastRestartSlot, Sysvar, SysvarId},
|
||||
timing::years_as_slots,
|
||||
transaction::{
|
||||
self, MessageHash, Result, SanitizedTransaction, Transaction, TransactionError,
|
||||
|
@ -1447,6 +1447,7 @@ impl Bank {
|
|||
bank.update_rent();
|
||||
bank.update_epoch_schedule();
|
||||
bank.update_recent_blockhashes();
|
||||
bank.update_last_restart_slot();
|
||||
bank.fill_missing_sysvar_cache_entries();
|
||||
bank
|
||||
}
|
||||
|
@ -1744,6 +1745,7 @@ impl Bank {
|
|||
new.update_stake_history(Some(parent_epoch));
|
||||
new.update_clock(Some(parent_epoch));
|
||||
new.update_fees();
|
||||
new.update_last_restart_slot()
|
||||
});
|
||||
|
||||
let (_, fill_sysvar_cache_time_us) = measure_us!(new.fill_missing_sysvar_cache_entries());
|
||||
|
@ -2415,6 +2417,35 @@ impl Bank {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn update_last_restart_slot(&self) {
|
||||
let feature_flag = self
|
||||
.feature_set
|
||||
.is_active(&feature_set::last_restart_slot_sysvar::id());
|
||||
|
||||
if feature_flag {
|
||||
let last_restart_slot = {
|
||||
let slot = self.slot;
|
||||
let hard_forks = self.hard_forks();
|
||||
let hard_forks_r = hard_forks.read().unwrap();
|
||||
|
||||
// Only consider hard forks <= this bank's slot to avoid prematurely applying
|
||||
// a hard fork that is set to occur in the future.
|
||||
hard_forks_r
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(hard_fork, _)| *hard_fork <= slot)
|
||||
.map(|(slot, _)| *slot)
|
||||
.unwrap_or(0)
|
||||
};
|
||||
self.update_sysvar_account(&sysvar::last_restart_slot::id(), |account| {
|
||||
create_account(
|
||||
&LastRestartSlot { last_restart_slot },
|
||||
self.inherit_specially_retained_account_fields(account),
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_sysvar_for_tests<T>(&self, sysvar: &T)
|
||||
where
|
||||
T: Sysvar + SysvarId,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//! Information about the last restart slot (hard fork).
|
||||
|
||||
use {crate::clock::Slot, solana_sdk_macro::CloneZeroed};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Debug, CloneZeroed, PartialEq, Eq, Default)]
|
||||
pub struct LastRestartSlot {
|
||||
/// The last restart `Slot`.
|
||||
pub last_restart_slot: Slot,
|
||||
}
|
|
@ -495,6 +495,7 @@ pub mod incinerator;
|
|||
pub mod instruction;
|
||||
pub mod keccak;
|
||||
pub mod lamports;
|
||||
pub mod last_restart_slot;
|
||||
pub mod loader_instruction;
|
||||
pub mod loader_upgradeable_instruction;
|
||||
pub mod loader_v4;
|
||||
|
|
|
@ -54,7 +54,9 @@ pub trait SyscallStubs: Sync + Send {
|
|||
fn sol_get_epoch_rewards_sysvar(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
|
||||
fn sol_get_last_restart_slot(&self, _var_addr: *mut u8) -> u64 {
|
||||
UNSUPPORTED_SYSVAR
|
||||
}
|
||||
/// # Safety
|
||||
unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
|
||||
// cannot be overlapping
|
||||
|
@ -154,6 +156,13 @@ pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
|
|||
SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_get_last_restart_slot(var_addr: *mut u8) -> u64 {
|
||||
SYSCALL_STUBS
|
||||
.read()
|
||||
.unwrap()
|
||||
.sol_get_last_restart_slot(var_addr)
|
||||
}
|
||||
|
||||
pub(crate) fn sol_memcpy(dst: *mut u8, src: *const u8, n: usize) {
|
||||
unsafe {
|
||||
SYSCALL_STUBS.read().unwrap().sol_memcpy(dst, src, n);
|
||||
|
|
|
@ -50,6 +50,7 @@ define_syscall!(fn sol_get_clock_sysvar(addr: *mut u8) -> u64);
|
|||
define_syscall!(fn sol_get_epoch_schedule_sysvar(addr: *mut u8) -> u64);
|
||||
define_syscall!(fn sol_get_fees_sysvar(addr: *mut u8) -> u64);
|
||||
define_syscall!(fn sol_get_rent_sysvar(addr: *mut u8) -> u64);
|
||||
define_syscall!(fn sol_get_last_restart_slot(addr: *mut u8) -> u64);
|
||||
define_syscall!(fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64));
|
||||
define_syscall!(fn sol_memmove_(dst: *mut u8, src: *const u8, n: u64));
|
||||
define_syscall!(fn sol_memcmp_(s1: *const u8, s2: *const u8, n: u64, result: *mut i32));
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//! Information about the last restart slot (hard fork).
|
||||
//!
|
||||
//! The _last restart sysvar_ provides access to the last restart slot kept in the
|
||||
//! bank fork for the slot on the fork that executes the current transaction.
|
||||
//! In case there was no fork it returns _0_.
|
||||
//!
|
||||
//! [`LastRestartSlot`] implements [`Sysvar::get`] and can be loaded efficiently without
|
||||
//! passing the sysvar account ID to the program.
|
||||
//!
|
||||
//! See also the Solana [SIMD proposal][simd].
|
||||
//!
|
||||
//! [simd]: https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0047-syscall-and-sysvar-for-last-restart-slot.md
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Accessing via on-chain program directly:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use solana_program::{
|
||||
//! # account_info::{AccountInfo, next_account_info},
|
||||
//! # entrypoint::ProgramResult,
|
||||
//! # msg,
|
||||
//! # pubkey::Pubkey,
|
||||
//! # sysvar::Sysvar,
|
||||
//! # last_restart_slot::LastRestartSlot,
|
||||
//! # };
|
||||
//!
|
||||
//! fn process_instruction(
|
||||
//! program_id: &Pubkey,
|
||||
//! accounts: &[AccountInfo],
|
||||
//! instruction_data: &[u8],
|
||||
//! ) -> ProgramResult {
|
||||
//!
|
||||
//! let last_restart_slot = LastRestartSlot::get();
|
||||
//! msg!("last restart slot: {:?}", last_restart_slot);
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
||||
pub use crate::last_restart_slot::LastRestartSlot;
|
||||
use crate::{impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar};
|
||||
|
||||
crate::declare_sysvar_id!(
|
||||
"SysvarLastRestartS1ot1111111111111111111111",
|
||||
LastRestartSlot
|
||||
);
|
||||
|
||||
impl Sysvar for LastRestartSlot {
|
||||
impl_sysvar_get!(sol_get_last_restart_slot);
|
||||
}
|
|
@ -91,6 +91,7 @@ pub mod epoch_rewards;
|
|||
pub mod epoch_schedule;
|
||||
pub mod fees;
|
||||
pub mod instructions;
|
||||
pub mod last_restart_slot;
|
||||
pub mod recent_blockhashes;
|
||||
pub mod rent;
|
||||
pub mod rewards;
|
||||
|
@ -113,6 +114,7 @@ lazy_static! {
|
|||
stake_history::id(),
|
||||
instructions::id(),
|
||||
epoch_rewards::id(),
|
||||
last_restart_slot::id(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
/**
|
||||
* @brief Solana Last Restart Slot system call
|
||||
*/
|
||||
|
||||
#include <sol/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get Last Restart Slot
|
||||
*/
|
||||
@SYSCALL u64 sol_get_last_restart_slot(uint8_t *result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@}*/
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
/**
|
||||
* @brief Solana Last Restart Slot system call
|
||||
*/
|
||||
|
||||
#include <sol/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get Last Restart Slot
|
||||
*/
|
||||
/* DO NOT MODIFY THIS GENERATED FILE. INSTEAD CHANGE sdk/sbf/c/inc/sol/inc/last_restart_slot.inc AND RUN `cargo run --bin gen-headers` */
|
||||
#ifndef SOL_SBFV2
|
||||
u64 sol_get_last_restart_slot(uint8_t *result);
|
||||
#else
|
||||
typedef u64(*sol_get_last_restart_slot_pointer_type)(uint8_t *result);
|
||||
static u64 sol_get_last_restart_slot(uint8_t *result arg1) {
|
||||
sol_get_last_restart_slot_pointer_type sol_get_last_restart_slot_pointer = (sol_get_last_restart_slot_pointer_type) 411697201;
|
||||
return sol_get_last_restart_slot_pointer(arg1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@}*/
|
|
@ -668,6 +668,10 @@ pub mod checked_arithmetic_in_fee_validation {
|
|||
solana_sdk::declare_id!("5Pecy6ie6XGm22pc9d4P9W5c31BugcFBuy6hsP2zkETv");
|
||||
}
|
||||
|
||||
pub mod last_restart_slot_sysvar {
|
||||
solana_sdk::declare_id!("HooKD5NC9QNxk25QuzCssB8ecrEzGt6eXEPBUxWp1LaR");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -830,6 +834,7 @@ lazy_static! {
|
|||
(vote_state_add_vote_latency::id(), "replace Lockout with LandedVote (including vote latency) in vote state #31264"),
|
||||
(checked_arithmetic_in_fee_validation::id(), "checked arithmetic in fee validation #31273"),
|
||||
(bpf_account_data_direct_mapping::id(), "use memory regions to map account data into the rbpf vm instead of copying the data"),
|
||||
(last_restart_slot_sysvar::id(), "enable new sysvar last_restart_slot"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue