add activate_stake to stake_api (#4600)
This commit is contained in:
parent
be3a0b6b10
commit
a18c0e34f4
|
@ -428,31 +428,16 @@ impl LocalCluster {
|
||||||
let stake_account_keypair = Keypair::new();
|
let stake_account_keypair = Keypair::new();
|
||||||
let stake_account_pubkey = stake_account_keypair.pubkey();
|
let stake_account_pubkey = stake_account_keypair.pubkey();
|
||||||
let mut transaction = Transaction::new_signed_instructions(
|
let mut transaction = Transaction::new_signed_instructions(
|
||||||
&[from_account.as_ref()],
|
&[from_account.as_ref(), &stake_account_keypair],
|
||||||
stake_instruction::create_delegate_account(
|
stake_instruction::create_stake_account_and_delegate_stake(
|
||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
|
&vote_account_pubkey,
|
||||||
amount,
|
amount,
|
||||||
),
|
),
|
||||||
client.get_recent_blockhash().unwrap().0,
|
client.get_recent_blockhash().unwrap().0,
|
||||||
);
|
);
|
||||||
|
|
||||||
client
|
|
||||||
.retry_transfer(&from_account, &mut transaction, 5)
|
|
||||||
.expect("fund stake");
|
|
||||||
client
|
|
||||||
.wait_for_balance(&stake_account_pubkey, Some(amount))
|
|
||||||
.expect("get balance");
|
|
||||||
|
|
||||||
let mut transaction = Transaction::new_signed_with_payer(
|
|
||||||
vec![stake_instruction::delegate_stake(
|
|
||||||
&stake_account_pubkey,
|
|
||||||
&vote_account_pubkey,
|
|
||||||
)],
|
|
||||||
Some(&from_account.pubkey()),
|
|
||||||
&[from_account.as_ref(), &stake_account_keypair],
|
|
||||||
client.get_recent_blockhash().unwrap().0,
|
|
||||||
);
|
|
||||||
client
|
client
|
||||||
.send_and_confirm_transaction(
|
.send_and_confirm_transaction(
|
||||||
&[from_account.as_ref(), &stake_account_keypair],
|
&[from_account.as_ref(), &stake_account_keypair],
|
||||||
|
@ -461,6 +446,9 @@ impl LocalCluster {
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
.expect("delegate stake");
|
.expect("delegate stake");
|
||||||
|
client
|
||||||
|
.wait_for_balance(&stake_account_pubkey, Some(amount))
|
||||||
|
.expect("get balance");
|
||||||
}
|
}
|
||||||
info!("Checking for vote account registration");
|
info!("Checking for vote account registration");
|
||||||
let vote_account_user_data = client.get_account_data(&vote_account_pubkey);
|
let vote_account_user_data = client.get_account_data(&vote_account_pubkey);
|
||||||
|
|
|
@ -193,22 +193,14 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
process_instructions(
|
process_instructions(
|
||||||
bank,
|
bank,
|
||||||
&[from_account],
|
&[from_account, &stake_account_keypair],
|
||||||
stake_instruction::create_delegate_account(
|
stake_instruction::create_stake_account_and_delegate_stake(
|
||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
|
vote_pubkey,
|
||||||
amount,
|
amount,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
process_instructions(
|
|
||||||
bank,
|
|
||||||
&[from_account, &stake_account_keypair],
|
|
||||||
vec![stake_instruction::delegate_stake(
|
|
||||||
&stake_account_pubkey,
|
|
||||||
vote_pubkey,
|
|
||||||
)],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -245,7 +245,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||||
// passive bootstrap leader stake
|
// passive bootstrap leader stake
|
||||||
(
|
(
|
||||||
bootstrap_stake_keypair.pubkey(),
|
bootstrap_stake_keypair.pubkey(),
|
||||||
stake_state::create_delegate_stake_account(
|
stake_state::create_stake_account(
|
||||||
&bootstrap_vote_keypair.pubkey(),
|
&bootstrap_vote_keypair.pubkey(),
|
||||||
&vote_state,
|
&vote_state,
|
||||||
bootstrap_leader_stake_lamports,
|
bootstrap_leader_stake_lamports,
|
||||||
|
|
|
@ -112,7 +112,7 @@ setup_validator_accounts() {
|
||||||
# Delegate the stake. The transaction fee is paid by the node but the
|
# Delegate the stake. The transaction fee is paid by the node but the
|
||||||
# transaction must be signed by the stake_keypair
|
# transaction must be signed by the stake_keypair
|
||||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||||
delegate-stake "$stake_keypair_path" "$vote_pubkey" || return $?
|
delegate-stake "$stake_keypair_path" "$vote_pubkey" "$stake_lamports" || return $?
|
||||||
|
|
||||||
# Setup validator storage account
|
# Setup validator storage account
|
||||||
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
|
||||||
|
|
|
@ -10,39 +10,40 @@ use solana_sdk::system_instruction;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum StakeInstruction {
|
pub enum StakeInstruction {
|
||||||
/// Initialize the stake account as a Delegate account.
|
/// Initialize the stake account as a Stake account.
|
||||||
///
|
///
|
||||||
/// Expects 2 Accounts:
|
/// Expects 1 Accounts:
|
||||||
/// 0 - payer (TODO unused/remove)
|
/// 0 - StakeAccount to be initialized
|
||||||
/// 1 - Delegate StakeAccount to be initialized
|
InitializeStake,
|
||||||
InitializeDelegate,
|
|
||||||
|
|
||||||
// Initialize the stake account as a MiningPool account
|
// Initialize the stake account as a MiningPool account
|
||||||
///
|
///
|
||||||
/// Expects 2 Accounts:
|
/// Expects 1 Accounts:
|
||||||
/// 0 - payer (TODO unused/remove)
|
/// 0 - MiningPool StakeAccount to be initialized
|
||||||
/// 1 - MiningPool StakeAccount to be initialized
|
|
||||||
InitializeMiningPool,
|
InitializeMiningPool,
|
||||||
|
|
||||||
/// `Delegate` or `Assign` a stake account to a particular node
|
/// `Delegate` a stake to a particular node
|
||||||
///
|
///
|
||||||
/// Expects 3 Accounts:
|
/// Expects 2 Accounts:
|
||||||
/// 0 - payer (TODO unused/remove)
|
/// 0 - Delegate StakeAccount to be updated <= must have this signature
|
||||||
/// 1 - Delegate StakeAccount to be updated
|
/// 1 - VoteAccount to which this Stake will be delegated
|
||||||
/// 2 - VoteAccount to which this Stake will be delegated
|
///
|
||||||
DelegateStake,
|
/// The u64 is the portion of the Stake account balance to be activated,
|
||||||
|
/// must be less than StakeAccount.lamports
|
||||||
|
///
|
||||||
|
/// This instruction resets rewards, so issue
|
||||||
|
DelegateStake(u64),
|
||||||
|
|
||||||
/// Redeem credits in the stake account
|
/// Redeem credits in the stake account
|
||||||
///
|
///
|
||||||
/// Expects 4 Accounts:
|
/// Expects 3 Accounts:
|
||||||
/// 0 - payer (TODO unused/remove)
|
/// 0 - MiningPool Stake Account to redeem credits from
|
||||||
/// 1 - MiningPool Stake Account to redeem credits from
|
/// 1 - Delegate StakeAccount to be updated
|
||||||
/// 2 - Delegate StakeAccount to be updated
|
/// 2 - VoteAccount to which the Stake is delegated,
|
||||||
/// 3 - VoteAccount to which the Stake is delegated
|
|
||||||
RedeemVoteCredits,
|
RedeemVoteCredits,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_delegate_account(
|
pub fn create_stake_account(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
staker_pubkey: &Pubkey,
|
staker_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
|
@ -57,12 +58,23 @@ pub fn create_delegate_account(
|
||||||
),
|
),
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
id(),
|
id(),
|
||||||
&StakeInstruction::InitializeDelegate,
|
&StakeInstruction::InitializeStake,
|
||||||
vec![AccountMeta::new(*staker_pubkey, false)],
|
vec![AccountMeta::new(*staker_pubkey, false)],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_stake_account_and_delegate_stake(
|
||||||
|
from_pubkey: &Pubkey,
|
||||||
|
staker_pubkey: &Pubkey,
|
||||||
|
vote_pubkey: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
let mut instructions = create_stake_account(from_pubkey, staker_pubkey, lamports);
|
||||||
|
instructions.push(delegate_stake(staker_pubkey, vote_pubkey, lamports));
|
||||||
|
instructions
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_mining_pool_account(
|
pub fn create_mining_pool_account(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
staker_pubkey: &Pubkey,
|
staker_pubkey: &Pubkey,
|
||||||
|
@ -97,12 +109,12 @@ pub fn redeem_vote_credits(
|
||||||
Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
|
Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
|
pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey, stake: u64) -> Instruction {
|
||||||
let account_metas = vec![
|
let account_metas = vec![
|
||||||
AccountMeta::new(*stake_pubkey, true),
|
AccountMeta::new(*stake_pubkey, true),
|
||||||
AccountMeta::new(*vote_pubkey, false),
|
AccountMeta::new(*vote_pubkey, false),
|
||||||
];
|
];
|
||||||
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
Instruction::new(id(), &StakeInstruction::DelegateStake(stake), account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
|
@ -130,18 +142,18 @@ pub fn process_instruction(
|
||||||
}
|
}
|
||||||
me.initialize_mining_pool()
|
me.initialize_mining_pool()
|
||||||
}
|
}
|
||||||
StakeInstruction::InitializeDelegate => {
|
StakeInstruction::InitializeStake => {
|
||||||
if !rest.is_empty() {
|
if !rest.is_empty() {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
me.initialize_delegate()
|
me.initialize_stake()
|
||||||
}
|
}
|
||||||
StakeInstruction::DelegateStake => {
|
StakeInstruction::DelegateStake(stake) => {
|
||||||
if rest.len() != 1 {
|
if rest.len() != 1 {
|
||||||
Err(InstructionError::InvalidInstructionData)?;
|
Err(InstructionError::InvalidInstructionData)?;
|
||||||
}
|
}
|
||||||
let vote = &rest[0];
|
let vote = &rest[0];
|
||||||
me.delegate_stake(vote)
|
me.delegate_stake(vote, stake)
|
||||||
}
|
}
|
||||||
StakeInstruction::RedeemVoteCredits => {
|
StakeInstruction::RedeemVoteCredits => {
|
||||||
if rest.len() != 2 {
|
if rest.len() != 2 {
|
||||||
|
@ -189,7 +201,7 @@ mod tests {
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&delegate_stake(&Pubkey::default(), &Pubkey::default())),
|
process_instruction(&delegate_stake(&Pubkey::default(), &Pubkey::default(), 0)),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -207,7 +219,7 @@ mod tests {
|
||||||
false,
|
false,
|
||||||
&mut Account::default(),
|
&mut Account::default(),
|
||||||
)],
|
)],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::InvalidInstructionData),
|
||||||
);
|
);
|
||||||
|
@ -221,7 +233,7 @@ mod tests {
|
||||||
false,
|
false,
|
||||||
&mut Account::default()
|
&mut Account::default()
|
||||||
),],
|
),],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidInstructionData),
|
Err(InstructionError::InvalidInstructionData),
|
||||||
);
|
);
|
||||||
|
@ -246,7 +258,7 @@ mod tests {
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default()),
|
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default()),
|
||||||
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
|
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
|
||||||
],
|
],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,9 +14,10 @@ use solana_vote_api::vote_state::VoteState;
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
pub enum StakeState {
|
pub enum StakeState {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
Delegate {
|
Stake {
|
||||||
voter_pubkey: Pubkey,
|
voter_pubkey: Pubkey,
|
||||||
credits_observed: u64,
|
credits_observed: u64,
|
||||||
|
stake: u64,
|
||||||
},
|
},
|
||||||
MiningPool,
|
MiningPool,
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,7 @@ impl StakeState {
|
||||||
|
|
||||||
pub fn voter_pubkey(&self) -> Option<Pubkey> {
|
pub fn voter_pubkey(&self) -> Option<Pubkey> {
|
||||||
match self {
|
match self {
|
||||||
StakeState::Delegate { voter_pubkey, .. } => Some(*voter_pubkey),
|
StakeState::Stake { voter_pubkey, .. } => Some(*voter_pubkey),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,8 +90,12 @@ impl StakeState {
|
||||||
|
|
||||||
pub trait StakeAccount {
|
pub trait StakeAccount {
|
||||||
fn initialize_mining_pool(&mut self) -> Result<(), InstructionError>;
|
fn initialize_mining_pool(&mut self) -> Result<(), InstructionError>;
|
||||||
fn initialize_delegate(&mut self) -> Result<(), InstructionError>;
|
fn initialize_stake(&mut self) -> Result<(), InstructionError>;
|
||||||
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError>;
|
fn delegate_stake(
|
||||||
|
&mut self,
|
||||||
|
vote_account: &KeyedAccount,
|
||||||
|
stake: u64,
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
fn redeem_vote_credits(
|
fn redeem_vote_credits(
|
||||||
&mut self,
|
&mut self,
|
||||||
stake_account: &mut KeyedAccount,
|
stake_account: &mut KeyedAccount,
|
||||||
|
@ -106,26 +111,35 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn initialize_delegate(&mut self) -> Result<(), InstructionError> {
|
fn initialize_stake(&mut self) -> Result<(), InstructionError> {
|
||||||
if let StakeState::Uninitialized = self.state()? {
|
if let StakeState::Uninitialized = self.state()? {
|
||||||
self.set_state(&StakeState::Delegate {
|
self.set_state(&StakeState::Stake {
|
||||||
voter_pubkey: Pubkey::default(),
|
voter_pubkey: Pubkey::default(),
|
||||||
credits_observed: 0,
|
credits_observed: 0,
|
||||||
|
stake: 0,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn delegate_stake(&mut self, vote_account: &KeyedAccount) -> Result<(), InstructionError> {
|
fn delegate_stake(
|
||||||
|
&mut self,
|
||||||
|
vote_account: &KeyedAccount,
|
||||||
|
stake: u64,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
if self.signer_key().is_none() {
|
if self.signer_key().is_none() {
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
if stake > self.account.lamports {
|
||||||
|
return Err(InstructionError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
|
||||||
if let StakeState::Delegate { .. } = self.state()? {
|
if let StakeState::Stake { .. } = self.state()? {
|
||||||
let vote_state: VoteState = vote_account.state()?;
|
let vote_state: VoteState = vote_account.state()?;
|
||||||
self.set_state(&StakeState::Delegate {
|
self.set_state(&StakeState::Stake {
|
||||||
voter_pubkey: *vote_account.unsigned_key(),
|
voter_pubkey: *vote_account.unsigned_key(),
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
|
stake,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
|
@ -139,9 +153,10 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let (
|
if let (
|
||||||
StakeState::MiningPool,
|
StakeState::MiningPool,
|
||||||
StakeState::Delegate {
|
StakeState::Stake {
|
||||||
voter_pubkey,
|
voter_pubkey,
|
||||||
credits_observed,
|
credits_observed,
|
||||||
|
..
|
||||||
},
|
},
|
||||||
) = (self.state()?, stake_account.state()?)
|
) = (self.state()?, stake_account.state()?)
|
||||||
{
|
{
|
||||||
|
@ -167,9 +182,10 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
stake_account.account.lamports += stakers_reward;
|
stake_account.account.lamports += stakers_reward;
|
||||||
vote_account.account.lamports += voters_reward;
|
vote_account.account.lamports += voters_reward;
|
||||||
|
|
||||||
stake_account.set_state(&StakeState::Delegate {
|
stake_account.set_state(&StakeState::Stake {
|
||||||
voter_pubkey,
|
voter_pubkey,
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
|
stake: 0,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// not worth collecting
|
// not worth collecting
|
||||||
|
@ -182,7 +198,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// utility function, used by Bank, tests, genesis
|
// utility function, used by Bank, tests, genesis
|
||||||
pub fn create_delegate_stake_account(
|
pub fn create_stake_account(
|
||||||
voter_pubkey: &Pubkey,
|
voter_pubkey: &Pubkey,
|
||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
|
@ -190,9 +206,10 @@ pub fn create_delegate_stake_account(
|
||||||
let mut stake_account = Account::new(lamports, std::mem::size_of::<StakeState>(), &id());
|
let mut stake_account = Account::new(lamports, std::mem::size_of::<StakeState>(), &id());
|
||||||
|
|
||||||
stake_account
|
stake_account
|
||||||
.set_state(&StakeState::Delegate {
|
.set_state(&StakeState::Stake {
|
||||||
voter_pubkey: *voter_pubkey,
|
voter_pubkey: *voter_pubkey,
|
||||||
credits_observed: vote_state.credits(),
|
credits_observed: vote_state.credits(),
|
||||||
|
stake: lamports,
|
||||||
})
|
})
|
||||||
.expect("set_state");
|
.expect("set_state");
|
||||||
|
|
||||||
|
@ -223,7 +240,9 @@ mod tests {
|
||||||
vote_keyed_account.set_state(&vote_state).unwrap();
|
vote_keyed_account.set_state(&vote_state).unwrap();
|
||||||
|
|
||||||
let stake_pubkey = Pubkey::default();
|
let stake_pubkey = Pubkey::default();
|
||||||
let mut stake_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
let stake_lamports = 42;
|
||||||
|
let mut stake_account =
|
||||||
|
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -232,37 +251,45 @@ mod tests {
|
||||||
assert_eq!(stake_state, StakeState::default());
|
assert_eq!(stake_state, StakeState::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
stake_keyed_account.initialize_delegate().unwrap();
|
stake_keyed_account.initialize_stake().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate_stake(&vote_keyed_account),
|
stake_keyed_account.delegate_stake(&vote_keyed_account, 0),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
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);
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account)
|
.delegate_stake(&vote_keyed_account, stake_lamports)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// verify that create_delegate_stake_account() matches the
|
// verify can only stake up to account lamports
|
||||||
|
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
|
||||||
|
assert_eq!(
|
||||||
|
stake_keyed_account.delegate_stake(&vote_keyed_account, stake_lamports + 1),
|
||||||
|
Err(InstructionError::InsufficientFunds)
|
||||||
|
);
|
||||||
|
|
||||||
|
// verify that create_stake_account() matches the
|
||||||
// resulting account from delegate_stake()
|
// resulting account from delegate_stake()
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_delegate_stake_account(&vote_pubkey, &vote_state, 0),
|
create_stake_account(&vote_pubkey, &vote_state, stake_lamports),
|
||||||
*stake_keyed_account.account,
|
*stake_keyed_account.account,
|
||||||
);
|
);
|
||||||
|
|
||||||
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
let stake_state: StakeState = stake_keyed_account.state().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_state,
|
stake_state,
|
||||||
StakeState::Delegate {
|
StakeState::Stake {
|
||||||
voter_pubkey: vote_keypair.pubkey(),
|
voter_pubkey: vote_keypair.pubkey(),
|
||||||
credits_observed: vote_state.credits()
|
credits_observed: vote_state.credits(),
|
||||||
|
stake: stake_lamports,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let stake_state = StakeState::MiningPool;
|
let stake_state = StakeState::MiningPool;
|
||||||
stake_keyed_account.set_state(&stake_state).unwrap();
|
stake_keyed_account.set_state(&stake_state).unwrap();
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account)
|
.delegate_stake(&vote_keyed_account, 0)
|
||||||
.is_err());
|
.is_err());
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -334,11 +361,11 @@ mod tests {
|
||||||
&id(),
|
&id(),
|
||||||
);
|
);
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
||||||
stake_keyed_account.initialize_delegate().unwrap();
|
stake_keyed_account.initialize_stake().unwrap();
|
||||||
|
|
||||||
// delegate the stake
|
// delegate the stake
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account)
|
.delegate_stake(&vote_keyed_account, STAKE_GETS_PAID_EVERY_VOTE)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
let mut mining_pool_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
let mut mining_pool_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
||||||
|
@ -402,13 +429,15 @@ mod tests {
|
||||||
vote_keyed_account.set_state(&vote_state).unwrap();
|
vote_keyed_account.set_state(&vote_state).unwrap();
|
||||||
|
|
||||||
let pubkey = Pubkey::default();
|
let pubkey = Pubkey::default();
|
||||||
let mut stake_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
let stake_lamports = 0;
|
||||||
|
let mut stake_account =
|
||||||
|
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
|
||||||
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
let mut stake_keyed_account = KeyedAccount::new(&pubkey, true, &mut stake_account);
|
||||||
stake_keyed_account.initialize_delegate().unwrap();
|
stake_keyed_account.initialize_stake().unwrap();
|
||||||
|
|
||||||
// delegate the stake
|
// delegate the stake
|
||||||
assert!(stake_keyed_account
|
assert!(stake_keyed_account
|
||||||
.delegate_stake(&vote_keyed_account)
|
.delegate_stake(&vote_keyed_account, stake_lamports)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
let mut mining_pool_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
let mut mining_pool_account = Account::new(0, std::mem::size_of::<StakeState>(), &id());
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub fn create_genesis_block_with_leader(
|
||||||
// passive bootstrap leader stake, duplicates above temporarily
|
// passive bootstrap leader stake, duplicates above temporarily
|
||||||
(
|
(
|
||||||
staking_keypair.pubkey(),
|
staking_keypair.pubkey(),
|
||||||
stake_state::create_delegate_stake_account(
|
stake_state::create_stake_account(
|
||||||
&voting_keypair.pubkey(),
|
&voting_keypair.pubkey(),
|
||||||
&vote_state,
|
&vote_state,
|
||||||
bootstrap_leader_stake_lamports,
|
bootstrap_leader_stake_lamports,
|
||||||
|
|
|
@ -100,7 +100,7 @@ mod tests {
|
||||||
fn create_stake_account(stake: u64, vote_pubkey: &Pubkey) -> (Pubkey, Account) {
|
fn create_stake_account(stake: u64, vote_pubkey: &Pubkey) -> (Pubkey, Account) {
|
||||||
(
|
(
|
||||||
Pubkey::new_rand(),
|
Pubkey::new_rand(),
|
||||||
stake_state::create_delegate_stake_account(&vote_pubkey, &VoteState::default(), stake),
|
stake_state::create_stake_account(&vote_pubkey, &VoteState::default(), stake),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ pub enum InstructionError {
|
||||||
/// An account's data was too small
|
/// An account's data was too small
|
||||||
AccountDataTooSmall,
|
AccountDataTooSmall,
|
||||||
|
|
||||||
|
/// An account's balance was too small to complete the instruction
|
||||||
|
InsufficientFunds,
|
||||||
|
|
||||||
/// The account did not have the expected program id
|
/// The account did not have the expected program id
|
||||||
IncorrectProgramId,
|
IncorrectProgramId,
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub enum WalletCommand {
|
||||||
ShowVoteAccount(Pubkey),
|
ShowVoteAccount(Pubkey),
|
||||||
CreateStakeAccount(Pubkey, u64),
|
CreateStakeAccount(Pubkey, u64),
|
||||||
CreateMiningPoolAccount(Pubkey, u64),
|
CreateMiningPoolAccount(Pubkey, u64),
|
||||||
DelegateStake(Keypair, Pubkey),
|
DelegateStake(Keypair, Pubkey, u64),
|
||||||
RedeemVoteCredits(Pubkey, Pubkey, Pubkey),
|
RedeemVoteCredits(Pubkey, Pubkey, Pubkey),
|
||||||
ShowStakeAccount(Pubkey),
|
ShowStakeAccount(Pubkey),
|
||||||
CreateStorageMiningPoolAccount(Pubkey, u64),
|
CreateStorageMiningPoolAccount(Pubkey, u64),
|
||||||
|
@ -142,16 +142,26 @@ impl WalletConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the pubkey for an argument with `name` or None if not present.
|
// Return parsed values from matches at `name`
|
||||||
fn pubkey_of(matches: &ArgMatches<'_>, name: &str) -> Option<Pubkey> {
|
fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
|
||||||
matches.value_of(name).map(|x| x.parse::<Pubkey>().unwrap())
|
where
|
||||||
}
|
T: std::str::FromStr,
|
||||||
|
<T as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
// Return the pubkeys for arguments with `name` or None if none present.
|
{
|
||||||
fn pubkeys_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Pubkey>> {
|
|
||||||
matches
|
matches
|
||||||
.values_of(name)
|
.values_of(name)
|
||||||
.map(|xs| xs.map(|x| x.parse::<Pubkey>().unwrap()).collect())
|
.map(|xs| xs.map(|x| x.parse::<T>().unwrap()).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a parsed value from matches at `name`
|
||||||
|
fn value_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<T>
|
||||||
|
where
|
||||||
|
T: std::str::FromStr,
|
||||||
|
<T as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
|
{
|
||||||
|
matches
|
||||||
|
.value_of(name)
|
||||||
|
.map(|value| value.parse::<T>().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the keypair for an argument with filename `name` or None if not present.
|
// Return the keypair for an argument with filename `name` or None if not present.
|
||||||
|
@ -171,11 +181,11 @@ pub fn parse_command(
|
||||||
Ok(WalletCommand::Airdrop(lamports))
|
Ok(WalletCommand::Airdrop(lamports))
|
||||||
}
|
}
|
||||||
("balance", Some(balance_matches)) => {
|
("balance", Some(balance_matches)) => {
|
||||||
let pubkey = pubkey_of(&balance_matches, "pubkey").unwrap_or(*pubkey);
|
let pubkey = value_of(&balance_matches, "pubkey").unwrap_or(*pubkey);
|
||||||
Ok(WalletCommand::Balance(pubkey))
|
Ok(WalletCommand::Balance(pubkey))
|
||||||
}
|
}
|
||||||
("cancel", Some(cancel_matches)) => {
|
("cancel", Some(cancel_matches)) => {
|
||||||
let process_id = pubkey_of(cancel_matches, "process_id").unwrap();
|
let process_id = value_of(cancel_matches, "process_id").unwrap();
|
||||||
Ok(WalletCommand::Cancel(process_id))
|
Ok(WalletCommand::Cancel(process_id))
|
||||||
}
|
}
|
||||||
("confirm", Some(confirm_matches)) => {
|
("confirm", Some(confirm_matches)) => {
|
||||||
|
@ -188,8 +198,8 @@ pub fn parse_command(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("create-vote-account", Some(matches)) => {
|
("create-vote-account", Some(matches)) => {
|
||||||
let voting_account_pubkey = pubkey_of(matches, "voting_account_pubkey").unwrap();
|
let voting_account_pubkey = value_of(matches, "voting_account_pubkey").unwrap();
|
||||||
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
let node_pubkey = value_of(matches, "node_pubkey").unwrap();
|
||||||
let commission = if let Some(commission) = matches.value_of("commission") {
|
let commission = if let Some(commission) = matches.value_of("commission") {
|
||||||
commission.parse()?
|
commission.parse()?
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,11 +214,11 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("authorize-voter", Some(matches)) => {
|
("authorize-voter", Some(matches)) => {
|
||||||
let voting_account_pubkey = pubkey_of(matches, "voting_account_pubkey").unwrap();
|
let voting_account_pubkey = value_of(matches, "voting_account_pubkey").unwrap();
|
||||||
let authorized_voter_keypair =
|
let authorized_voter_keypair =
|
||||||
keypair_of(matches, "authorized_voter_keypair_file").unwrap();
|
keypair_of(matches, "authorized_voter_keypair_file").unwrap();
|
||||||
let new_authorized_voter_pubkey =
|
let new_authorized_voter_pubkey =
|
||||||
pubkey_of(matches, "new_authorized_voter_pubkey").unwrap();
|
value_of(matches, "new_authorized_voter_pubkey").unwrap();
|
||||||
|
|
||||||
Ok(WalletCommand::AuthorizeVoter(
|
Ok(WalletCommand::AuthorizeVoter(
|
||||||
voting_account_pubkey,
|
voting_account_pubkey,
|
||||||
|
@ -217,11 +227,11 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("show-vote-account", Some(matches)) => {
|
("show-vote-account", Some(matches)) => {
|
||||||
let voting_account_pubkey = pubkey_of(matches, "voting_account_pubkey").unwrap();
|
let voting_account_pubkey = value_of(matches, "voting_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::ShowVoteAccount(voting_account_pubkey))
|
Ok(WalletCommand::ShowVoteAccount(voting_account_pubkey))
|
||||||
}
|
}
|
||||||
("create-stake-account", Some(matches)) => {
|
("create-stake-account", Some(matches)) => {
|
||||||
let staking_account_pubkey = pubkey_of(matches, "staking_account_pubkey").unwrap();
|
let staking_account_pubkey = value_of(matches, "staking_account_pubkey").unwrap();
|
||||||
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
||||||
Ok(WalletCommand::CreateStakeAccount(
|
Ok(WalletCommand::CreateStakeAccount(
|
||||||
staking_account_pubkey,
|
staking_account_pubkey,
|
||||||
|
@ -230,7 +240,7 @@ pub fn parse_command(
|
||||||
}
|
}
|
||||||
("create-mining-pool-account", Some(matches)) => {
|
("create-mining-pool-account", Some(matches)) => {
|
||||||
let mining_pool_account_pubkey =
|
let mining_pool_account_pubkey =
|
||||||
pubkey_of(matches, "mining_pool_account_pubkey").unwrap();
|
value_of(matches, "mining_pool_account_pubkey").unwrap();
|
||||||
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
||||||
Ok(WalletCommand::CreateMiningPoolAccount(
|
Ok(WalletCommand::CreateMiningPoolAccount(
|
||||||
mining_pool_account_pubkey,
|
mining_pool_account_pubkey,
|
||||||
|
@ -240,17 +250,19 @@ pub fn parse_command(
|
||||||
("delegate-stake", Some(matches)) => {
|
("delegate-stake", Some(matches)) => {
|
||||||
let staking_account_keypair =
|
let staking_account_keypair =
|
||||||
keypair_of(matches, "staking_account_keypair_file").unwrap();
|
keypair_of(matches, "staking_account_keypair_file").unwrap();
|
||||||
let voting_account_pubkey = pubkey_of(matches, "voting_account_pubkey").unwrap();
|
let voting_account_pubkey = value_of(matches, "voting_account_pubkey").unwrap();
|
||||||
|
let stake = matches.value_of("stake").unwrap().parse()?;
|
||||||
Ok(WalletCommand::DelegateStake(
|
Ok(WalletCommand::DelegateStake(
|
||||||
staking_account_keypair,
|
staking_account_keypair,
|
||||||
voting_account_pubkey,
|
voting_account_pubkey,
|
||||||
|
stake,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("redeem-vote-credits", Some(matches)) => {
|
("redeem-vote-credits", Some(matches)) => {
|
||||||
let mining_pool_account_pubkey =
|
let mining_pool_account_pubkey =
|
||||||
pubkey_of(matches, "mining_pool_account_pubkey").unwrap();
|
value_of(matches, "mining_pool_account_pubkey").unwrap();
|
||||||
let staking_account_pubkey = pubkey_of(matches, "staking_account_pubkey").unwrap();
|
let staking_account_pubkey = value_of(matches, "staking_account_pubkey").unwrap();
|
||||||
let voting_account_pubkey = pubkey_of(matches, "voting_account_pubkey").unwrap();
|
let voting_account_pubkey = value_of(matches, "voting_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::RedeemVoteCredits(
|
Ok(WalletCommand::RedeemVoteCredits(
|
||||||
mining_pool_account_pubkey,
|
mining_pool_account_pubkey,
|
||||||
staking_account_pubkey,
|
staking_account_pubkey,
|
||||||
|
@ -258,12 +270,12 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("show-stake-account", Some(matches)) => {
|
("show-stake-account", Some(matches)) => {
|
||||||
let staking_account_pubkey = pubkey_of(matches, "staking_account_pubkey").unwrap();
|
let staking_account_pubkey = value_of(matches, "staking_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::ShowStakeAccount(staking_account_pubkey))
|
Ok(WalletCommand::ShowStakeAccount(staking_account_pubkey))
|
||||||
}
|
}
|
||||||
("create-storage-mining-pool-account", Some(matches)) => {
|
("create-storage-mining-pool-account", Some(matches)) => {
|
||||||
let storage_mining_pool_account_pubkey =
|
let storage_mining_pool_account_pubkey =
|
||||||
pubkey_of(matches, "storage_mining_pool_account_pubkey").unwrap();
|
value_of(matches, "storage_mining_pool_account_pubkey").unwrap();
|
||||||
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
let lamports = matches.value_of("lamports").unwrap().parse()?;
|
||||||
Ok(WalletCommand::CreateStorageMiningPoolAccount(
|
Ok(WalletCommand::CreateStorageMiningPoolAccount(
|
||||||
storage_mining_pool_account_pubkey,
|
storage_mining_pool_account_pubkey,
|
||||||
|
@ -271,16 +283,16 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("create-replicator-storage-account", Some(matches)) => {
|
("create-replicator-storage-account", Some(matches)) => {
|
||||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
let account_owner = value_of(matches, "storage_account_owner").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = value_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::CreateReplicatorStorageAccount(
|
Ok(WalletCommand::CreateReplicatorStorageAccount(
|
||||||
account_owner,
|
account_owner,
|
||||||
storage_account_pubkey,
|
storage_account_pubkey,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("create-validator-storage-account", Some(matches)) => {
|
("create-validator-storage-account", Some(matches)) => {
|
||||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
let account_owner = value_of(matches, "storage_account_owner").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = value_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::CreateValidatorStorageAccount(
|
Ok(WalletCommand::CreateValidatorStorageAccount(
|
||||||
account_owner,
|
account_owner,
|
||||||
storage_account_pubkey,
|
storage_account_pubkey,
|
||||||
|
@ -288,8 +300,8 @@ pub fn parse_command(
|
||||||
}
|
}
|
||||||
("claim-storage-reward", Some(matches)) => {
|
("claim-storage-reward", Some(matches)) => {
|
||||||
let storage_mining_pool_account_pubkey =
|
let storage_mining_pool_account_pubkey =
|
||||||
pubkey_of(matches, "storage_mining_pool_account_pubkey").unwrap();
|
value_of(matches, "storage_mining_pool_account_pubkey").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = value_of(matches, "storage_account_pubkey").unwrap();
|
||||||
let slot = matches.value_of("slot").unwrap().parse()?;
|
let slot = matches.value_of("slot").unwrap().parse()?;
|
||||||
Ok(WalletCommand::ClaimStorageReward(
|
Ok(WalletCommand::ClaimStorageReward(
|
||||||
storage_mining_pool_account_pubkey,
|
storage_mining_pool_account_pubkey,
|
||||||
|
@ -298,7 +310,7 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("show-storage-account", Some(matches)) => {
|
("show-storage-account", Some(matches)) => {
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = value_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(WalletCommand::ShowStorageAccount(storage_account_pubkey))
|
Ok(WalletCommand::ShowStorageAccount(storage_account_pubkey))
|
||||||
}
|
}
|
||||||
("deploy", Some(deploy_matches)) => Ok(WalletCommand::Deploy(
|
("deploy", Some(deploy_matches)) => Ok(WalletCommand::Deploy(
|
||||||
|
@ -310,7 +322,7 @@ pub fn parse_command(
|
||||||
("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
|
("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
|
||||||
("pay", Some(pay_matches)) => {
|
("pay", Some(pay_matches)) => {
|
||||||
let lamports = pay_matches.value_of("lamports").unwrap().parse()?;
|
let lamports = pay_matches.value_of("lamports").unwrap().parse()?;
|
||||||
let to = pubkey_of(&pay_matches, "to").unwrap_or(*pubkey);
|
let to = value_of(&pay_matches, "to").unwrap_or(*pubkey);
|
||||||
let timestamp = if pay_matches.is_present("timestamp") {
|
let timestamp = if pay_matches.is_present("timestamp") {
|
||||||
// Parse input for serde_json
|
// Parse input for serde_json
|
||||||
let date_string = if !pay_matches.value_of("timestamp").unwrap().contains('Z') {
|
let date_string = if !pay_matches.value_of("timestamp").unwrap().contains('Z') {
|
||||||
|
@ -322,8 +334,8 @@ pub fn parse_command(
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let timestamp_pubkey = pubkey_of(&pay_matches, "timestamp_pubkey");
|
let timestamp_pubkey = value_of(&pay_matches, "timestamp_pubkey");
|
||||||
let witness_vec = pubkeys_of(&pay_matches, "witness");
|
let witness_vec = values_of(&pay_matches, "witness");
|
||||||
let cancelable = if pay_matches.is_present("cancelable") {
|
let cancelable = if pay_matches.is_present("cancelable") {
|
||||||
Some(*pubkey)
|
Some(*pubkey)
|
||||||
} else {
|
} else {
|
||||||
|
@ -340,13 +352,13 @@ pub fn parse_command(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
("send-signature", Some(sig_matches)) => {
|
("send-signature", Some(sig_matches)) => {
|
||||||
let to = pubkey_of(&sig_matches, "to").unwrap();
|
let to = value_of(&sig_matches, "to").unwrap();
|
||||||
let process_id = pubkey_of(&sig_matches, "process_id").unwrap();
|
let process_id = value_of(&sig_matches, "process_id").unwrap();
|
||||||
Ok(WalletCommand::Witness(to, process_id))
|
Ok(WalletCommand::Witness(to, process_id))
|
||||||
}
|
}
|
||||||
("send-timestamp", Some(timestamp_matches)) => {
|
("send-timestamp", Some(timestamp_matches)) => {
|
||||||
let to = pubkey_of(×tamp_matches, "to").unwrap();
|
let to = value_of(×tamp_matches, "to").unwrap();
|
||||||
let process_id = pubkey_of(×tamp_matches, "process_id").unwrap();
|
let process_id = value_of(×tamp_matches, "process_id").unwrap();
|
||||||
let dt = if timestamp_matches.is_present("datetime") {
|
let dt = if timestamp_matches.is_present("datetime") {
|
||||||
// Parse input for serde_json
|
// Parse input for serde_json
|
||||||
let date_string = if !timestamp_matches
|
let date_string = if !timestamp_matches
|
||||||
|
@ -553,7 +565,7 @@ fn process_create_stake_account(
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let ixs = stake_instruction::create_delegate_account(
|
let ixs = stake_instruction::create_stake_account(
|
||||||
&config.keypair.pubkey(),
|
&config.keypair.pubkey(),
|
||||||
staking_account_pubkey,
|
staking_account_pubkey,
|
||||||
lamports,
|
lamports,
|
||||||
|
@ -595,11 +607,13 @@ fn process_delegate_stake(
|
||||||
config: &WalletConfig,
|
config: &WalletConfig,
|
||||||
staking_account_keypair: &Keypair,
|
staking_account_keypair: &Keypair,
|
||||||
voting_account_pubkey: &Pubkey,
|
voting_account_pubkey: &Pubkey,
|
||||||
|
stake: u64,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let ixs = vec![stake_instruction::delegate_stake(
|
let ixs = vec![stake_instruction::delegate_stake(
|
||||||
&staking_account_keypair.pubkey(),
|
&staking_account_keypair.pubkey(),
|
||||||
voting_account_pubkey,
|
voting_account_pubkey,
|
||||||
|
stake,
|
||||||
)];
|
)];
|
||||||
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -645,13 +659,15 @@ fn process_show_stake_account(
|
||||||
use solana_stake_api::stake_state::StakeState;
|
use solana_stake_api::stake_state::StakeState;
|
||||||
let stake_account = rpc_client.get_account(staking_account_pubkey)?;
|
let stake_account = rpc_client.get_account(staking_account_pubkey)?;
|
||||||
match stake_account.state() {
|
match stake_account.state() {
|
||||||
Ok(StakeState::Delegate {
|
Ok(StakeState::Stake {
|
||||||
voter_pubkey,
|
voter_pubkey,
|
||||||
credits_observed,
|
credits_observed,
|
||||||
|
stake,
|
||||||
}) => {
|
}) => {
|
||||||
println!("account lamports: {}", stake_account.lamports);
|
println!("account lamports: {}", stake_account.lamports);
|
||||||
println!("voter pubkey: {}", voter_pubkey);
|
println!("voter pubkey: {}", voter_pubkey);
|
||||||
println!("credits observed: {}", credits_observed);
|
println!("credits observed: {}", credits_observed);
|
||||||
|
println!("activated stake: {}", stake);
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
Ok(StakeState::MiningPool) => {
|
Ok(StakeState::MiningPool) => {
|
||||||
|
@ -1059,12 +1075,13 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletCommand::DelegateStake(staking_account_keypair, voting_account_pubkey) => {
|
WalletCommand::DelegateStake(staking_account_keypair, voting_account_pubkey, lamports) => {
|
||||||
process_delegate_stake(
|
process_delegate_stake(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
&staking_account_keypair,
|
&staking_account_keypair,
|
||||||
&voting_account_pubkey,
|
&voting_account_pubkey,
|
||||||
|
*lamports,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1460,7 +1477,15 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
.validator(is_pubkey)
|
.validator(is_pubkey)
|
||||||
.help("The voting account to which to delegate the stake."),
|
.help("The voting account to which the stake will be delegated"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake")
|
||||||
|
.index(3)
|
||||||
|
.value_name("NUM")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("The number of lamports to stake, must be less than the stake account's balance."),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -1891,10 +1916,11 @@ mod tests {
|
||||||
"delegate-stake",
|
"delegate-stake",
|
||||||
&keypair_file,
|
&keypair_file,
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
|
"42",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
||||||
WalletCommand::DelegateStake(keypair, pubkey)
|
WalletCommand::DelegateStake(keypair, pubkey, 42)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Deploy Subcommand
|
// Test Deploy Subcommand
|
||||||
|
@ -2062,7 +2088,7 @@ mod tests {
|
||||||
|
|
||||||
let bob_keypair = Keypair::new();
|
let bob_keypair = Keypair::new();
|
||||||
let node_pubkey = Pubkey::new_rand();
|
let node_pubkey = Pubkey::new_rand();
|
||||||
config.command = WalletCommand::DelegateStake(bob_keypair.into(), node_pubkey);
|
config.command = WalletCommand::DelegateStake(bob_keypair.into(), node_pubkey, 100);
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue