Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,062 changes: 1,842 additions & 1,220 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ license = "Apache-2.0"
edition = "2021"

[workspace.metadata.cli]
solana = "2.3.4"
solana = "3.0.0"

[workspace.lints.rust.unexpected_cfgs]
level = "warn"
Expand Down
1 change: 0 additions & 1 deletion clients/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ thiserror = "1.0"

[dev-dependencies]
assert_matches = "1.5.0"
solana-sdk = "2.2.1"
2 changes: 2 additions & 0 deletions clients/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(non_local_definitions)] // <-- Rustc warning on `FromPrimitive`

mod generated;
mod hooked;

Expand Down
52 changes: 31 additions & 21 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,43 @@ bpf-entrypoint = []
test-sbf = []

[dependencies]
arrayref = "0.3.8"
bincode = "1.3.3"
borsh = { version = "1.5.1", features = ["derive", "unstable__schema"] }
num-derive = "0.4"
num-traits = "0.2"
num_enum = "0.7.3"
solana-program = "2.2.1"
thiserror = "1.0.63"
solana-account-info = { version = "3.0.0", features = ["bincode"] }
solana-clock = "3.0.0"
solana-cpi = "3.0.0"
solana-instruction-error = "2.0.0"
solana-msg = "3.0.0"
solana-native-token = "3.0.0"
solana-program-entrypoint = "3.0.0"
solana-program-error = "3.0.0"
solana-pubkey = "3.0.0"
solana-rent = "3.0.0"
solana-stake-interface = { version = "2", features = ["bincode", "borsh", "sysvar"] }
solana-sysvar = "3.0.0"
solana-vote-interface = { version = "4.0.1", features = ["bincode"] }

[dev-dependencies]
assert_matches = "1.5.0"
agave-feature-set = "3.0.0"
arbitrary = { version = "1.4.1", features = ["derive"] }
mollusk-svm = { version = "0.4.0", features = ["all-builtins"] }
assert_matches = "1.5.0"
mollusk-svm = { version = "0.6.1", features = ["all-builtins"] }
proptest = "1.6.0"
solana-account = { version = "2.2.1", features = ["bincode"] }
solana-config-interface = { version = "1", features = ["serde"] }
solana-feature-set = "2.2.1"
solana-logger = "2.2.1"
solana-program-test = "2.3.4"
solana-program-runtime = "2.2.0"
solana-stake-interface = { version = "1", features = ["bincode"] }
solana-system-interface = { version = "1", features = ["bincode"] }
solana-vote-program = "2.2.0"
solana-sdk = "2.2.1"
solana-sdk-ids = "2.2.1"
solana-sysvar = { version = "2.2.1", features = ["bincode"] }
rand = "0.8.5"
solana-account = { version = "3.0.0", features = ["bincode"] }
solana-config-interface = { version = "1", features = ["serde"] }
solana-epoch-rewards = "3.0.0"
solana-epoch-schedule = "3.0.0"
solana-instruction = "3.0.0"
solana-keypair = "3.0.0"
solana-logger = "3.0.0"
solana-program-test = "3.0.0"
solana-sdk-ids = "3.0.0"
solana-signature = "3.0.0"
solana-signer = "3.0.0"
solana-system-interface = { version = "2.0.0", features = ["bincode"] }
solana-sysvar-id = "3.0.0"
solana-transaction = "3.0.0"
solana-vote-program = { git = "https://github.com/buffalojoec/solana.git", branch = "vote-handler-dcou", features = ["dev-context-only-utils"] }
test-case = "3.3.1"

[lib]
Expand Down
7 changes: 5 additions & 2 deletions program/src/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

use {
crate::processor::Processor,
solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg, pubkey::Pubkey},
solana_account_info::AccountInfo,
solana_msg::msg,
solana_program_entrypoint::{entrypoint, ProgramResult},
solana_pubkey::Pubkey,
};

solana_program::entrypoint!(process_instruction);
entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
Expand Down
33 changes: 19 additions & 14 deletions program/src/helpers/delegate.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
use {
crate::PERPETUAL_NEW_WARMUP_COOLDOWN_RATE_EPOCH,
solana_program::{
account_info::AccountInfo,
clock::Epoch,
program_error::ProgramError,
pubkey::Pubkey,
stake::{
instruction::StakeError,
state::{Delegation, Meta, Stake},
},
solana_account_info::AccountInfo,
solana_clock::Epoch,
solana_program_error::ProgramError,
solana_pubkey::Pubkey,
solana_stake_interface::{
error::StakeError,
state::{Delegation, Meta, Stake},
sysvar::stake_history::StakeHistorySysvar,
vote::state::VoteState,
},
};

Expand All @@ -23,20 +20,20 @@ pub(crate) struct ValidatedDelegatedInfo {
pub(crate) fn new_stake(
stake: u64,
voter_pubkey: &Pubkey,
vote_state: &VoteState,
credits_observed: u64,
activation_epoch: Epoch,
) -> Stake {
Stake {
delegation: Delegation::new(voter_pubkey, stake, activation_epoch),
credits_observed: vote_state.credits(),
credits_observed,
}
}

pub(crate) fn redelegate_stake(
stake: &mut Stake,
stake_lamports: u64,
voter_pubkey: &Pubkey,
vote_state: &VoteState,
credits_observed: u64,
epoch: Epoch,
stake_history: &StakeHistorySysvar,
) -> Result<(), ProgramError> {
Expand Down Expand Up @@ -68,7 +65,7 @@ pub(crate) fn redelegate_stake(
stake.delegation.activation_epoch = epoch;
stake.delegation.deactivation_epoch = u64::MAX;
stake.delegation.voter_pubkey = *voter_pubkey;
stake.credits_observed = vote_state.credits();
stake.credits_observed = credits_observed;
Ok(())
}

Expand All @@ -88,3 +85,11 @@ pub(crate) fn validate_delegated_amount(
}
Ok(ValidatedDelegatedInfo { stake_amount })
}

pub(crate) fn get_vote_credits_observed(epoch_credits: &[(u64, u64, u64)]) -> u64 {
if epoch_credits.is_empty() {
0
} else {
epoch_credits.last().unwrap().1
}
}
23 changes: 9 additions & 14 deletions program/src/helpers/merge.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use {
crate::{helpers::checked_add, PERPETUAL_NEW_WARMUP_COOLDOWN_RATE_EPOCH},
solana_program::{
clock::{Clock, Epoch},
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
stake::{instruction::StakeError, stake_flags::StakeFlags, state::*},
stake_history::StakeHistoryGetEntry,
solana_clock::{Clock, Epoch},
solana_msg::msg,
solana_program_error::{ProgramError, ProgramResult},
solana_stake_interface::{
error::StakeError, stake_flags::StakeFlags, stake_history::StakeHistoryGetEntry, state::*,
},
std::convert::TryFrom,
};
Expand Down Expand Up @@ -233,13 +231,10 @@ mod tests {
super::*,
crate::id,
proptest::prelude::*,
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
account_utils::StateMut,
pubkey::Pubkey,
stake_history::{StakeHistory, StakeHistoryEntry},
sysvar::rent::Rent,
},
solana_account::{state_traits::StateMut, AccountSharedData, ReadableAccount},
solana_pubkey::Pubkey,
solana_rent::Rent,
solana_stake_interface::stake_history::{StakeHistory, StakeHistoryEntry},
};

#[test]
Expand Down
2 changes: 1 addition & 1 deletion program/src/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use solana_program::{instruction::InstructionError, program_error::ProgramError};
use {solana_instruction_error::InstructionError, solana_program_error::ProgramError};

pub(crate) mod delegate;
pub(crate) use delegate::*;
Expand Down
5 changes: 4 additions & 1 deletion program/src/helpers/split.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use solana_program::{program_error::ProgramError, rent::Rent, stake::state::Meta, sysvar::Sysvar};
use {
solana_program_error::ProgramError, solana_rent::Rent, solana_stake_interface::state::Meta,
solana_sysvar::Sysvar,
};

/// After calling `validate_split_amount()`, this struct contains calculated
/// values that are used by the caller.
Expand Down
6 changes: 2 additions & 4 deletions program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use solana_program::native_token::LAMPORTS_PER_SOL;
use solana_native_token::LAMPORTS_PER_SOL;

pub mod helpers;
pub mod processor;

#[cfg(feature = "bpf-entrypoint")]
pub mod entrypoint;

pub use solana_program;

solana_program::declare_id!("Stake11111111111111111111111111111111111111");
solana_pubkey::declare_id!("Stake11111111111111111111111111111111111111");

// placeholders for features
// we have ONE feature in the current stake program we care about:
Expand Down
94 changes: 61 additions & 33 deletions program/src/processor.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,65 @@
use {
crate::{helpers::*, id, PERPETUAL_NEW_WARMUP_COOLDOWN_RATE_EPOCH},
solana_program::{
account_info::{next_account_info, AccountInfo},
clock::Clock,
entrypoint::ProgramResult,
msg,
program::set_return_data,
program_error::ProgramError,
pubkey::Pubkey,
rent::Rent,
stake::{
instruction::{
AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs, LockupArgs, LockupCheckedArgs,
StakeError, StakeInstruction,
},
stake_flags::StakeFlags,
state::{Authorized, Lockup, Meta, StakeAuthorize, StakeStateV2},
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
solana_account_info::{next_account_info, AccountInfo},
solana_clock::Clock,
solana_cpi::set_return_data,
solana_msg::msg,
solana_program_error::{ProgramError, ProgramResult},
solana_pubkey::Pubkey,
solana_rent::Rent,
solana_stake_interface::{
error::StakeError,
instruction::{
AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs, LockupArgs, LockupCheckedArgs,
StakeInstruction,
},
sysvar::{epoch_rewards::EpochRewards, stake_history::StakeHistorySysvar, Sysvar},
vote::{program as solana_vote_program, state::VoteState},
stake_flags::StakeFlags,
state::{Authorized, Lockup, Meta, StakeAuthorize, StakeStateV2},
sysvar::stake_history::StakeHistorySysvar,
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
},
solana_sysvar::{epoch_rewards::EpochRewards, Sysvar, SysvarSerialize},
solana_vote_interface::{
program as solana_vote_program,
state::{VoteStateV3, VoteStateV4},
},
std::{collections::HashSet, mem::MaybeUninit},
};

fn get_vote_state(vote_account_info: &AccountInfo) -> Result<Box<VoteState>, ProgramError> {
fn get_vote_state_epoch_credits(
vote_account_info: &AccountInfo,
) -> Result<Vec<(u64, u64, u64)>, ProgramError> {
if *vote_account_info.owner != solana_vote_program::id() {
return Err(ProgramError::IncorrectProgramId);
}

let mut vote_state = Box::new(MaybeUninit::uninit());
VoteState::deserialize_into_uninit(&vote_account_info.try_borrow_data()?, vote_state.as_mut())
.map_err(|_| ProgramError::InvalidAccountData)?;
let vote_state = unsafe { Box::from_raw(Box::into_raw(vote_state) as *mut VoteState) };

Ok(vote_state)
// Check the variant first.
let data = vote_account_info.try_borrow_data()?;
match data.first() {
Some(2) => {
// VoteStateV3
let mut vote_state = Box::new(MaybeUninit::uninit());
VoteStateV3::deserialize_into_uninit(&data, vote_state.as_mut())
.map_err(|_| ProgramError::InvalidAccountData)?;
let vote_state =
unsafe { Box::from_raw(Box::into_raw(vote_state) as *mut VoteStateV3) };
Ok(vote_state.epoch_credits)
}
Some(3) => {
// VoteStateV4
let mut vote_state = Box::new(MaybeUninit::uninit());
VoteStateV4::deserialize_into_uninit(&data, vote_state.as_mut(), vote_account_info.key)
.map_err(|_| ProgramError::InvalidAccountData)?;
let vote_state =
unsafe { Box::from_raw(Box::into_raw(vote_state) as *mut VoteStateV4) };
Ok(vote_state.epoch_credits)
}
_ => {
// Older versions are not supported.
// Neither is zero data.
Err(ProgramError::InvalidAccountData)
}
}
}

fn get_stake_state(stake_account_info: &AccountInfo) -> Result<StakeStateV2, ProgramError> {
Expand Down Expand Up @@ -377,7 +402,8 @@ impl Processor {
let clock = &Clock::from_account_info(clock_info)?;
let stake_history = &StakeHistorySysvar(clock.epoch);

let vote_state = get_vote_state(vote_account_info)?;
let vote_state_epoch_credits = get_vote_state_epoch_credits(vote_account_info)?;
let credits_observed = get_vote_credits_observed(&vote_state_epoch_credits);

match get_stake_state(stake_account_info)? {
StakeStateV2::Initialized(meta) => {
Expand All @@ -391,7 +417,7 @@ impl Processor {
let stake = new_stake(
stake_amount,
vote_account_info.key,
&vote_state,
credits_observed,
clock.epoch,
);

Expand All @@ -412,7 +438,7 @@ impl Processor {
&mut stake,
stake_amount,
vote_account_info.key,
&vote_state,
credits_observed,
clock.epoch,
stake_history,
)?;
Expand Down Expand Up @@ -989,10 +1015,12 @@ impl Processor {

let clock = Clock::get()?;

let delinquent_vote_state = get_vote_state(delinquent_vote_account_info)?;
let reference_vote_state = get_vote_state(reference_vote_account_info)?;
let delinquent_vote_state_epoch_credits =
get_vote_state_epoch_credits(delinquent_vote_account_info)?;
let reference_vote_state_epoch_credits =
get_vote_state_epoch_credits(reference_vote_account_info)?;

if !acceptable_reference_epoch_credits(&reference_vote_state.epoch_credits, clock.epoch) {
if !acceptable_reference_epoch_credits(&reference_vote_state_epoch_credits, clock.epoch) {
return Err(StakeError::InsufficientReferenceVotes.into());
}

Expand All @@ -1006,7 +1034,7 @@ impl Processor {
// Deactivate the stake account if its delegated vote account has never voted or
// has not voted in the last
// `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
if eligible_for_deactivate_delinquent(&delinquent_vote_state.epoch_credits, clock.epoch)
if eligible_for_deactivate_delinquent(&delinquent_vote_state_epoch_credits, clock.epoch)
{
stake.deactivate(clock.epoch)?;

Expand Down
Loading