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()
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
use {
|
||||
crate::{clone_zeroed, copy_field},
|
||||
std::mem::MaybeUninit,
|
||||
};
|
||||
use solana_sdk_macro::CloneZeroed;
|
||||
|
||||
/// 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.
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, CloneZeroed, Default, PartialEq, Eq)]
|
||||
pub struct Clock {
|
||||
/// The current `Slot`.
|
||||
pub slot: Slot,
|
||||
|
@ -170,21 +167,6 @@ pub struct Clock {
|
|||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
//! epochs increasing in slots until they last for [`DEFAULT_SLOTS_PER_EPOCH`].
|
||||
|
||||
pub use crate::clock::{Epoch, Slot, DEFAULT_SLOTS_PER_EPOCH};
|
||||
use {
|
||||
crate::{clone_zeroed, copy_field},
|
||||
std::mem::MaybeUninit,
|
||||
};
|
||||
use solana_sdk_macro::CloneZeroed;
|
||||
|
||||
/// 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;
|
||||
|
@ -32,7 +29,7 @@ pub const MAX_LEADER_SCHEDULE_EPOCH_OFFSET: u64 = 3;
|
|||
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, PartialEq, Eq, Deserialize, Serialize, AbiExample)]
|
||||
#[derive(Debug, CloneZeroed, Copy, PartialEq, Eq, Deserialize, Serialize, AbiExample)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpochSchedule {
|
||||
/// 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 {
|
||||
pub fn new(slots_per_epoch: u64) -> Self {
|
||||
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
|
||||
// interaction within rustdoc between the reexports inside this module of
|
||||
// `solana_program`'s top-level modules, and `solana_sdk`'s glob re-export of
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
|
||||
#![allow(clippy::integer_arithmetic)]
|
||||
|
||||
use {
|
||||
crate::{clock::DEFAULT_SLOTS_PER_EPOCH, clone_zeroed, copy_field},
|
||||
std::mem::MaybeUninit,
|
||||
};
|
||||
use {crate::clock::DEFAULT_SLOTS_PER_EPOCH, solana_sdk_macro::CloneZeroed};
|
||||
|
||||
/// Configuration of network rent.
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Copy, Debug, AbiExample)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, CloneZeroed, Copy, Debug, AbiExample)]
|
||||
pub struct Rent {
|
||||
/// Rental rate in lamports/byte-year.
|
||||
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 {
|
||||
/// Calculate how much rent to burn from the collected rent.
|
||||
///
|
||||
|
|
|
@ -22,10 +22,9 @@
|
|||
|
||||
use {
|
||||
crate::{
|
||||
clone_zeroed, copy_field, fee_calculator::FeeCalculator, impl_sysvar_get,
|
||||
program_error::ProgramError, sysvar::Sysvar,
|
||||
fee_calculator::FeeCalculator, impl_sysvar_get, program_error::ProgramError, sysvar::Sysvar,
|
||||
},
|
||||
std::mem::MaybeUninit,
|
||||
solana_sdk_macro::CloneZeroed,
|
||||
};
|
||||
|
||||
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"
|
||||
)]
|
||||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, CloneZeroed, Default, PartialEq, Eq)]
|
||||
pub struct Fees {
|
||||
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 {
|
||||
pub fn new(fee_calculator: &FeeCalculator) -> Self {
|
||||
#[allow(deprecated)]
|
||||
|
|
|
@ -13,11 +13,11 @@ pub use signer::signers;
|
|||
pub use solana_program::program_stubs;
|
||||
pub use solana_program::{
|
||||
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,
|
||||
custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id,
|
||||
decode_error, ed25519_program, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator,
|
||||
instruction, keccak, lamports, loader_instruction, loader_upgradeable_instruction, message,
|
||||
msg, native_token, nonce, program, program_error, program_memory, program_option, program_pack,
|
||||
bpf_loader_upgradeable, clock, config, custom_heap_default, custom_panic_default,
|
||||
debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id, decode_error,
|
||||
ed25519_program, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator, instruction,
|
||||
keccak, lamports, loader_instruction, loader_upgradeable_instruction, message, msg,
|
||||
native_token, nonce, program, program_error, program_memory, program_option, program_pack,
|
||||
rent, sanitize, sdk_ids, secp256k1_program, secp256k1_recover, serialize_utils, short_vec,
|
||||
slot_hashes, slot_history, stake, stake_history, syscalls, system_instruction, system_program,
|
||||
sysvar, unchecked_div_by_const, vote, wasm_bindgen,
|
||||
|
|
Loading…
Reference in New Issue