parent
94eb78d399
commit
933e835838
|
@ -19,7 +19,7 @@ source scripts/ulimit-n.sh
|
||||||
# Clear cached json keypair files
|
# Clear cached json keypair files
|
||||||
rm -rf "$HOME/.config/solana"
|
rm -rf "$HOME/.config/solana"
|
||||||
|
|
||||||
# Clear the C dependency files, if dependeny moves these files are not regenerated
|
# Clear the C dependency files, if dependency moves these files are not regenerated
|
||||||
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
|
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
|
||||||
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
|
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
|
||||||
|
|
||||||
|
|
|
@ -895,7 +895,9 @@ fn process_show_stake_account(
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
Ok(StakeState::RewardsPool) => Ok("Stake account is a rewards pool".to_string()),
|
Ok(StakeState::RewardsPool) => Ok("Stake account is a rewards pool".to_string()),
|
||||||
Ok(StakeState::Uninitialized) => Ok("Stake account is uninitialized".to_string()),
|
Ok(StakeState::Uninitialized) | Ok(StakeState::Lockup(_)) => {
|
||||||
|
Ok("Stake account is uninitialized".to_string())
|
||||||
|
}
|
||||||
Err(err) => Err(WalletError::RpcRequestError(format!(
|
Err(err) => Err(WalletError::RpcRequestError(format!(
|
||||||
"Account data could not be deserialized to stake state: {:?}",
|
"Account data could not be deserialized to stake state: {:?}",
|
||||||
err
|
err
|
||||||
|
|
|
@ -10,14 +10,25 @@ use solana_sdk::{
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction, sysvar,
|
system_instruction, sysvar,
|
||||||
|
timing::Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum StakeInstruction {
|
pub enum StakeInstruction {
|
||||||
|
/// `Lockup` a stake until the specified slot
|
||||||
|
///
|
||||||
|
/// Expects 1 Account:
|
||||||
|
/// 0 - Uninitialized StakeAccount to be lockup'd
|
||||||
|
///
|
||||||
|
/// The u64 is the portion of the Stake account balance to be activated,
|
||||||
|
/// must be less than StakeAccount.lamports
|
||||||
|
///
|
||||||
|
Lockup(Slot),
|
||||||
|
|
||||||
/// `Delegate` a stake to a particular node
|
/// `Delegate` a stake to a particular node
|
||||||
///
|
///
|
||||||
/// Expects 3 Accounts:
|
/// Expects 3 Accounts:
|
||||||
/// 0 - Uninitialized StakeAccount to be delegated <= must have this signature
|
/// 0 - Lockup'd StakeAccount to be delegated <= must have this signature
|
||||||
/// 1 - VoteAccount to which this Stake will be delegated
|
/// 1 - VoteAccount to which this Stake will be delegated
|
||||||
/// 2 - Clock sysvar Account that carries clock bank epoch
|
/// 2 - Clock sysvar Account that carries clock bank epoch
|
||||||
/// 3 - Config Account that carries stake config
|
/// 3 - Config Account that carries stake config
|
||||||
|
@ -58,28 +69,44 @@ pub enum StakeInstruction {
|
||||||
Deactivate,
|
Deactivate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_stake_account_with_lockup(
|
||||||
|
from_pubkey: &Pubkey,
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
lockup: Slot,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
vec![
|
||||||
|
system_instruction::create_account(
|
||||||
|
from_pubkey,
|
||||||
|
stake_pubkey,
|
||||||
|
lamports,
|
||||||
|
std::mem::size_of::<StakeState>() as u64,
|
||||||
|
&id(),
|
||||||
|
),
|
||||||
|
Instruction::new(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::Lockup(lockup),
|
||||||
|
vec![AccountMeta::new(*stake_pubkey, false)],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_stake_account(
|
pub fn create_stake_account(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
staker_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
vec![system_instruction::create_account(
|
create_stake_account_with_lockup(from_pubkey, stake_pubkey, lamports, 0)
|
||||||
from_pubkey,
|
|
||||||
staker_pubkey,
|
|
||||||
lamports,
|
|
||||||
std::mem::size_of::<StakeState>() as u64,
|
|
||||||
&id(),
|
|
||||||
)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_stake_account_and_delegate_stake(
|
pub fn create_stake_account_and_delegate_stake(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
staker_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
vote_pubkey: &Pubkey,
|
vote_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
let mut instructions = create_stake_account(from_pubkey, staker_pubkey, lamports);
|
let mut instructions = create_stake_account(from_pubkey, stake_pubkey, lamports);
|
||||||
instructions.push(delegate_stake(staker_pubkey, vote_pubkey, lamports));
|
instructions.push(delegate_stake(stake_pubkey, vote_pubkey, lamports));
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +169,7 @@ pub fn process_instruction(
|
||||||
|
|
||||||
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
||||||
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
||||||
|
StakeInstruction::Lockup(slot) => me.lockup(slot),
|
||||||
StakeInstruction::DelegateStake(stake) => {
|
StakeInstruction::DelegateStake(stake) => {
|
||||||
if rest.len() != 3 {
|
if rest.len() != 3 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
|
|
|
@ -14,13 +14,14 @@ use solana_sdk::{
|
||||||
self,
|
self,
|
||||||
stake_history::{StakeHistory, StakeHistoryEntry},
|
stake_history::{StakeHistory, StakeHistoryEntry},
|
||||||
},
|
},
|
||||||
timing::Epoch,
|
timing::{Epoch, Slot},
|
||||||
};
|
};
|
||||||
use solana_vote_api::vote_state::VoteState;
|
use solana_vote_api::vote_state::VoteState;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub enum StakeState {
|
pub enum StakeState {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
|
Lockup(Slot),
|
||||||
Stake(Stake),
|
Stake(Stake),
|
||||||
RewardsPool,
|
RewardsPool,
|
||||||
}
|
}
|
||||||
|
@ -57,6 +58,7 @@ pub struct Stake {
|
||||||
pub activation_epoch: Epoch, // epoch the stake was activated, std::Epoch::MAX if is a bootstrap stake
|
pub activation_epoch: Epoch, // epoch the stake was activated, std::Epoch::MAX if is a bootstrap stake
|
||||||
pub deactivation_epoch: Epoch, // epoch the stake was deactivated, std::Epoch::MAX if not deactivated
|
pub deactivation_epoch: Epoch, // epoch the stake was deactivated, std::Epoch::MAX if not deactivated
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
pub lockup: Slot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Stake {
|
impl Default for Stake {
|
||||||
|
@ -68,6 +70,7 @@ impl Default for Stake {
|
||||||
activation_epoch: 0,
|
activation_epoch: 0,
|
||||||
deactivation_epoch: std::u64::MAX,
|
deactivation_epoch: std::u64::MAX,
|
||||||
config: Config::default(),
|
config: Config::default(),
|
||||||
|
lockup: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,6 +259,7 @@ impl Stake {
|
||||||
vote_state,
|
vote_state,
|
||||||
std::u64::MAX,
|
std::u64::MAX,
|
||||||
&Config::default(),
|
&Config::default(),
|
||||||
|
0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,6 +269,7 @@ impl Stake {
|
||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
activation_epoch: Epoch,
|
activation_epoch: Epoch,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
lockup: Slot,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stake,
|
stake,
|
||||||
|
@ -272,6 +277,7 @@ impl Stake {
|
||||||
voter_pubkey: *voter_pubkey,
|
voter_pubkey: *voter_pubkey,
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
config: *config,
|
config: *config,
|
||||||
|
lockup,
|
||||||
..Stake::default()
|
..Stake::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,6 +288,7 @@ impl Stake {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait StakeAccount {
|
pub trait StakeAccount {
|
||||||
|
fn lockup(&mut self, slot: Slot) -> Result<(), InstructionError>;
|
||||||
fn delegate_stake(
|
fn delegate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
vote_account: &KeyedAccount,
|
vote_account: &KeyedAccount,
|
||||||
|
@ -311,6 +318,13 @@ pub trait StakeAccount {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StakeAccount for KeyedAccount<'a> {
|
impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
|
fn lockup(&mut self, lockup: Slot) -> Result<(), InstructionError> {
|
||||||
|
if let StakeState::Uninitialized = self.state()? {
|
||||||
|
self.set_state(&StakeState::Lockup(lockup))
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
}
|
||||||
|
}
|
||||||
fn delegate_stake(
|
fn delegate_stake(
|
||||||
&mut self,
|
&mut self,
|
||||||
vote_account: &KeyedAccount,
|
vote_account: &KeyedAccount,
|
||||||
|
@ -326,13 +340,14 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
return Err(InstructionError::InsufficientFunds);
|
return Err(InstructionError::InsufficientFunds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let StakeState::Uninitialized = self.state()? {
|
if let StakeState::Lockup(lockup) = self.state()? {
|
||||||
let stake = Stake::new(
|
let stake = Stake::new(
|
||||||
new_stake,
|
new_stake,
|
||||||
vote_account.unsigned_key(),
|
vote_account.unsigned_key(),
|
||||||
&vote_account.state()?,
|
&vote_account.state()?,
|
||||||
clock.epoch,
|
clock.epoch,
|
||||||
config,
|
config,
|
||||||
|
lockup,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.set_state(&StakeState::Stake(stake))
|
self.set_state(&StakeState::Stake(stake))
|
||||||
|
@ -410,6 +425,19 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transfer(
|
||||||
|
from: &mut Account,
|
||||||
|
to: &mut Account,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
if lamports > from.lamports {
|
||||||
|
return Err(InstructionError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
from.lamports -= lamports;
|
||||||
|
to.lamports += lamports;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
match self.state()? {
|
match self.state()? {
|
||||||
StakeState::Stake(stake) => {
|
StakeState::Stake(stake) => {
|
||||||
// if we have a deactivation epoch and we're in cooldown
|
// if we have a deactivation epoch and we're in cooldown
|
||||||
|
@ -425,20 +453,16 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
if lamports > self.account.lamports.saturating_sub(staked) {
|
if lamports > self.account.lamports.saturating_sub(staked) {
|
||||||
return Err(InstructionError::InsufficientFunds);
|
return Err(InstructionError::InsufficientFunds);
|
||||||
}
|
}
|
||||||
self.account.lamports -= lamports;
|
|
||||||
to.account.lamports += lamports;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
StakeState::Uninitialized => {
|
StakeState::Lockup(lockup) => {
|
||||||
if lamports > self.account.lamports {
|
if lockup > clock.slot {
|
||||||
return Err(InstructionError::InsufficientFunds);
|
return Err(InstructionError::InsufficientFunds);
|
||||||
}
|
}
|
||||||
self.account.lamports -= lamports;
|
|
||||||
to.account.lamports += lamports;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
_ => Err(InstructionError::InvalidAccountData),
|
StakeState::Uninitialized => {}
|
||||||
|
_ => return Err(InstructionError::InvalidAccountData),
|
||||||
}
|
}
|
||||||
|
transfer(&mut self.account, &mut to.account, lamports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,15 +570,20 @@ mod tests {
|
||||||
|
|
||||||
let stake_pubkey = Pubkey::default();
|
let stake_pubkey = Pubkey::default();
|
||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account =
|
let mut stake_account = Account::new_data_with_space(
|
||||||
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
stake_lamports,
|
||||||
|
&StakeState::Lockup(0),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
// unsigned keyed account
|
// unsigned keyed account
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
|
|
||||||
{
|
{
|
||||||
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
||||||
assert_eq!(stake_state, StakeState::default());
|
assert_eq!(stake_state, StakeState::Lockup(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -583,7 +612,8 @@ mod tests {
|
||||||
stake: stake_lamports,
|
stake: stake_lamports,
|
||||||
activation_epoch: clock.epoch,
|
activation_epoch: clock.epoch,
|
||||||
deactivation_epoch: std::u64::MAX,
|
deactivation_epoch: std::u64::MAX,
|
||||||
config: Config::default()
|
config: Config::default(),
|
||||||
|
lockup: 0
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// verify that delegate_stake can't be called twice StakeState::default()
|
// verify that delegate_stake can't be called twice StakeState::default()
|
||||||
|
@ -865,12 +895,41 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deactivate_stake() {
|
fn test_stake_lockup() {
|
||||||
let stake_pubkey = Pubkey::new_rand();
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account =
|
let mut stake_account =
|
||||||
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
||||||
|
|
||||||
|
// unsigned keyed account
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
|
||||||
|
assert_eq!(stake_keyed_account.lockup(1), Ok(()));
|
||||||
|
|
||||||
|
// first time works, as is uninit
|
||||||
|
assert_eq!(
|
||||||
|
StakeState::from(&stake_keyed_account.account).unwrap(),
|
||||||
|
StakeState::Lockup(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2nd time fails, can't move it from anything other than uninit->lockup
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.lockup(1),
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deactivate_stake() {
|
||||||
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
|
let stake_lamports = 42;
|
||||||
|
let mut stake_account = Account::new_data_with_space(
|
||||||
|
stake_lamports,
|
||||||
|
&StakeState::Lockup(0),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
let clock = sysvar::clock::Clock {
|
let clock = sysvar::clock::Clock {
|
||||||
epoch: 1,
|
epoch: 1,
|
||||||
..sysvar::clock::Clock::default()
|
..sysvar::clock::Clock::default()
|
||||||
|
@ -923,8 +982,13 @@ mod tests {
|
||||||
let stake_pubkey = Pubkey::new_rand();
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
let total_lamports = 100;
|
let total_lamports = 100;
|
||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account =
|
let mut stake_account = Account::new_data_with_space(
|
||||||
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
|
total_lamports,
|
||||||
|
&StakeState::Lockup(0),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
let mut clock = sysvar::clock::Clock::default();
|
let mut clock = sysvar::clock::Clock::default();
|
||||||
|
|
||||||
|
@ -1051,8 +1115,13 @@ mod tests {
|
||||||
let stake_pubkey = Pubkey::new_rand();
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
let total_lamports = 100;
|
let total_lamports = 100;
|
||||||
let stake_lamports = 42;
|
let stake_lamports = 42;
|
||||||
let mut stake_account =
|
let mut stake_account = Account::new_data_with_space(
|
||||||
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
|
total_lamports,
|
||||||
|
&StakeState::Lockup(0),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
let clock = sysvar::clock::Clock::default();
|
let clock = sysvar::clock::Clock::default();
|
||||||
let mut future = sysvar::clock::Clock::default();
|
let mut future = sysvar::clock::Clock::default();
|
||||||
|
@ -1102,21 +1171,49 @@ mod tests {
|
||||||
fn test_withdraw_stake_invalid_state() {
|
fn test_withdraw_stake_invalid_state() {
|
||||||
let stake_pubkey = Pubkey::new_rand();
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
let total_lamports = 100;
|
let total_lamports = 100;
|
||||||
let mut stake_account =
|
let mut stake_account = Account::new_data_with_space(
|
||||||
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
|
total_lamports,
|
||||||
|
&StakeState::RewardsPool,
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");;
|
||||||
|
|
||||||
let clock = sysvar::clock::Clock::default();
|
let to = Pubkey::new_rand();
|
||||||
let mut future = sysvar::clock::Clock::default();
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
future.epoch += 16;
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.withdraw(
|
||||||
|
total_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
|
&sysvar::clock::Clock::default(),
|
||||||
|
&StakeHistory::default()
|
||||||
|
),
|
||||||
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_withdraw_lockout() {
|
||||||
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
|
let total_lamports = 100;
|
||||||
|
let mut stake_account = Account::new_data_with_space(
|
||||||
|
total_lamports,
|
||||||
|
&StakeState::Lockup(1),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(1, 0, &system_program::id());
|
let mut to_account = Account::new(1, 0, &system_program::id());
|
||||||
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
let stake_state = StakeState::RewardsPool;
|
|
||||||
stake_keyed_account.set_state(&stake_state).unwrap();
|
|
||||||
|
|
||||||
|
let mut clock = sysvar::clock::Clock::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.withdraw(
|
stake_keyed_account.withdraw(
|
||||||
total_lamports,
|
total_lamports,
|
||||||
|
@ -1124,7 +1221,18 @@ mod tests {
|
||||||
&clock,
|
&clock,
|
||||||
&StakeHistory::default()
|
&StakeHistory::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InsufficientFunds)
|
||||||
|
);
|
||||||
|
|
||||||
|
clock.slot += 1;
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.withdraw(
|
||||||
|
total_lamports,
|
||||||
|
&mut to_keyed_account,
|
||||||
|
&clock,
|
||||||
|
&StakeHistory::default()
|
||||||
|
),
|
||||||
|
Ok(())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,8 +1329,14 @@ mod tests {
|
||||||
|
|
||||||
let pubkey = Pubkey::default();
|
let pubkey = Pubkey::default();
|
||||||
let stake_lamports = 100;
|
let stake_lamports = 100;
|
||||||
let mut stake_account =
|
let mut stake_account = Account::new_data_with_space(
|
||||||
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
stake_lamports,
|
||||||
|
&StakeState::Lockup(0),
|
||||||
|
std::mem::size_of::<StakeState>(),
|
||||||
|
&id(),
|
||||||
|
)
|
||||||
|
.expect("stake_account");
|
||||||
|
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
||||||
|
|
||||||
let vote_pubkey = Pubkey::new_rand();
|
let vote_pubkey = Pubkey::new_rand();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bincode::{deserialize_from, serialize_into, serialized_size};
|
use bincode::{deserialize_from, serialize_into, serialized_size};
|
||||||
use memmap::MmapMut;
|
use memmap::MmapMut;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::{account::Account, pubkey::Pubkey, Epoch};
|
use solana_sdk::{account::Account, pubkey::Pubkey, timing::Epoch};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{create_dir_all, remove_file, OpenOptions};
|
use std::fs::{create_dir_all, remove_file, OpenOptions};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::pubkey::Pubkey;
|
use crate::{pubkey::Pubkey, timing::Epoch};
|
||||||
use crate::Epoch;
|
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
/// An Account with data that is stored on chain
|
/// An Account with data that is stored on chain
|
||||||
|
@ -64,6 +63,19 @@ impl Account {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_data_with_space<T: serde::Serialize>(
|
||||||
|
lamports: u64,
|
||||||
|
state: &T,
|
||||||
|
space: usize,
|
||||||
|
owner: &Pubkey,
|
||||||
|
) -> Result<Account, bincode::Error> {
|
||||||
|
let mut account = Self::new(lamports, space, owner);
|
||||||
|
|
||||||
|
account.serialize_data(state)?;
|
||||||
|
|
||||||
|
Ok(account)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
|
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
|
||||||
bincode::deserialize(&self.data)
|
bincode::deserialize(&self.data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,3 @@ pub mod transport;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
pub type Epoch = u64;
|
|
||||||
pub type Slot = u64;
|
|
||||||
|
|
Loading…
Reference in New Issue