Cli refactor: vote and storage program functionalities (#6242)

automerge
This commit is contained in:
Tyera Eulberg 2019-10-04 15:18:19 -06:00 committed by Grimes
parent 7f53737000
commit 0c3ff6b75c
12 changed files with 611 additions and 543 deletions

View File

@ -6,6 +6,7 @@ pub mod display;
pub mod input_parsers;
pub mod input_validators;
pub mod stake;
pub mod storage;
pub mod validator_info;
pub mod vote;
pub mod wallet;

271
cli/src/storage.rs Normal file
View File

@ -0,0 +1,271 @@
use crate::{
input_parsers::*,
input_validators::*,
wallet::{
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, ProcessResult,
WalletCommand, WalletConfig, WalletError,
},
};
use clap::{App, Arg, ArgMatches, SubCommand};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
account_utils::State, message::Message, pubkey::Pubkey, signature::KeypairUtil,
system_instruction::SystemError, transaction::Transaction,
};
use solana_storage_api::storage_instruction::{self, StorageAccountType};
pub trait StorageSubCommands {
fn storage_subcommands(self) -> Self;
}
impl StorageSubCommands for App<'_, '_> {
fn storage_subcommands(self) -> Self {
self.subcommand(
SubCommand::with_name("create-replicator-storage-account")
.about("Create a replicator storage account")
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
),
)
.subcommand(
SubCommand::with_name("create-validator-storage-account")
.about("Create a validator storage account")
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
),
)
.subcommand(
SubCommand::with_name("claim-storage-reward")
.about("Redeem storage reward credits")
.arg(
Arg::with_name("node_account_pubkey")
.index(1)
.value_name("NODE PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("The node account to credit the rewards to"),
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage account address to redeem credits for"),
),
)
.subcommand(
SubCommand::with_name("show-storage-account")
.about("Show the contents of a storage account")
.arg(
Arg::with_name("storage_account_pubkey")
.index(1)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage account pubkey"),
),
)
}
}
pub fn parse_storage_create_replicator_account(
matches: &ArgMatches<'_>,
) -> Result<WalletCommand, WalletError> {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::CreateStorageAccount {
account_owner,
storage_account_pubkey,
account_type: StorageAccountType::Replicator,
})
}
pub fn parse_storage_create_validator_account(
matches: &ArgMatches<'_>,
) -> Result<WalletCommand, WalletError> {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::CreateStorageAccount {
account_owner,
storage_account_pubkey,
account_type: StorageAccountType::Validator,
})
}
pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::ClaimStorageReward {
node_account_pubkey,
storage_account_pubkey,
})
}
pub fn parse_storage_get_account_command(
matches: &ArgMatches<'_>,
) -> Result<WalletCommand, WalletError> {
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::ShowStorageAccount(storage_account_pubkey))
}
pub fn process_create_storage_account(
rpc_client: &RpcClient,
config: &WalletConfig,
account_owner: &Pubkey,
storage_account_pubkey: &Pubkey,
account_type: StorageAccountType,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "wallet keypair".to_string()),
(
&storage_account_pubkey,
"storage_account_pubkey".to_string(),
),
)?;
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = storage_instruction::create_storage_account(
&config.keypair.pubkey(),
&account_owner,
storage_account_pubkey,
1,
account_type,
);
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
log_instruction_custom_error::<SystemError>(result)
}
pub fn process_claim_storage_reward(
rpc_client: &RpcClient,
config: &WalletConfig,
node_account_pubkey: &Pubkey,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let instruction =
storage_instruction::claim_reward(node_account_pubkey, storage_account_pubkey);
let signers = [&config.keypair];
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
let mut tx = Transaction::new(&signers, message, recent_blockhash);
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &signers)?;
Ok(signature_str.to_string())
}
pub fn process_show_storage_account(
rpc_client: &RpcClient,
_config: &WalletConfig,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
let account = rpc_client.get_account(storage_account_pubkey)?;
if account.owner != solana_storage_api::id() {
return Err(WalletError::RpcRequestError(
format!("{:?} is not a storage account", storage_account_pubkey).to_string(),
)
.into());
}
use solana_storage_api::storage_contract::StorageContract;
let storage_contract: StorageContract = account.state().map_err(|err| {
WalletError::RpcRequestError(
format!("Unable to deserialize storage account: {:?}", err).to_string(),
)
})?;
println!("{:#?}", storage_contract);
println!("account lamports: {}", account.lamports);
Ok("".to_string())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::wallet::{app, parse_command};
#[test]
fn test_parse_command() {
let test_commands = app("test", "desc", "version");
let pubkey = Pubkey::new_rand();
let pubkey_string = pubkey.to_string();
let storage_account_pubkey = Pubkey::new_rand();
let storage_account_string = storage_account_pubkey.to_string();
let test_create_replicator_storage_account = test_commands.clone().get_matches_from(vec![
"test",
"create-replicator-storage-account",
&pubkey_string,
&storage_account_string,
]);
assert_eq!(
parse_command(&pubkey, &test_create_replicator_storage_account).unwrap(),
WalletCommand::CreateStorageAccount {
account_owner: pubkey,
storage_account_pubkey,
account_type: StorageAccountType::Replicator,
}
);
let test_create_validator_storage_account = test_commands.clone().get_matches_from(vec![
"test",
"create-validator-storage-account",
&pubkey_string,
&storage_account_string,
]);
assert_eq!(
parse_command(&pubkey, &test_create_validator_storage_account).unwrap(),
WalletCommand::CreateStorageAccount {
account_owner: pubkey,
storage_account_pubkey,
account_type: StorageAccountType::Validator,
}
);
let test_claim_storage_reward = test_commands.clone().get_matches_from(vec![
"test",
"claim-storage-reward",
&pubkey_string,
&storage_account_string,
]);
assert_eq!(
parse_command(&pubkey, &test_claim_storage_reward).unwrap(),
WalletCommand::ClaimStorageReward {
node_account_pubkey: pubkey,
storage_account_pubkey,
}
);
}
// TODO: Add process tests
}

View File

@ -1,11 +1,12 @@
use crate::{
input_parsers::*,
input_validators::*,
wallet::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
log_instruction_custom_error, ProcessResult, WalletCommand, WalletConfig, WalletError,
},
};
use clap::{value_t_or_exit, ArgMatches};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
pubkey::Pubkey, signature::KeypairUtil, system_instruction::SystemError,
@ -16,6 +17,148 @@ use solana_vote_api::{
vote_state::{VoteAuthorize, VoteInit, VoteState},
};
pub trait VoteSubCommands {
fn vote_subcommands(self) -> Self;
}
impl VoteSubCommands for App<'_, '_> {
fn vote_subcommands(self) -> Self {
self.subcommand(
SubCommand::with_name("create-vote-account")
.about("Create a vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account address to fund"),
)
.arg(
Arg::with_name("node_pubkey")
.index(2)
.value_name("VALIDATOR PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Validator that will vote with this account"),
)
.arg(
Arg::with_name("commission")
.long("commission")
.value_name("NUM")
.takes_value(true)
.help("The commission taken on reward redemption (0-255), default: 0"),
)
.arg(
Arg::with_name("authorized_voter")
.long("authorized-voter")
.value_name("PUBKEY")
.takes_value(true)
.validator(is_pubkey_or_keypair)
.help("Public key of the authorized voter (defaults to vote account)"),
)
.arg(
Arg::with_name("authorized_withdrawer")
.long("authorized-withdrawer")
.value_name("PUBKEY")
.takes_value(true)
.validator(is_pubkey_or_keypair)
.help("Public key of the authorized withdrawer (defaults to wallet)"),
),
)
.subcommand(
SubCommand::with_name("vote-authorize-voter")
.about("Authorize a new vote signing keypair for the given vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account in which to set the authorized voter"),
)
.arg(
Arg::with_name("new_authorized_pubkey")
.index(2)
.value_name("NEW VOTER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("New vote signer to authorize"),
),
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer")
.about("Authorize a new withdraw signing keypair for the given vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account in which to set the authorized withdrawer"),
)
.arg(
Arg::with_name("new_authorized_pubkey")
.index(2)
.value_name("NEW WITHDRAWER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("New withdrawer to authorize"),
),
)
.subcommand(
SubCommand::with_name("show-vote-account")
.about("Show the contents of a vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account pubkey"),
)
.arg(
Arg::with_name("lamports")
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
),
)
.subcommand(
SubCommand::with_name("uptime")
.about("Show the uptime of a validator, based on epoch voting history")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account pubkey"),
)
.arg(
Arg::with_name("span")
.long("span")
.value_name("NUM OF EPOCHS")
.takes_value(true)
.help("Number of recent epochs to examine"),
)
.arg(
Arg::with_name("aggregate")
.long("aggregate")
.help("Aggregate uptime data across span"),
),
)
}
}
pub fn parse_vote_create_account(
pubkey: &Pubkey,
matches: &ArgMatches<'_>,
@ -62,6 +205,21 @@ pub fn parse_vote_get_account_command(
})
}
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
let aggregate = matches.is_present("aggregate");
let span = if matches.is_present("span") {
Some(value_t_or_exit!(matches, "span", u64))
} else {
None
};
Ok(WalletCommand::Uptime {
pubkey: vote_account_pubkey,
aggregate,
span,
})
}
pub fn process_create_vote_account(
rpc_client: &RpcClient,
config: &WalletConfig,
@ -121,21 +279,6 @@ pub fn process_vote_authorize(
log_instruction_custom_error::<VoteError>(result)
}
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
let aggregate = matches.is_present("aggregate");
let span = if matches.is_present("span") {
Some(value_t_or_exit!(matches, "span", u64))
} else {
None
};
Ok(WalletCommand::Uptime {
pubkey: vote_account_pubkey,
aggregate,
span,
})
}
pub fn process_show_vote_account(
rpc_client: &RpcClient,
_config: &WalletConfig,

View File

@ -1,5 +1,5 @@
use crate::{
display::println_name_value, input_parsers::*, input_validators::*, stake::*,
display::println_name_value, input_parsers::*, input_validators::*, stake::*, storage::*,
validator_info::*, vote::*,
};
use chrono::prelude::*;
@ -15,7 +15,6 @@ use solana_drone::drone::request_airdrop_transaction;
#[cfg(test)]
use solana_drone::drone_mock::request_airdrop_transaction;
use solana_sdk::{
account_utils::State,
bpf_loader, clock,
fee_calculator::FeeCalculator,
hash::Hash,
@ -31,7 +30,7 @@ use solana_sdk::{
transaction::{Transaction, TransactionError},
};
use solana_stake_api::stake_state::{Authorized, Lockup, StakeAuthorize};
use solana_storage_api::storage_instruction;
use solana_storage_api::storage_instruction::StorageAccountType;
use solana_vote_api::vote_state::{VoteAuthorize, VoteInit};
use std::{
collections::VecDeque,
@ -51,21 +50,46 @@ static CROSS_MARK: Emoji = Emoji("❌ ", "");
#[derive(Debug, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum WalletCommand {
Address,
// Cluster Info Commands
Fees,
Airdrop {
drone_host: Option<IpAddr>,
drone_port: u16,
lamports: u64,
use_lamports_unit: bool,
GetGenesisBlockhash,
GetSlot,
GetEpochInfo,
GetTransactionCount,
GetVersion,
Ping {
interval: Duration,
count: Option<u64>,
timeout: Duration,
},
Balance {
// Program Deployment
Deploy(String),
// Stake Commands
CreateStakeAccount(Pubkey, Authorized, Lockup, u64),
DelegateStake(Pubkey, Pubkey, bool),
DeactivateStake(Pubkey, Pubkey),
RedeemVoteCredits(Pubkey, Pubkey),
ShowStakeAccount {
pubkey: Pubkey,
use_lamports_unit: bool,
},
Cancel(Pubkey),
Confirm(Signature),
VoteAuthorize(Pubkey, Pubkey, VoteAuthorize),
StakeAuthorize(Pubkey, Pubkey, StakeAuthorize),
WithdrawStake(Pubkey, Pubkey, u64),
// Storage Commands
CreateStorageAccount {
account_owner: Pubkey,
storage_account_pubkey: Pubkey,
account_type: StorageAccountType,
},
ClaimStorageReward {
node_account_pubkey: Pubkey,
storage_account_pubkey: Pubkey,
},
ShowStorageAccount(Pubkey),
// Validator Info Commands
GetValidatorInfo(Option<Pubkey>),
SetValidatorInfo(ValidatorInfo, Option<Pubkey>),
// Vote Commands
CreateVoteAccount(Pubkey, VoteInit),
ShowAccount {
pubkey: Pubkey,
@ -81,26 +105,21 @@ pub enum WalletCommand {
aggregate: bool,
span: Option<u64>,
},
CreateStakeAccount(Pubkey, Authorized, Lockup, u64),
StakeAuthorize(Pubkey, Pubkey, StakeAuthorize),
DelegateStake(Pubkey, Pubkey, bool),
WithdrawStake(Pubkey, Pubkey, u64),
DeactivateStake(Pubkey, Pubkey),
RedeemVoteCredits(Pubkey, Pubkey),
ShowStakeAccount {
VoteAuthorize(Pubkey, Pubkey, VoteAuthorize),
// Wallet Commands
Address,
Airdrop {
drone_host: Option<IpAddr>,
drone_port: u16,
lamports: u64,
use_lamports_unit: bool,
},
Balance {
pubkey: Pubkey,
use_lamports_unit: bool,
},
CreateReplicatorStorageAccount(Pubkey, Pubkey),
CreateValidatorStorageAccount(Pubkey, Pubkey),
ClaimStorageReward(Pubkey, Pubkey),
ShowStorageAccount(Pubkey),
Deploy(String),
GetGenesisBlockhash,
GetSlot,
GetEpochInfo,
GetTransactionCount,
GetVersion,
Cancel(Pubkey),
Confirm(Signature),
Pay {
lamports: u64,
to: Pubkey,
@ -109,15 +128,8 @@ pub enum WalletCommand {
witnesses: Option<Vec<Pubkey>>,
cancelable: Option<Pubkey>,
},
Ping {
interval: Duration,
count: Option<u64>,
timeout: Duration,
},
TimeElapsed(Pubkey, Pubkey, DateTime<Utc>), // TimeElapsed(to, process_id, timestamp)
Witness(Pubkey, Pubkey), // Witness(to, process_id)
GetValidatorInfo(Option<Pubkey>),
SetValidatorInfo(ValidatorInfo, Option<Pubkey>),
}
#[derive(Debug, Clone)]
@ -265,33 +277,13 @@ pub fn parse_command(
("redeem-vote-credits", Some(matches)) => parse_redeem_vote_credits(matches),
("show-stake-account", Some(matches)) => parse_show_stake_account(matches),
("create-replicator-storage-account", Some(matches)) => {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::CreateReplicatorStorageAccount(
account_owner,
storage_account_pubkey,
))
parse_storage_create_replicator_account(matches)
}
("create-validator-storage-account", Some(matches)) => {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::CreateValidatorStorageAccount(
account_owner,
storage_account_pubkey,
))
}
("claim-storage-reward", Some(matches)) => {
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::ClaimStorageReward(
node_account_pubkey,
storage_account_pubkey,
))
}
("show-storage-account", Some(matches)) => {
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
Ok(WalletCommand::ShowStorageAccount(storage_account_pubkey))
parse_storage_create_validator_account(matches)
}
("claim-storage-reward", Some(matches)) => parse_storage_claim_reward(matches),
("show-storage-account", Some(matches)) => parse_storage_get_account_command(matches),
("deploy", Some(deploy_matches)) => Ok(WalletCommand::Deploy(
deploy_matches
.value_of("program_location")
@ -543,102 +535,6 @@ fn process_show_account(
Ok("".to_string())
}
fn process_create_replicator_storage_account(
rpc_client: &RpcClient,
config: &WalletConfig,
account_owner: &Pubkey,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "wallet keypair".to_string()),
(
&storage_account_pubkey,
"storage_account_pubkey".to_string(),
),
)?;
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = storage_instruction::create_replicator_storage_account(
&config.keypair.pubkey(),
&account_owner,
storage_account_pubkey,
1,
);
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
log_instruction_custom_error::<SystemError>(result)
}
fn process_create_validator_storage_account(
rpc_client: &RpcClient,
config: &WalletConfig,
account_owner: &Pubkey,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "wallet keypair".to_string()),
(
&storage_account_pubkey,
"storage_account_pubkey".to_string(),
),
)?;
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = storage_instruction::create_validator_storage_account(
&config.keypair.pubkey(),
account_owner,
storage_account_pubkey,
1,
);
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
log_instruction_custom_error::<SystemError>(result)
}
fn process_claim_storage_reward(
rpc_client: &RpcClient,
config: &WalletConfig,
node_account_pubkey: &Pubkey,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let instruction =
storage_instruction::claim_reward(node_account_pubkey, storage_account_pubkey);
let signers = [&config.keypair];
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
let mut tx = Transaction::new(&signers, message, recent_blockhash);
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &signers)?;
Ok(signature_str.to_string())
}
fn process_show_storage_account(
rpc_client: &RpcClient,
_config: &WalletConfig,
storage_account_pubkey: &Pubkey,
) -> ProcessResult {
let account = rpc_client.get_account(storage_account_pubkey)?;
if account.owner != solana_storage_api::id() {
return Err(WalletError::RpcRequestError(
format!("{:?} is not a storage account", storage_account_pubkey).to_string(),
)
.into());
}
use solana_storage_api::storage_contract::StorageContract;
let storage_contract: StorageContract = account.state().map_err(|err| {
WalletError::RpcRequestError(
format!("Unable to deserialize storage account: {:?}", err).to_string(),
)
})?;
println!("{:#?}", storage_contract);
println!("account lamports: {}", account.lamports);
Ok("".to_string())
}
fn process_deploy(
rpc_client: &RpcClient,
config: &WalletConfig,
@ -1211,33 +1107,27 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
*use_lamports_unit,
),
WalletCommand::CreateReplicatorStorageAccount(
storage_account_owner,
WalletCommand::CreateStorageAccount {
account_owner,
storage_account_pubkey,
) => process_create_replicator_storage_account(
account_type,
} => process_create_storage_account(
&rpc_client,
config,
&storage_account_owner,
&account_owner,
&storage_account_pubkey,
*account_type,
),
WalletCommand::CreateValidatorStorageAccount(account_owner, storage_account_pubkey) => {
process_create_validator_storage_account(
&rpc_client,
config,
&account_owner,
&storage_account_pubkey,
)
}
WalletCommand::ClaimStorageReward(node_account_pubkey, storage_account_pubkey) => {
process_claim_storage_reward(
&rpc_client,
config,
node_account_pubkey,
&storage_account_pubkey,
)
}
WalletCommand::ClaimStorageReward {
node_account_pubkey,
storage_account_pubkey,
} => process_claim_storage_reward(
&rpc_client,
config,
node_account_pubkey,
&storage_account_pubkey,
),
WalletCommand::ShowStorageAccount(storage_account_pubkey) => {
process_show_storage_account(&rpc_client, config, &storage_account_pubkey)
@ -1482,95 +1372,6 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.help("The transaction signature to confirm"),
),
)
.subcommand(
SubCommand::with_name("vote-authorize-voter")
.about("Authorize a new vote signing keypair for the given vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account in which to set the authorized voter"),
)
.arg(
Arg::with_name("new_authorized_pubkey")
.index(2)
.value_name("NEW VOTER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("New vote signer to authorize"),
),
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer")
.about("Authorize a new withdraw signing keypair for the given vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account in which to set the authorized withdrawer"),
)
.arg(
Arg::with_name("new_authorized_pubkey")
.index(2)
.value_name("NEW WITHDRAWER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("New withdrawer to authorize"),
),
)
.subcommand(
SubCommand::with_name("create-vote-account")
.about("Create a vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account address to fund"),
)
.arg(
Arg::with_name("node_pubkey")
.index(2)
.value_name("VALIDATOR PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Validator that will vote with this account"),
)
.arg(
Arg::with_name("commission")
.long("commission")
.value_name("NUM")
.takes_value(true)
.help("The commission taken on reward redemption (0-255), default: 0"),
)
.arg(
Arg::with_name("authorized_voter")
.long("authorized-voter")
.value_name("PUBKEY")
.takes_value(true)
.validator(is_pubkey_or_keypair)
.help("Public key of the authorized voter (defaults to vote account)"),
)
.arg(
Arg::with_name("authorized_withdrawer")
.long("authorized-withdrawer")
.value_name("PUBKEY")
.takes_value(true)
.validator(is_pubkey_or_keypair)
.help("Public key of the authorized withdrawer (defaults to wallet)"),
),
)
.subcommand(
SubCommand::with_name("show-account")
.about("Show the contents of an account")
@ -1598,154 +1399,9 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.help("Display balance in lamports instead of SOL"),
),
)
.subcommand(
SubCommand::with_name("show-vote-account")
.about("Show the contents of a vote account")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account pubkey"),
)
.arg(
Arg::with_name("lamports")
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
),
)
.subcommand(
SubCommand::with_name("uptime")
.about("Show the uptime of a validator, based on epoch voting history")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account pubkey"),
)
.arg(
Arg::with_name("span")
.long("span")
.value_name("NUM OF EPOCHS")
.takes_value(true)
.help("Number of recent epochs to examine")
)
.arg(
Arg::with_name("aggregate")
.long("aggregate")
.help("Aggregate uptime data across span")
),
)
.vote_subcommands()
.stake_subcommands()
.subcommand(
SubCommand::with_name("create-storage-mining-pool-account")
.about("Create mining pool account")
.arg(
Arg::with_name("storage_account_pubkey")
.index(1)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage mining pool account address to fund"),
)
.arg(
Arg::with_name("amount")
.index(2)
.value_name("AMOUNT")
.takes_value(true)
.required(true)
.help("The amount to assign to the storage mining pool account (default unit SOL)"),
)
.arg(
Arg::with_name("unit")
.index(3)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request"),
),
)
.subcommand(
SubCommand::with_name("create-replicator-storage-account")
.about("Create a replicator storage account")
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
)
)
.subcommand(
SubCommand::with_name("create-validator-storage-account")
.about("Create a validator storage account")
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
)
)
.subcommand(
SubCommand::with_name("claim-storage-reward")
.about("Redeem storage reward credits")
.arg(
Arg::with_name("node_account_pubkey")
.index(1)
.value_name("NODE PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("The node account to credit the rewards to"),
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage account address to redeem credits for"),
))
.subcommand(
SubCommand::with_name("show-storage-account")
.about("Show the contents of a storage account")
.arg(
Arg::with_name("storage_account_pubkey")
.index(1)
.value_name("STORAGE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage account pubkey"),
)
)
.storage_subcommands()
.subcommand(
SubCommand::with_name("deploy")
.about("Deploy a program")

View File

@ -35,7 +35,7 @@ use solana_sdk::timing::timestamp;
use solana_sdk::transaction::Transaction;
use solana_sdk::transport::TransportError;
use solana_storage_api::storage_contract::StorageContract;
use solana_storage_api::storage_instruction;
use solana_storage_api::storage_instruction::{self, StorageAccountType};
use std::fs::File;
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
use std::mem::size_of;
@ -600,11 +600,12 @@ impl Replicator {
}
};
let ix = storage_instruction::create_replicator_storage_account(
let ix = storage_instruction::create_storage_account(
&keypair.pubkey(),
&keypair.pubkey(),
&storage_keypair.pubkey(),
1,
StorageAccountType::Replicator,
);
let tx = Transaction::new_signed_instructions(&[keypair], ix, blockhash);
let signature = client.async_send_transaction(tx)?;

View File

@ -641,6 +641,7 @@ mod tests {
use solana_sdk::hash::{Hash, Hasher};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_storage_api::storage_instruction::StorageAccountType;
use std::cmp::{max, min};
use std::fs::remove_dir_all;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@ -822,11 +823,12 @@ mod tests {
// create accounts
let bank = Arc::new(Bank::new_from_parent(&bank, &keypair.pubkey(), 1));
let account_ix = storage_instruction::create_replicator_storage_account(
let account_ix = storage_instruction::create_storage_account(
&mint_keypair.pubkey(),
&Pubkey::new_rand(),
&replicator_keypair.pubkey(),
1,
StorageAccountType::Replicator,
);
let account_tx = Transaction::new_signed_instructions(
&[&mint_keypair],

View File

@ -25,7 +25,10 @@ use solana_stake_api::{
config as stake_config, stake_instruction,
stake_state::{Authorized as StakeAuthorized, StakeState},
};
use solana_storage_api::{storage_contract, storage_instruction};
use solana_storage_api::{
storage_contract,
storage_instruction::{self, StorageAccountType},
};
use solana_vote_api::{
vote_instruction,
vote_state::{VoteInit, VoteState},
@ -532,22 +535,19 @@ impl LocalCluster {
from_keypair: &Arc<Keypair>,
replicator: bool,
) -> Result<()> {
let storage_account_type = if replicator {
StorageAccountType::Replicator
} else {
StorageAccountType::Validator
};
let message = Message::new_with_payer(
if replicator {
storage_instruction::create_replicator_storage_account(
&from_keypair.pubkey(),
&from_keypair.pubkey(),
&storage_keypair.pubkey(),
1,
)
} else {
storage_instruction::create_validator_storage_account(
&from_keypair.pubkey(),
&from_keypair.pubkey(),
&storage_keypair.pubkey(),
1,
)
},
storage_instruction::create_storage_account(
&from_keypair.pubkey(),
&from_keypair.pubkey(),
&storage_keypair.pubkey(),
1,
storage_account_type,
),
Some(&from_keypair.pubkey()),
);
let signer_keys = vec![from_keypair.as_ref()];

View File

@ -1,3 +1,4 @@
use crate::storage_instruction::StorageAccountType;
use log::*;
use num_derive::FromPrimitive;
use serde_derive::{Deserialize, Serialize};
@ -130,30 +131,27 @@ impl<'a> StorageAccount<'a> {
Self { id, account }
}
pub fn initialize_replicator_storage(&mut self, owner: Pubkey) -> Result<(), InstructionError> {
pub fn initialize_storage(
&mut self,
owner: Pubkey,
account_type: StorageAccountType,
) -> Result<(), InstructionError> {
let storage_contract = &mut self.account.state()?;
if let StorageContract::Uninitialized = storage_contract {
*storage_contract = StorageContract::ReplicatorStorage {
owner,
proofs: BTreeMap::new(),
validations: BTreeMap::new(),
credits: Credits::default(),
};
self.account.set_state(storage_contract)
} else {
Err(InstructionError::AccountAlreadyInitialized)
}
}
pub fn initialize_validator_storage(&mut self, owner: Pubkey) -> Result<(), InstructionError> {
let storage_contract = &mut self.account.state()?;
if let StorageContract::Uninitialized = storage_contract {
*storage_contract = StorageContract::ValidatorStorage {
owner,
segment: 0,
hash: Hash::default(),
lockout_validations: BTreeMap::new(),
credits: Credits::default(),
*storage_contract = match account_type {
StorageAccountType::Replicator => StorageContract::ReplicatorStorage {
owner,
proofs: BTreeMap::new(),
validations: BTreeMap::new(),
credits: Credits::default(),
},
StorageAccountType::Validator => StorageContract::ValidatorStorage {
owner,
segment: 0,
hash: Hash::default(),
lockout_validations: BTreeMap::new(),
credits: Credits::default(),
},
};
self.account.set_state(storage_contract)
} else {

View File

@ -8,17 +8,21 @@ use solana_sdk::signature::Signature;
use solana_sdk::system_instruction;
use solana_sdk::sysvar::{clock, rewards};
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
pub enum StorageAccountType {
Replicator,
Validator,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum StorageInstruction {
/// Initialize the account as a validator or replicator
///
/// Expects 1 Account:
/// 0 - Account to be initialized
InitializeValidatorStorage {
owner: Pubkey,
},
InitializeReplicatorStorage {
InitializeStorage {
owner: Pubkey,
account_type: StorageAccountType,
},
SubmitMiningProof {
@ -81,11 +85,12 @@ pub fn proof_mask_limit() -> u64 {
bytes - ratio
}
pub fn create_validator_storage_account(
pub fn create_storage_account(
from_pubkey: &Pubkey,
storage_owner: &Pubkey,
storage_pubkey: &Pubkey,
lamports: u64,
account_type: StorageAccountType,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
@ -97,32 +102,9 @@ pub fn create_validator_storage_account(
),
Instruction::new(
id(),
&StorageInstruction::InitializeValidatorStorage {
owner: *storage_owner,
},
vec![AccountMeta::new(*storage_pubkey, false)],
),
]
}
pub fn create_replicator_storage_account(
from_pubkey: &Pubkey,
storage_owner: &Pubkey,
storage_pubkey: &Pubkey,
lamports: u64,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
from_pubkey,
storage_pubkey,
lamports,
STORAGE_ACCOUNT_SPACE,
&id(),
),
Instruction::new(
id(),
&StorageInstruction::InitializeReplicatorStorage {
&StorageInstruction::InitializeStorage {
owner: *storage_owner,
account_type,
},
vec![AccountMeta::new(*storage_pubkey, false)],
),

View File

@ -20,17 +20,14 @@ pub fn process_instruction(
let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me[0].account);
match bincode::deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
StorageInstruction::InitializeReplicatorStorage { owner } => {
StorageInstruction::InitializeStorage {
owner,
account_type,
} => {
if !rest.is_empty() {
return Err(InstructionError::InvalidArgument);
}
storage_account.initialize_replicator_storage(owner)
}
StorageInstruction::InitializeValidatorStorage { owner } => {
if !rest.is_empty() {
return Err(InstructionError::InvalidArgument);
}
storage_account.initialize_validator_storage(owner)
storage_account.initialize_storage(owner, account_type)
}
StorageInstruction::SubmitMiningProof {
sha_state,

View File

@ -1,26 +1,32 @@
use assert_matches::assert_matches;
use bincode::deserialize;
use log::*;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::genesis_utils::{create_genesis_block, GenesisBlockInfo};
use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount};
use solana_sdk::account_utils::State;
use solana_sdk::client::SyncClient;
use solana_sdk::clock::{get_segment_from_slot, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT};
use solana_sdk::hash::{hash, Hash};
use solana_sdk::instruction::{Instruction, InstructionError};
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::system_instruction;
use solana_sdk::sysvar::clock::{self, Clock};
use solana_sdk::sysvar::rewards::{self, Rewards};
use solana_storage_api::id;
use solana_storage_api::storage_contract::StorageAccount;
use solana_storage_api::storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE};
use solana_storage_api::storage_instruction;
use solana_storage_api::storage_processor::process_instruction;
use solana_runtime::{
bank::Bank,
bank_client::BankClient,
genesis_utils::{create_genesis_block, GenesisBlockInfo},
};
use solana_sdk::{
account::{create_keyed_accounts, Account, KeyedAccount},
account_utils::State,
client::SyncClient,
clock::{get_segment_from_slot, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
hash::{hash, Hash},
instruction::{Instruction, InstructionError},
message::Message,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature},
system_instruction,
sysvar::clock::{self, Clock},
sysvar::rewards::{self, Rewards},
};
use solana_storage_api::{
id,
storage_contract::StorageAccount,
storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE},
storage_instruction::{self, StorageAccountType},
storage_processor::process_instruction,
};
use std::collections::HashMap;
use std::sync::Arc;
@ -61,11 +67,12 @@ fn test_account_owner() {
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let message = Message::new(storage_instruction::create_validator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&account_owner,
&validator_storage_pubkey,
1,
StorageAccountType::Validator,
));
bank_client
.send_message(&[&mint_keypair], message)
@ -80,11 +87,12 @@ fn test_account_owner() {
assert!(false, "wrong account type found")
}
let message = Message::new(storage_instruction::create_replicator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&account_owner,
&replicator_storage_pubkey,
1,
StorageAccountType::Replicator,
));
bank_client
.send_message(&[&mint_keypair], message)
@ -111,7 +119,7 @@ fn test_proof_bounds() {
{
let mut storage_account = StorageAccount::new(pubkey, &mut account);
storage_account
.initialize_replicator_storage(account_owner)
.initialize_storage(account_owner, StorageAccountType::Replicator)
.unwrap();
}
@ -224,7 +232,7 @@ fn test_submit_mining_ok() {
{
let mut storage_account = StorageAccount::new(pubkey, &mut account);
storage_account
.initialize_replicator_storage(account_owner)
.initialize_storage(account_owner, StorageAccountType::Replicator)
.unwrap();
}
@ -473,11 +481,12 @@ fn init_storage_accounts(
&mut validator_accounts_to_create
.into_iter()
.flat_map(|account| {
storage_instruction::create_validator_storage_account(
storage_instruction::create_storage_account(
&mint.pubkey(),
owner,
account,
lamports,
StorageAccountType::Validator,
)
})
.collect(),
@ -485,11 +494,12 @@ fn init_storage_accounts(
replicator_accounts_to_create
.into_iter()
.for_each(|account| {
ixs.append(&mut storage_instruction::create_replicator_storage_account(
ixs.append(&mut storage_instruction::create_storage_account(
&mint.pubkey(),
owner,
account,
lamports,
StorageAccountType::Replicator,
))
});
let message = Message::new(ixs);
@ -590,19 +600,21 @@ fn test_bank_storage() {
.transfer(10, &mint_keypair, &replicator_pubkey)
.unwrap();
let message = Message::new(storage_instruction::create_replicator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&replicator_pubkey,
1,
StorageAccountType::Replicator,
));
bank_client.send_message(&[&mint_keypair], message).unwrap();
let message = Message::new(storage_instruction::create_validator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&validator_pubkey,
1,
StorageAccountType::Validator,
));
bank_client.send_message(&[&mint_keypair], message).unwrap();

View File

@ -86,8 +86,11 @@ pub(crate) mod tests {
use solana_sdk::genesis_block::create_genesis_block;
use solana_sdk::message::Message;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_storage_api::storage_contract::{StorageAccount, STORAGE_ACCOUNT_SPACE};
use solana_storage_api::{storage_instruction, storage_processor};
use solana_storage_api::{
storage_contract::{StorageAccount, STORAGE_ACCOUNT_SPACE},
storage_instruction::{self, StorageAccountType},
storage_processor,
};
use std::sync::Arc;
#[test]
@ -110,22 +113,24 @@ pub(crate) mod tests {
bank_client
.transfer(10, &mint_keypair, &replicator_pubkey)
.unwrap();
let message = Message::new(storage_instruction::create_replicator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&replicator_pubkey,
1,
StorageAccountType::Replicator,
));
bank_client.send_message(&[&mint_keypair], message).unwrap();
bank_client
.transfer(10, &mint_keypair, &validator_pubkey)
.unwrap();
let message = Message::new(storage_instruction::create_validator_storage_account(
let message = Message::new(storage_instruction::create_storage_account(
&mint_pubkey,
&Pubkey::default(),
&validator_pubkey,
1,
StorageAccountType::Validator,
));
bank_client.send_message(&[&mint_keypair], message).unwrap();
@ -192,7 +197,7 @@ pub(crate) mod tests {
Account::new(1, STORAGE_ACCOUNT_SPACE as usize, &solana_storage_api::id());
let mut validator = StorageAccount::new(validator_pubkey, &mut validator_account);
validator
.initialize_validator_storage(validator_pubkey)
.initialize_storage(validator_pubkey, StorageAccountType::Validator)
.unwrap();
let storage_contract = &mut validator_account.state().unwrap();
if let StorageContract::ValidatorStorage {
@ -208,7 +213,7 @@ pub(crate) mod tests {
Account::new(1, STORAGE_ACCOUNT_SPACE as usize, &solana_storage_api::id());
let mut replicator = StorageAccount::new(replicator_pubkey, &mut replicator_account);
replicator
.initialize_replicator_storage(replicator_pubkey)
.initialize_storage(replicator_pubkey, StorageAccountType::Replicator)
.unwrap();
let storage_contract = &mut replicator_account.state().unwrap();
if let StorageContract::ReplicatorStorage {