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
2,437 changes: 1,608 additions & 829 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ edition = "2021"
spherenet-stake-interface = { version = "^0", path = "interface" }

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

[workspace.lints.rust.unexpected_cfgs]
level = "warn"
Expand All @@ -30,9 +30,9 @@ check-cfg = [

[workspace.metadata.toolchains]
build = "1.90.0"
format = "nightly-2025-02-16"
lint = "nightly-2025-02-16"
test = "nightly-2025-02-16"
format = "nightly-2025-09-18"
lint = "nightly-2025-09-18"
test = "nightly-2025-09-18"

[workspace.metadata.spellcheck]
config = "scripts/spellcheck.toml"
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
RUST_TOOLCHAIN_NIGHTLY = nightly-2025-02-16
SOLANA_CLI_VERSION = 3.0.0
RUST_TOOLCHAIN_NIGHTLY = nightly-2025-09-18
SOLANA_CLI_VERSION = 3.1.14

nightly = +${RUST_TOOLCHAIN_NIGHTLY}

Expand Down Expand Up @@ -55,8 +55,10 @@ format-rust:
build-sbf-%:
cargo build-sbf --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)

# getrandom 0.3 (via solana-frozen-abi under `--all-features`) needs this cfg to
# select its wasm-bindgen backend on wasm32-unknown-unknown.
build-wasm-%:
cargo $(nightly) build --target wasm32-unknown-unknown --manifest-path $(call make-path,$*)/Cargo.toml --all-features $(ARGS)
RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo $(nightly) build --target wasm32-unknown-unknown --manifest-path $(call make-path,$*)/Cargo.toml --all-features $(ARGS)

build-doc-%:
RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo $(nightly) doc --all-features --no-deps --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
Expand Down
8 changes: 8 additions & 0 deletions interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ solana-signer = { version = "3.0.0", optional = true }
[target.'cfg(not(target_os = "solana"))'.dependencies]
serde_json = { version = "1.0", optional = true }

# solana-program (via spherenet-validator-whitelist-interface) and solana-keypair
# pull in getrandom 0.2, which needs its `js` backend on wasm32-unknown-unknown.
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
getrandom = { version = "0.2", features = ["js"] }
# solana-frozen-abi (`frozen-abi` feature) pulls in getrandom 0.3, which also
# needs `--cfg getrandom_backend="wasm_js"` (set by `make build-wasm-%`).
getrandom_03 = { package = "getrandom", version = "0.3", features = ["wasm_js"] }

[dev-dependencies]
anyhow = "1"
assert_matches = "1.5.0"
Expand Down
4 changes: 2 additions & 2 deletions interface/idl.json
Original file line number Diff line number Diff line change
Expand Up @@ -1843,10 +1843,10 @@
}
],
"kind": "programNode",
"name": "solanaStakeInterface",
"name": "spherenetStakeInterface",
"pdas": [],
"publicKey": "Stake11111111111111111111111111111111111111",
"version": "2.0.2"
"version": "0.2.2"
},
"standard": "codama",
"version": "1.0.0"
Expand Down
27 changes: 17 additions & 10 deletions interface/src/helpers/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
use solana_keypair::Keypair;
use solana_pubkey::Pubkey;
use solana_rent::Rent;
use solana_signer::Signer;
use spherenet_validator_whitelist_interface::state::{
account::ValidatorWhitelistAccount, whitelist_entry::ValidatorWhitelistEntry, AccountState,
SizeOf,
use {
solana_account::AccountSharedData,
solana_genesis_config::GenesisConfig,
solana_keypair::Keypair,
solana_pubkey::Pubkey,
solana_rent::Rent,
solana_signer::Signer,
spherenet_validator_whitelist_interface::state::{
account::ValidatorWhitelistAccount, whitelist_entry::ValidatorWhitelistEntry, AccountState,
SizeOf,
},
};

use solana_account::AccountSharedData;
use solana_genesis_config::GenesisConfig;

pub fn add_validator_whitelist_account_to_genesis_config(
genesis_config: &mut GenesisConfig,
authority: &Pubkey,
vote_accounts_count: u32,
) {
let data_size = ValidatorWhitelistAccount::SIZE_OF;

// `lamports_per_byte_year` is deprecated in solana-rent 3.1 (renamed in
// v4); there is no replacement accessor in 3.x, so read it directly.
#[allow(deprecated)]
let non_zero_rent = match genesis_config.rent.lamports_per_byte_year {
0 => &Rent::default(),
_ => &genesis_config.rent,
Expand Down Expand Up @@ -64,6 +68,9 @@ pub fn add_validator_whitelist_entry_to_genesis_config(
}
.pack();

// `lamports_per_byte_year` is deprecated in solana-rent 3.1 (renamed in
// v4); there is no replacement accessor in 3.x, so read it directly.
#[allow(deprecated)]
let non_zero_rent = match genesis_config.rent.lamports_per_byte_year {
0 => &Rent::default(),
_ => &genesis_config.rent,
Expand Down
4 changes: 2 additions & 2 deletions interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
#[allow(deprecated)]
pub mod config;
pub mod error;
#[cfg(feature = "helpers")]
pub mod helpers;
pub mod instruction;
pub mod stake_flags;
pub mod stake_history;
pub mod state;
#[cfg(feature = "sysvar")]
pub mod sysvar;
pub mod tools;
#[cfg(feature = "helpers")]
pub mod helpers;

#[cfg(feature = "codama")]
use codama_macros::codama;
Expand Down
6 changes: 1 addition & 5 deletions interface/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1514,11 +1514,7 @@ mod tests {
})
.sum::<u64>();

let delta = if total_effective_stake > prev_total_effective_stake {
total_effective_stake - prev_total_effective_stake
} else {
prev_total_effective_stake - total_effective_stake
};
let delta = total_effective_stake.abs_diff(prev_total_effective_stake);

// uncomment and add ! for fun with graphing
// eprint("{:8} {:8} {:8} ", epoch, total_effective_stake, delta);
Expand Down
12 changes: 9 additions & 3 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ solana-keypair = { version = "3.0.0", optional = true }
solana-signer = { version = "3.0.0", optional = true }
solana-instruction = { version = "3.0.0", optional = true }

# solana-program (via spherenet-validator-whitelist-interface) and solana-keypair
# pull in getrandom 0.2, which needs its `js` backend on wasm32-unknown-unknown.
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
getrandom = { version = "0.2", features = ["js"] }

[dev-dependencies]
agave-feature-set = "3.0.0"
agave-feature-set = "3.1.0"
arbitrary = { version = "1.4.2", features = ["derive"] }
assert_matches = "1.5.0"
mollusk-svm = { version = "0.7.1", features = ["all-builtins"] }
mollusk-svm = { version = "0.12.0", features = ["all-builtins"] }
proptest = "1.10.0"
rand = "0.9.2"
solana-account = { version = "3.2.0", features = ["bincode"] }
Expand All @@ -49,7 +54,8 @@ 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.10"
solana-program-binaries = "3.1.12"
solana-program-test = { version = "3.1.12", features = ["agave-unstable-api"] }
solana-sdk-ids = "3.0.0"
solana-signature = "3.2.0"
solana-signer = "3.0.0"
Expand Down
2 changes: 1 addition & 1 deletion program/src/instruction_builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

use {
solana_instruction::{AccountMeta, Instruction},
solana_pubkey::Pubkey,
spherenet_stake_interface::{
instruction::{create_account, create_account_with_seed, StakeInstruction},
program::ID,
state::{Authorized, Lockup},
},
spherenet_validator_whitelist_interface::program_solana::ID as WHITELIST_PROGRAM_ID,
};
use solana_pubkey::Pubkey;

// Inline some constants to avoid dependencies.
//
Expand Down
3 changes: 1 addition & 2 deletions program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ pub mod instruction_builders;
// Re-export commonly used functions when helpers feature enabled
#[cfg(feature = "helpers")]
pub use instruction_builders::{
create_account_and_delegate_stake, create_account_with_seed_and_delegate_stake,
delegate_stake,
create_account_and_delegate_stake, create_account_with_seed_and_delegate_stake, delegate_stake,
};

solana_pubkey::declare_id!("Stake11111111111111111111111111111111111111");
Expand Down
16 changes: 10 additions & 6 deletions program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use {
solana_program_error::{ProgramError, ProgramResult},
solana_pubkey::Pubkey,
solana_rent::Rent,
solana_sysvar::{epoch_rewards::EpochRewards, Sysvar},
solana_sysvar_id::SysvarId,
solana_vote_interface::{program as solana_vote_program, state::VoteStateV4},
spherenet_stake_interface::{
error::StakeError,
instruction::{
Expand All @@ -18,9 +21,6 @@ use {
sysvar::stake_history::StakeHistorySysvar,
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
},
solana_sysvar::{epoch_rewards::EpochRewards, Sysvar},
solana_sysvar_id::SysvarId,
solana_vote_interface::{program as solana_vote_program, state::VoteStateV4},
spherenet_validator_whitelist_interface::onchain::WhitelistEntryInformation,
std::{collections::HashSet, mem::MaybeUninit},
};
Expand Down Expand Up @@ -1263,7 +1263,9 @@ impl Processor {
delisted_vote_account_info.key,
)
.map_err(|e| match e {
solana_instruction_error::InstructionError::Custom(code) => ProgramError::Custom(code),
solana_instruction_error::InstructionError::Custom(code) => {
ProgramError::Custom(code)
}
_ => ProgramError::InvalidInstructionData,
})?;

Expand Down Expand Up @@ -1299,8 +1301,10 @@ impl Processor {
&clock,
)
}
owner if owner == spherenet_validator_whitelist_interface::program_solana::id()
|| owner == solana_sdk_ids::system_program::id() => {
owner
if owner == spherenet_validator_whitelist_interface::program_solana::id()
|| owner == solana_sdk_ids::system_program::id() =>
{
// Delisted delinquent: whitelist entry (active or tombstone)
Self::deactivate_delisted_delinquent(
stake_account_info,
Expand Down
90 changes: 52 additions & 38 deletions program/tests/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ use {
solana_sdk_ids::system_program,
// Mollusk depends on solana-stake-interface, so we need to use its StakeHistoryEntry for test setup
solana_stake_interface::stake_history::StakeHistoryEntry,
solana_svm_log_collector::LogCollector,
solana_sysvar_id::SysvarId,
solana_vote_interface::{
program as vote_program,
state::{VoteStateV4, VoteStateVersions},
},
spherenet_stake_interface::{
instruction::{self, LockupArgs},
stake_flags::StakeFlags,
Expand All @@ -24,12 +30,6 @@ use {
},
},
spherenet_stake_program::{get_minimum_delegation, id},
solana_svm_log_collector::LogCollector,
solana_sysvar_id::SysvarId,
solana_vote_interface::{
program as vote_program,
state::{VoteStateV4, VoteStateVersions},
},
spherenet_validator_whitelist_interface::state::{
whitelist_entry::ValidatorWhitelistEntry, AccountState, SizeOf,
},
Expand Down Expand Up @@ -136,13 +136,13 @@ fn create_whitelist_entry_account(vote_address: &Pubkey) -> (Pubkey, Account) {

let lamports = Rent::default().minimum_balance(<ValidatorWhitelistEntry as SizeOf>::SIZE_OF);

let account = Account::create(
let account = Account {
lamports,
data.to_vec(),
spherenet_validator_whitelist_interface::program_solana::id(),
false,
u64::MAX,
);
data: data.to_vec(),
owner: spherenet_validator_whitelist_interface::program_solana::id(),
executable: false,
rent_epoch: u64::MAX,
};

(entry_pubkey, account)
}
Expand Down Expand Up @@ -202,13 +202,13 @@ impl Env {
let vote_rent_exemption = Rent::default().minimum_balance(VoteStateV4::size_of());
let vote_state_versions = VoteStateVersions::new_v4(VoteStateV4::default());
let vote_data = bincode::serialize(&vote_state_versions).unwrap();
let vote_account = Account::create(
vote_rent_exemption,
vote_data,
vote_program::id(),
false,
u64::MAX,
);
let vote_account = Account {
lamports: vote_rent_exemption,
data: vote_data,
owner: vote_program::id(),
executable: false,
rent_epoch: u64::MAX,
};
base_accounts.insert(VOTE_ACCOUNT_RED, vote_account.clone());
base_accounts.insert(VOTE_ACCOUNT_BLUE, vote_account);

Expand All @@ -221,31 +221,34 @@ impl Env {
}
let vote_state_versions = VoteStateVersions::new_v4(reference_vote_state);
let vote_data = bincode::serialize(&vote_state_versions).unwrap();
let vote_account = Account::create(
vote_rent_exemption,
vote_data,
vote_program::id(),
false,
u64::MAX,
);
let vote_account = Account {
lamports: vote_rent_exemption,
data: vote_data,
owner: vote_program::id(),
executable: false,
rent_epoch: u64::MAX,
};
base_accounts.insert(VOTE_ACCOUNT_GOLD, vote_account);

// create whitelist entries for all vote accounts
let (whitelist_red, whitelist_red_account) = create_whitelist_entry_account(&VOTE_ACCOUNT_RED);
let (whitelist_blue, whitelist_blue_account) = create_whitelist_entry_account(&VOTE_ACCOUNT_BLUE);
let (whitelist_gold, whitelist_gold_account) = create_whitelist_entry_account(&VOTE_ACCOUNT_GOLD);
let (whitelist_red, whitelist_red_account) =
create_whitelist_entry_account(&VOTE_ACCOUNT_RED);
let (whitelist_blue, whitelist_blue_account) =
create_whitelist_entry_account(&VOTE_ACCOUNT_BLUE);
let (whitelist_gold, whitelist_gold_account) =
create_whitelist_entry_account(&VOTE_ACCOUNT_GOLD);
base_accounts.insert(whitelist_red, whitelist_red_account);
base_accounts.insert(whitelist_blue, whitelist_blue_account);
base_accounts.insert(whitelist_gold, whitelist_gold_account);

// create two blank stake accounts
let stake_account = Account::create(
STAKE_RENT_EXEMPTION,
vec![0; StakeStateV2::size_of()],
id(),
false,
u64::MAX,
);
let stake_account = Account {
lamports: STAKE_RENT_EXEMPTION,
data: vec![0; StakeStateV2::size_of()],
owner: id(),
executable: false,
rent_epoch: u64::MAX,
};
base_accounts.insert(STAKE_ACCOUNT_BLACK, stake_account.clone());
base_accounts.insert(STAKE_ACCOUNT_WHITE, stake_account);

Expand Down Expand Up @@ -576,7 +579,12 @@ impl StakeInterface {

// Create instruction with whitelist entry
let whitelist_entry_pubkey = spherenet_validator_whitelist_interface::state::whitelist_entry::get_whitelist_entry_pubkey(&VOTE_ACCOUNT_RED).unwrap();
instruction::delegate_stake(&STAKE_ACCOUNT_BLACK, &STAKER_BLACK, &VOTE_ACCOUNT_RED, &whitelist_entry_pubkey)
instruction::delegate_stake(
&STAKE_ACCOUNT_BLACK,
&STAKER_BLACK,
&VOTE_ACCOUNT_RED,
&whitelist_entry_pubkey,
)
}
Self::Split {
lockup_state,
Expand Down Expand Up @@ -1148,7 +1156,13 @@ fn test_no_use_dealloc() {
.get(&stake_address)
.unwrap_or_else(|| env.base_accounts.get(&stake_address).unwrap())
.lamports();
let stake_account = Account::create(lamports, vec![], id(), false, u64::MAX);
let stake_account = Account {
lamports,
data: vec![],
owner: id(),
executable: false,
rent_epoch: u64::MAX,
};
env.override_accounts.insert(stake_address, stake_account);

if is_withdraw {
Expand Down
Loading
Loading