Adapt solana deploy
This commit is contained in:
123
cli/src/cli.rs
123
cli/src/cli.rs
@ -2,7 +2,7 @@ use crate::{
|
|||||||
checks::*,
|
checks::*,
|
||||||
cli_output::{CliAccount, CliSignOnlyData, CliSignature, OutputFormat},
|
cli_output::{CliAccount, CliSignOnlyData, CliSignature, OutputFormat},
|
||||||
cluster_query::*,
|
cluster_query::*,
|
||||||
display::println_name_value,
|
display::{new_spinner_progress_bar, println_name_value, println_transaction},
|
||||||
nonce::{self, *},
|
nonce::{self, *},
|
||||||
offline::{blockhash_query::BlockhashQuery, *},
|
offline::{blockhash_query::BlockhashQuery, *},
|
||||||
spend_utils::*,
|
spend_utils::*,
|
||||||
@ -27,7 +27,7 @@ use solana_clap_utils::{
|
|||||||
use solana_client::{
|
use solana_client::{
|
||||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||||
rpc_client::RpcClient,
|
rpc_client::RpcClient,
|
||||||
rpc_config::RpcLargestAccountsFilter,
|
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
||||||
rpc_response::{RpcAccount, RpcKeyedAccount},
|
rpc_response::{RpcAccount, RpcKeyedAccount},
|
||||||
};
|
};
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@ -37,7 +37,7 @@ use solana_faucet::faucet_mock::request_airdrop_transaction;
|
|||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
bpf_loader,
|
bpf_loader,
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot, DEFAULT_TICKS_PER_SECOND},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
fee_calculator::FeeCalculator,
|
fee_calculator::FeeCalculator,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@ -48,6 +48,7 @@ use solana_sdk::{
|
|||||||
program_utils::DecodeError,
|
program_utils::DecodeError,
|
||||||
pubkey::{Pubkey, MAX_SEED_LEN},
|
pubkey::{Pubkey, MAX_SEED_LEN},
|
||||||
signature::{Keypair, Signature, Signer, SignerError},
|
signature::{Keypair, Signature, Signer, SignerError},
|
||||||
|
signers::Signers,
|
||||||
system_instruction::{self, SystemError},
|
system_instruction::{self, SystemError},
|
||||||
system_program,
|
system_program,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
@ -1159,7 +1160,7 @@ fn process_confirm(
|
|||||||
"\nTransaction executed in slot {}:",
|
"\nTransaction executed in slot {}:",
|
||||||
confirmed_transaction.slot
|
confirmed_transaction.slot
|
||||||
);
|
);
|
||||||
crate::display::println_transaction(
|
println_transaction(
|
||||||
&confirmed_transaction
|
&confirmed_transaction
|
||||||
.transaction
|
.transaction
|
||||||
.transaction
|
.transaction
|
||||||
@ -1189,7 +1190,7 @@ fn process_confirm(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_decode_transaction(transaction: &Transaction) -> ProcessResult {
|
fn process_decode_transaction(transaction: &Transaction) -> ProcessResult {
|
||||||
crate::display::println_transaction(transaction, &None, "");
|
println_transaction(transaction, &None, "");
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1227,6 +1228,103 @@ fn process_show_account(
|
|||||||
Ok(account_string)
|
Ok(account_string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_and_confirm_transactions_with_spinner<T: Signers>(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
mut transactions: Vec<Transaction>,
|
||||||
|
signer_keys: &T,
|
||||||
|
) -> Result<(), Box<dyn error::Error>> {
|
||||||
|
let progress_bar = new_spinner_progress_bar();
|
||||||
|
let mut send_retries = 5;
|
||||||
|
loop {
|
||||||
|
let mut status_retries = 15;
|
||||||
|
|
||||||
|
// Send all transactions
|
||||||
|
let mut transactions_signatures = vec![];
|
||||||
|
let num_transactions = transactions.len();
|
||||||
|
for transaction in transactions {
|
||||||
|
if cfg!(not(test)) {
|
||||||
|
// Delay ~1 tick between write transactions in an attempt to reduce AccountInUse errors
|
||||||
|
// when all the write transactions modify the same program account (eg, deploying a
|
||||||
|
// new program)
|
||||||
|
sleep(Duration::from_millis(1000 / DEFAULT_TICKS_PER_SECOND));
|
||||||
|
}
|
||||||
|
|
||||||
|
let signature = rpc_client
|
||||||
|
.send_transaction_with_config(
|
||||||
|
&transaction,
|
||||||
|
RpcSendTransactionConfig {
|
||||||
|
skip_preflight: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
transactions_signatures.push((transaction, signature));
|
||||||
|
|
||||||
|
progress_bar.set_message(&format!(
|
||||||
|
"[{}/{}] Transactions sent",
|
||||||
|
transactions_signatures.len(),
|
||||||
|
num_transactions
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect statuses for all the transactions, drop those that are confirmed
|
||||||
|
while status_retries > 0 {
|
||||||
|
status_retries -= 1;
|
||||||
|
|
||||||
|
progress_bar.set_message(&format!(
|
||||||
|
"[{}/{}] Transactions confirmed",
|
||||||
|
num_transactions - transactions_signatures.len(),
|
||||||
|
num_transactions
|
||||||
|
));
|
||||||
|
|
||||||
|
if cfg!(not(test)) {
|
||||||
|
// Retry twice a second
|
||||||
|
sleep(Duration::from_millis(500));
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions_signatures = transactions_signatures
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_transaction, signature)| {
|
||||||
|
if let Some(signature) = signature {
|
||||||
|
if let Ok(status) = rpc_client.get_signature_status(&signature) {
|
||||||
|
if rpc_client
|
||||||
|
.get_num_blocks_since_signature_confirmation(&signature)
|
||||||
|
.unwrap_or(0)
|
||||||
|
> 1
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return match status {
|
||||||
|
None => true,
|
||||||
|
Some(result) => result.is_err(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if transactions_signatures.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if send_retries == 0 {
|
||||||
|
return Err("Transactions failed".into());
|
||||||
|
}
|
||||||
|
send_retries -= 1;
|
||||||
|
|
||||||
|
// Re-sign any failed transactions with a new blockhash and retry
|
||||||
|
let (blockhash, _fee_calculator) = rpc_client
|
||||||
|
.get_new_blockhash(&transactions_signatures[0].0.message().recent_blockhash)?;
|
||||||
|
transactions = vec![];
|
||||||
|
for (mut transaction, _) in transactions_signatures.into_iter() {
|
||||||
|
transaction.try_sign(signer_keys, blockhash)?;
|
||||||
|
transactions.push(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process_deploy(
|
fn process_deploy(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
config: &CliConfig,
|
config: &CliConfig,
|
||||||
@ -1294,15 +1392,18 @@ fn process_deploy(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
trace!("Writing program data");
|
trace!("Writing program data");
|
||||||
rpc_client
|
send_and_confirm_transactions_with_spinner(&rpc_client, write_transactions, &signers).map_err(
|
||||||
.send_and_confirm_transactions_with_spinner(write_transactions, &signers)
|
|_| CliError::DynamicProgramError("Data writes to program account failed".to_string()),
|
||||||
.map_err(|_| {
|
)?;
|
||||||
CliError::DynamicProgramError("Data writes to program account failed".to_string())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("Finalizing program account");
|
trace!("Finalizing program account");
|
||||||
rpc_client
|
rpc_client
|
||||||
.send_and_confirm_transaction_with_spinner(&finalize_tx)
|
.send_and_confirm_transaction_with_spinner_and_config(
|
||||||
|
&finalize_tx,
|
||||||
|
RpcSendTransactionConfig {
|
||||||
|
skip_preflight: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
CliError::DynamicProgramError(format!("Finalizing program account failed: {}", e))
|
CliError::DynamicProgramError(format!("Finalizing program account failed: {}", e))
|
||||||
})?;
|
})?;
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||||
cli_output::*,
|
cli_output::*,
|
||||||
display::println_name_value,
|
display::{new_spinner_progress_bar, println_name_value},
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
};
|
};
|
||||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
use console::{style, Emoji};
|
use console::{style, Emoji};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
commitment::{commitment_arg, COMMITMENT_ARG},
|
commitment::{commitment_arg, COMMITMENT_ARG},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
@ -467,15 +466,6 @@ pub fn parse_transaction_history(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new process bar for processing that will take an unknown amount of time
|
|
||||||
fn new_spinner_progress_bar() -> ProgressBar {
|
|
||||||
let progress_bar = ProgressBar::new(42);
|
|
||||||
progress_bar
|
|
||||||
.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {wide_msg}"));
|
|
||||||
progress_bar.enable_steady_tick(100);
|
|
||||||
progress_bar
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_catchup(
|
pub fn process_catchup(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
node_pubkey: &Pubkey,
|
node_pubkey: &Pubkey,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::cli::SettingType;
|
use crate::cli::SettingType;
|
||||||
use console::style;
|
use console::style;
|
||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
@ -200,3 +201,12 @@ pub fn println_transaction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new process bar for processing that will take an unknown amount of time
|
||||||
|
pub fn new_spinner_progress_bar() -> ProgressBar {
|
||||||
|
let progress_bar = ProgressBar::new(42);
|
||||||
|
progress_bar
|
||||||
|
.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {wide_msg}"));
|
||||||
|
progress_bar.enable_steady_tick(100);
|
||||||
|
progress_bar
|
||||||
|
}
|
||||||
|
@ -32,7 +32,6 @@ use solana_transaction_status::{
|
|||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -416,96 +415,6 @@ impl RpcClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_and_confirm_transactions_with_spinner<T: Signers>(
|
|
||||||
&self,
|
|
||||||
mut transactions: Vec<Transaction>,
|
|
||||||
signer_keys: &T,
|
|
||||||
) -> Result<(), Box<dyn error::Error>> {
|
|
||||||
let progress_bar = new_spinner_progress_bar();
|
|
||||||
let mut send_retries = 5;
|
|
||||||
loop {
|
|
||||||
let mut status_retries = 15;
|
|
||||||
|
|
||||||
// Send all transactions
|
|
||||||
let mut transactions_signatures = vec![];
|
|
||||||
let num_transactions = transactions.len();
|
|
||||||
for transaction in transactions {
|
|
||||||
if cfg!(not(test)) {
|
|
||||||
// Delay ~1 tick between write transactions in an attempt to reduce AccountInUse errors
|
|
||||||
// when all the write transactions modify the same program account (eg, deploying a
|
|
||||||
// new program)
|
|
||||||
sleep(Duration::from_millis(1000 / DEFAULT_TICKS_PER_SECOND));
|
|
||||||
}
|
|
||||||
|
|
||||||
let signature = self.send_transaction(&transaction).ok();
|
|
||||||
transactions_signatures.push((transaction, signature));
|
|
||||||
|
|
||||||
progress_bar.set_message(&format!(
|
|
||||||
"[{}/{}] Transactions sent",
|
|
||||||
transactions_signatures.len(),
|
|
||||||
num_transactions
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect statuses for all the transactions, drop those that are confirmed
|
|
||||||
while status_retries > 0 {
|
|
||||||
status_retries -= 1;
|
|
||||||
|
|
||||||
progress_bar.set_message(&format!(
|
|
||||||
"[{}/{}] Transactions confirmed",
|
|
||||||
num_transactions - transactions_signatures.len(),
|
|
||||||
num_transactions
|
|
||||||
));
|
|
||||||
|
|
||||||
if cfg!(not(test)) {
|
|
||||||
// Retry twice a second
|
|
||||||
sleep(Duration::from_millis(500));
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions_signatures = transactions_signatures
|
|
||||||
.into_iter()
|
|
||||||
.filter(|(_transaction, signature)| {
|
|
||||||
if let Some(signature) = signature {
|
|
||||||
if let Ok(status) = self.get_signature_status(&signature) {
|
|
||||||
if self
|
|
||||||
.get_num_blocks_since_signature_confirmation(&signature)
|
|
||||||
.unwrap_or(0)
|
|
||||||
> 1
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return match status {
|
|
||||||
None => true,
|
|
||||||
Some(result) => result.is_err(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if transactions_signatures.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if send_retries == 0 {
|
|
||||||
return Err(RpcError::ForUser("Transactions failed".to_string()).into());
|
|
||||||
}
|
|
||||||
send_retries -= 1;
|
|
||||||
|
|
||||||
// Re-sign any failed transactions with a new blockhash and retry
|
|
||||||
let (blockhash, _fee_calculator) =
|
|
||||||
self.get_new_blockhash(&transactions_signatures[0].0.message().recent_blockhash)?;
|
|
||||||
transactions = vec![];
|
|
||||||
for (mut transaction, _) in transactions_signatures.into_iter() {
|
|
||||||
transaction.try_sign(signer_keys, blockhash)?;
|
|
||||||
transactions.push(transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resign_transaction<T: Signers>(
|
pub fn resign_transaction<T: Signers>(
|
||||||
&self,
|
&self,
|
||||||
tx: &mut Transaction,
|
tx: &mut Transaction,
|
||||||
@ -962,6 +871,17 @@ impl RpcClient {
|
|||||||
pub fn send_and_confirm_transaction_with_spinner(
|
pub fn send_and_confirm_transaction_with_spinner(
|
||||||
&self,
|
&self,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
|
) -> ClientResult<Signature> {
|
||||||
|
self.send_and_confirm_transaction_with_spinner_and_config(
|
||||||
|
transaction,
|
||||||
|
RpcSendTransactionConfig::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_and_confirm_transaction_with_spinner_and_config(
|
||||||
|
&self,
|
||||||
|
transaction: &Transaction,
|
||||||
|
config: RpcSendTransactionConfig,
|
||||||
) -> ClientResult<Signature> {
|
) -> ClientResult<Signature> {
|
||||||
let mut confirmations = 0;
|
let mut confirmations = 0;
|
||||||
|
|
||||||
@ -977,7 +897,7 @@ impl RpcClient {
|
|||||||
));
|
));
|
||||||
let mut status_retries = 15;
|
let mut status_retries = 15;
|
||||||
let (signature, status) = loop {
|
let (signature, status) = loop {
|
||||||
let signature = self.send_transaction(transaction)?;
|
let signature = self.send_transaction_with_config(transaction, config.clone())?;
|
||||||
|
|
||||||
// Get recent commitment in order to count confirmations for successful transactions
|
// Get recent commitment in order to count confirmations for successful transactions
|
||||||
let status = self
|
let status = self
|
||||||
|
Reference in New Issue
Block a user