Refactor - derive `CloneZeroed` (#28771)
* Adds proc_macro_derive(CloneZeroed). * Switches over all use sites of clone_zeroed() and copy_field(). * Removes clone_zeroed() and copy_field(). Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
This commit is contained in:
parent
43e5c188c2
commit
93fc4edef8
|
@ -405,3 +405,38 @@ pub fn wasm_bindgen_stub(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets padding in structures to zero explicitly.
|
||||||
|
// Otherwise padding could be inconsistent across the network and lead to divergence / consensus failures.
|
||||||
|
#[proc_macro_derive(CloneZeroed)]
|
||||||
|
pub fn derive_clone_zeroed(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
match parse_macro_input!(input as syn::Item) {
|
||||||
|
syn::Item::Struct(item_struct) => {
|
||||||
|
let clone_statements = match item_struct.fields {
|
||||||
|
syn::Fields::Named(ref fields) => fields.named.iter().map(|f| {
|
||||||
|
let name = &f.ident;
|
||||||
|
quote! {
|
||||||
|
std::ptr::addr_of_mut!((*ptr).#name).write(self.#name);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
let name = &item_struct.ident;
|
||||||
|
quote! {
|
||||||
|
impl Clone for #name {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let mut value = std::mem::MaybeUninit::<Self>::uninit();
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write_bytes(&mut value, 0, 1);
|
||||||
|
let ptr = value.as_mut_ptr();
|
||||||
|
#(#clone_statements)*
|
||||||
|
value.assume_init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
|
@ -20,10 +20,7 @@
|
||||||
//!
|
//!
|
||||||
//! [oracle]: https://docs.solana.com/implemented-proposals/validator-timestamp-oracle
|
//! [oracle]: https://docs.solana.com/implemented-proposals/validator-timestamp-oracle
|
||||||
|
|
||||||
use {
|
use solana_sdk_macro::CloneZeroed;
|
||||||
crate::{clone_zeroed, copy_field},
|
|
||||||
std::mem::MaybeUninit,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The default tick rate that the cluster attempts to achieve (160 per second).
|
/// The default tick rate that the cluster attempts to achieve (160 per second).
|
||||||
///
|
///
|
||||||
|
@ -147,7 +144,7 @@ pub type UnixTimestamp = i64;
|
||||||
///
|
///
|
||||||
/// All members of `Clock` start from 0 upon network boot.
|
/// All members of `Clock` start from 0 upon network boot.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, CloneZeroed, Default, PartialEq, Eq)]
|
||||||
pub struct Clock {
|
pub struct Clock {
|
||||||
/// The current `Slot`.
|
/// The current `Slot`.
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
|
@ -170,21 +167,6 @@ pub struct Clock {
|
||||||
pub unix_timestamp: UnixTimestamp,
|
pub unix_timestamp: UnixTimestamp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Clock {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
clone_zeroed(|cloned: &mut MaybeUninit<Self>| {
|
|
||||||
let ptr = cloned.as_mut_ptr();
|
|
||||||
unsafe {
|
|
||||||
copy_field!(ptr, self, slot);
|
|
||||||
copy_field!(ptr, self, epoch_start_timestamp);
|
|
||||||
copy_field!(ptr, self, epoch);
|
|
||||||
copy_field!(ptr, self, leader_schedule_epoch);
|
|
||||||
copy_field!(ptr, self, unix_timestamp);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -12,10 +12,7 @@
|
||||||
//! epochs increasing in slots until they last for [`DEFAULT_SLOTS_PER_EPOCH`].
|
//! epochs increasing in slots until they last for [`DEFAULT_SLOTS_PER_EPOCH`].
|
||||||
|
|
||||||
pub use crate::clock::{Epoch, Slot, DEFAULT_SLOTS_PER_EPOCH};
|
pub use crate::clock::{Epoch, Slot, DEFAULT_SLOTS_PER_EPOCH};
|
||||||
use {
|
use solana_sdk_macro::CloneZeroed;
|
||||||
crate::{clone_zeroed, copy_field},
|
|
||||||
std::mem::MaybeUninit,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The default number of slots before an epoch starts to calculate the leader schedule.
|
/// The default number of slots before an epoch starts to calculate the leader schedule.
|
||||||
pub const DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET: u64 = DEFAULT_SLOTS_PER_EPOCH;
|
pub const DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET: u64 = DEFAULT_SLOTS_PER_EPOCH;
|
||||||
|
@ -32,7 +29,7 @@ pub const MAX_LEADER_SCHEDULE_EPOCH_OFFSET: u64 = 3;
|
||||||
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
|
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, PartialEq, Eq, Deserialize, Serialize, AbiExample)]
|
#[derive(Debug, CloneZeroed, Copy, PartialEq, Eq, Deserialize, Serialize, AbiExample)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct EpochSchedule {
|
pub struct EpochSchedule {
|
||||||
/// The maximum number of slots in each epoch.
|
/// The maximum number of slots in each epoch.
|
||||||
|
@ -66,21 +63,6 @@ impl Default for EpochSchedule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for EpochSchedule {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
clone_zeroed(|cloned: &mut MaybeUninit<Self>| {
|
|
||||||
let ptr = cloned.as_mut_ptr();
|
|
||||||
unsafe {
|
|
||||||
copy_field!(ptr, self, slots_per_epoch);
|
|
||||||
copy_field!(ptr, self, leader_schedule_slot_offset);
|
|
||||||
copy_field!(ptr, self, warmup);
|
|
||||||
copy_field!(ptr, self, first_normal_epoch);
|
|
||||||
copy_field!(ptr, self, first_normal_slot);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EpochSchedule {
|
impl EpochSchedule {
|
||||||
pub fn new(slots_per_epoch: u64) -> Self {
|
pub fn new(slots_per_epoch: u64) -> Self {
|
||||||
Self::custom(slots_per_epoch, slots_per_epoch, true)
|
Self::custom(slots_per_epoch, slots_per_epoch, true)
|
||||||
|
|
|
@ -742,25 +742,6 @@ macro_rules! unchecked_div_by_const {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::{mem::MaybeUninit, ptr::write_bytes};
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! copy_field {
|
|
||||||
($ptr:expr, $self:ident, $field:ident) => {
|
|
||||||
std::ptr::addr_of_mut!((*$ptr).$field).write($self.$field)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_zeroed<T, F>(clone: F) -> T
|
|
||||||
where
|
|
||||||
F: Fn(&mut MaybeUninit<T>),
|
|
||||||
{
|
|
||||||
let mut value = MaybeUninit::<T>::uninit();
|
|
||||||
unsafe { write_bytes(&mut value, 0, 1) }
|
|
||||||
clone(&mut value);
|
|
||||||
unsafe { value.assume_init() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// This module is purposefully listed after all other exports: because of an
|
// This module is purposefully listed after all other exports: because of an
|
||||||
// interaction within rustdoc between the reexports inside this module of
|
// interaction within rustdoc between the reexports inside this module of
|
||||||
// `solana_program`'s top-level modules, and `solana_sdk`'s glob re-export of
|
// `solana_program`'s top-level modules, and `solana_sdk`'s glob re-export of
|
||||||
|
|
|
@ -4,14 +4,11 @@
|
||||||
|
|
||||||
#![allow(clippy::integer_arithmetic)]
|
#![allow(clippy::integer_arithmetic)]
|
||||||
|
|
||||||
use {
|
use {crate::clock::DEFAULT_SLOTS_PER_EPOCH, solana_sdk_macro::CloneZeroed};
|
||||||
crate::{clock::DEFAULT_SLOTS_PER_EPOCH, clone_zeroed, copy_field},
|
|
||||||
std::mem::MaybeUninit,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Configuration of network rent.
|
/// Configuration of network rent.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Copy, Debug, AbiExample)]
|
#[derive(Serialize, Deserialize, PartialEq, CloneZeroed, Copy, Debug, AbiExample)]
|
||||||
pub struct Rent {
|
pub struct Rent {
|
||||||
/// Rental rate in lamports/byte-year.
|
/// Rental rate in lamports/byte-year.
|
||||||
pub lamports_per_byte_year: u64,
|
pub lamports_per_byte_year: u64,
|
||||||
|
@ -62,19 +59,6 @@ impl Default for Rent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Rent {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
clone_zeroed(|cloned: &mut MaybeUninit<Self>| {
|
|
||||||
let ptr = cloned.as_mut_ptr();
|
|
||||||
unsafe {
|
|
||||||
copy_field!(ptr, self, lamports_per_byte_year);
|
|
||||||
copy_field!(ptr, self, exemption_threshold);
|
|
||||||
copy_field!(ptr, self, burn_percent);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rent {
|
impl Rent {
|
||||||
/// Calculate how much rent to burn from the collected rent.
|
/// Calculate how much rent to burn from the collected rent.
|
||||||
///
|
///
|
||||||
|
|
|
@ -22,10 +22,9 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
clone_zeroed, copy_field, fee_calculator::FeeCalculator, impl_sysvar_get,
|
fee_calculator::FeeCalculator, impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar,
|
||||||
program_error::ProgramError, sysvar::Sysvar,
|
|
||||||
},
|
},
|
||||||
std::mem::MaybeUninit,
|
solana_sdk_macro::CloneZeroed,
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::declare_deprecated_sysvar_id!("SysvarFees111111111111111111111111111111111", Fees);
|
crate::declare_deprecated_sysvar_id!("SysvarFees111111111111111111111111111111111", Fees);
|
||||||
|
@ -36,22 +35,11 @@ crate::declare_deprecated_sysvar_id!("SysvarFees11111111111111111111111111111111
|
||||||
note = "Please do not use, will no longer be available in the future"
|
note = "Please do not use, will no longer be available in the future"
|
||||||
)]
|
)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, CloneZeroed, Default, PartialEq, Eq)]
|
||||||
pub struct Fees {
|
pub struct Fees {
|
||||||
pub fee_calculator: FeeCalculator,
|
pub fee_calculator: FeeCalculator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Fees {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
clone_zeroed(|cloned: &mut MaybeUninit<Self>| {
|
|
||||||
let ptr = cloned.as_mut_ptr();
|
|
||||||
unsafe {
|
|
||||||
copy_field!(ptr, self, fee_calculator);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fees {
|
impl Fees {
|
||||||
pub fn new(fee_calculator: &FeeCalculator) -> Self {
|
pub fn new(fee_calculator: &FeeCalculator) -> Self {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
|
|
@ -13,11 +13,11 @@ pub use signer::signers;
|
||||||
pub use solana_program::program_stubs;
|
pub use solana_program::program_stubs;
|
||||||
pub use solana_program::{
|
pub use solana_program::{
|
||||||
account_info, address_lookup_table_account, blake3, borsh, bpf_loader, bpf_loader_deprecated,
|
account_info, address_lookup_table_account, blake3, borsh, bpf_loader, bpf_loader_deprecated,
|
||||||
bpf_loader_upgradeable, clock, clone_zeroed, config, copy_field, custom_heap_default,
|
bpf_loader_upgradeable, clock, config, custom_heap_default, custom_panic_default,
|
||||||
custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id,
|
debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id, decode_error,
|
||||||
decode_error, ed25519_program, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator,
|
ed25519_program, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator, instruction,
|
||||||
instruction, keccak, lamports, loader_instruction, loader_upgradeable_instruction, message,
|
keccak, lamports, loader_instruction, loader_upgradeable_instruction, message, msg,
|
||||||
msg, native_token, nonce, program, program_error, program_memory, program_option, program_pack,
|
native_token, nonce, program, program_error, program_memory, program_option, program_pack,
|
||||||
rent, sanitize, sdk_ids, secp256k1_program, secp256k1_recover, serialize_utils, short_vec,
|
rent, sanitize, sdk_ids, secp256k1_program, secp256k1_recover, serialize_utils, short_vec,
|
||||||
slot_hashes, slot_history, stake, stake_history, syscalls, system_instruction, system_program,
|
slot_hashes, slot_history, stake, stake_history, syscalls, system_instruction, system_program,
|
||||||
sysvar, unchecked_div_by_const, vote, wasm_bindgen,
|
sysvar, unchecked_div_by_const, vote, wasm_bindgen,
|
||||||
|
|
Loading…
Reference in New Issue