Update fee api to use blockhash (#21054)
This commit is contained in:
@@ -248,7 +248,7 @@ fn run_accounts_bench(
|
|||||||
let executor = TransactionExecutor::new(entrypoint_addr);
|
let executor = TransactionExecutor::new(entrypoint_addr);
|
||||||
|
|
||||||
// Create and close messages both require 2 signatures, fake a 2 signature message to calculate fees
|
// Create and close messages both require 2 signatures, fake a 2 signature message to calculate fees
|
||||||
let message = Message::new(
|
let mut message = Message::new(
|
||||||
&[
|
&[
|
||||||
Instruction::new_with_bytes(
|
Instruction::new_with_bytes(
|
||||||
Pubkey::new_unique(),
|
Pubkey::new_unique(),
|
||||||
@@ -270,6 +270,7 @@ fn run_accounts_bench(
|
|||||||
latest_blockhash = Instant::now();
|
latest_blockhash = Instant::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.recent_blockhash = blockhash;
|
||||||
let fee = client
|
let fee = client
|
||||||
.get_fee_for_message(&message)
|
.get_fee_for_message(&message)
|
||||||
.expect("get_fee_for_message");
|
.expect("get_fee_for_message");
|
||||||
|
@@ -289,7 +289,7 @@ impl Banks for BanksServer {
|
|||||||
) -> Option<u64> {
|
) -> Option<u64> {
|
||||||
let bank = self.bank(commitment);
|
let bank = self.bank(commitment);
|
||||||
let sanitized_message = SanitizedMessage::try_from(message).ok()?;
|
let sanitized_message = SanitizedMessage::try_from(message).ok()?;
|
||||||
Some(bank.get_fee_for_message(&sanitized_message))
|
bank.get_fee_for_message(&sanitized_message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ use solana_measure::measure::Measure;
|
|||||||
use solana_metrics::{self, datapoint_info};
|
use solana_metrics::{self, datapoint_info};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
client::Client,
|
client::Client,
|
||||||
clock::{DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE},
|
clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, Instruction},
|
instruction::{AccountMeta, Instruction},
|
||||||
@@ -389,6 +389,22 @@ fn generate_txs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_new_latest_blockhash<T: Client>(client: &Arc<T>, blockhash: &Hash) -> Option<Hash> {
|
||||||
|
let start = Instant::now();
|
||||||
|
while start.elapsed().as_secs() < 5 {
|
||||||
|
if let Ok(new_blockhash) = client.get_latest_blockhash() {
|
||||||
|
if new_blockhash != *blockhash {
|
||||||
|
return Some(new_blockhash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!("Got same blockhash ({:?}), will retry...", blockhash);
|
||||||
|
|
||||||
|
// Retry ~twice during a slot
|
||||||
|
sleep(Duration::from_millis(DEFAULT_MS_PER_SLOT / 2));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn poll_blockhash<T: Client>(
|
fn poll_blockhash<T: Client>(
|
||||||
exit_signal: &Arc<AtomicBool>,
|
exit_signal: &Arc<AtomicBool>,
|
||||||
blockhash: &Arc<RwLock<Hash>>,
|
blockhash: &Arc<RwLock<Hash>>,
|
||||||
@@ -400,7 +416,7 @@ fn poll_blockhash<T: Client>(
|
|||||||
loop {
|
loop {
|
||||||
let blockhash_updated = {
|
let blockhash_updated = {
|
||||||
let old_blockhash = *blockhash.read().unwrap();
|
let old_blockhash = *blockhash.read().unwrap();
|
||||||
if let Ok(new_blockhash) = client.get_new_latest_blockhash(&old_blockhash) {
|
if let Some(new_blockhash) = get_new_latest_blockhash(client, &old_blockhash) {
|
||||||
*blockhash.write().unwrap() = new_blockhash;
|
*blockhash.write().unwrap() = new_blockhash;
|
||||||
blockhash_last_updated = Instant::now();
|
blockhash_last_updated = Instant::now();
|
||||||
true
|
true
|
||||||
@@ -888,13 +904,14 @@ pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
|
|||||||
// pay for the transaction fees in a new run.
|
// pay for the transaction fees in a new run.
|
||||||
let enough_lamports = 8 * lamports_per_account / 10;
|
let enough_lamports = 8 * lamports_per_account / 10;
|
||||||
if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
|
if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
|
||||||
let single_sig_message = Message::new(
|
let single_sig_message = Message::new_with_blockhash(
|
||||||
&[Instruction::new_with_bytes(
|
&[Instruction::new_with_bytes(
|
||||||
Pubkey::new_unique(),
|
Pubkey::new_unique(),
|
||||||
&[],
|
&[],
|
||||||
vec![AccountMeta::new(Pubkey::new_unique(), true)],
|
vec![AccountMeta::new(Pubkey::new_unique(), true)],
|
||||||
)],
|
)],
|
||||||
None,
|
None,
|
||||||
|
&client.get_latest_blockhash().unwrap(),
|
||||||
);
|
);
|
||||||
let max_fee = client.get_fee_for_message(&single_sig_message).unwrap();
|
let max_fee = client.get_fee_for_message(&single_sig_message).unwrap();
|
||||||
let extra_fees = extra * max_fee;
|
let extra_fees = extra * max_fee;
|
||||||
|
@@ -65,7 +65,7 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
|
|||||||
messages: &[&Message],
|
messages: &[&Message],
|
||||||
commitment: CommitmentConfig,
|
commitment: CommitmentConfig,
|
||||||
) -> Result<(), CliError> {
|
) -> Result<(), CliError> {
|
||||||
let fee = get_fee_for_message(rpc_client, messages)?;
|
let fee = get_fee_for_messages(rpc_client, messages)?;
|
||||||
if !check_account_for_balance_with_commitment(
|
if !check_account_for_balance_with_commitment(
|
||||||
rpc_client,
|
rpc_client,
|
||||||
account_pubkey,
|
account_pubkey,
|
||||||
@@ -90,10 +90,16 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fee_for_message(rpc_client: &RpcClient, messages: &[&Message]) -> Result<u64, CliError> {
|
pub fn get_fee_for_messages(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
messages: &[&Message],
|
||||||
|
) -> Result<u64, CliError> {
|
||||||
Ok(messages
|
Ok(messages
|
||||||
.iter()
|
.iter()
|
||||||
.map(|message| rpc_client.get_fee_for_message(message))
|
.map(|message| {
|
||||||
|
println!("msg {:?}", message.recent_blockhash);
|
||||||
|
rpc_client.get_fee_for_message(message)
|
||||||
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.iter()
|
.iter()
|
||||||
.sum())
|
.sum())
|
||||||
@@ -235,7 +241,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_fee_for_message() {
|
fn test_get_fee_for_messages() {
|
||||||
let check_fee_response = json!(Response {
|
let check_fee_response = json!(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: json!(1),
|
value: json!(1),
|
||||||
@@ -245,14 +251,14 @@ mod tests {
|
|||||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||||
|
|
||||||
// No messages, no fee.
|
// No messages, no fee.
|
||||||
assert_eq!(get_fee_for_message(&rpc_client, &[]).unwrap(), 0);
|
assert_eq!(get_fee_for_messages(&rpc_client, &[]).unwrap(), 0);
|
||||||
|
|
||||||
// One message w/ one signature, a fee.
|
// One message w/ one signature, a fee.
|
||||||
let pubkey0 = Pubkey::new(&[0; 32]);
|
let pubkey0 = Pubkey::new(&[0; 32]);
|
||||||
let pubkey1 = Pubkey::new(&[1; 32]);
|
let pubkey1 = Pubkey::new(&[1; 32]);
|
||||||
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
|
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
|
||||||
let message0 = Message::new(&[ix0], Some(&pubkey0));
|
let message0 = Message::new(&[ix0], Some(&pubkey0));
|
||||||
assert_eq!(get_fee_for_message(&rpc_client, &[&message0]).unwrap(), 1);
|
assert_eq!(get_fee_for_messages(&rpc_client, &[&message0]).unwrap(), 1);
|
||||||
|
|
||||||
// No signatures, no fee.
|
// No signatures, no fee.
|
||||||
let check_fee_response = json!(Response {
|
let check_fee_response = json!(Response {
|
||||||
@@ -264,7 +270,7 @@ mod tests {
|
|||||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||||
let message = Message::default();
|
let message = Message::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_fee_for_message(&rpc_client, &[&message, &message]).unwrap(),
|
get_fee_for_messages(&rpc_client, &[&message, &message]).unwrap(),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1710,6 +1710,7 @@ fn do_process_program_write_and_deploy(
|
|||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
// Build messages to calculate fees
|
// Build messages to calculate fees
|
||||||
let mut messages: Vec<&Message> = Vec::new();
|
let mut messages: Vec<&Message> = Vec::new();
|
||||||
|
let blockhash = rpc_client.get_latest_blockhash()?;
|
||||||
|
|
||||||
// Initialize buffer account or complete if already partially initialized
|
// Initialize buffer account or complete if already partially initialized
|
||||||
let (initial_message, write_messages, balance_needed) =
|
let (initial_message, write_messages, balance_needed) =
|
||||||
@@ -1755,9 +1756,10 @@ fn do_process_program_write_and_deploy(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
let initial_message = if !initial_instructions.is_empty() {
|
let initial_message = if !initial_instructions.is_empty() {
|
||||||
Some(Message::new(
|
Some(Message::new_with_blockhash(
|
||||||
&initial_instructions,
|
&initial_instructions,
|
||||||
Some(&config.signers[0].pubkey()),
|
Some(&config.signers[0].pubkey()),
|
||||||
|
&blockhash,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -1777,7 +1779,7 @@ fn do_process_program_write_and_deploy(
|
|||||||
} else {
|
} else {
|
||||||
loader_instruction::write(buffer_pubkey, loader_id, offset, bytes)
|
loader_instruction::write(buffer_pubkey, loader_id, offset, bytes)
|
||||||
};
|
};
|
||||||
Message::new(&[instruction], Some(&payer_pubkey))
|
Message::new_with_blockhash(&[instruction], Some(&payer_pubkey), &blockhash)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut write_messages = vec![];
|
let mut write_messages = vec![];
|
||||||
@@ -1806,7 +1808,7 @@ fn do_process_program_write_and_deploy(
|
|||||||
|
|
||||||
let final_message = if let Some(program_signers) = program_signers {
|
let final_message = if let Some(program_signers) = program_signers {
|
||||||
let message = if loader_id == &bpf_loader_upgradeable::id() {
|
let message = if loader_id == &bpf_loader_upgradeable::id() {
|
||||||
Message::new(
|
Message::new_with_blockhash(
|
||||||
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||||
&config.signers[0].pubkey(),
|
&config.signers[0].pubkey(),
|
||||||
&program_signers[0].pubkey(),
|
&program_signers[0].pubkey(),
|
||||||
@@ -1818,11 +1820,13 @@ fn do_process_program_write_and_deploy(
|
|||||||
programdata_len,
|
programdata_len,
|
||||||
)?,
|
)?,
|
||||||
Some(&config.signers[0].pubkey()),
|
Some(&config.signers[0].pubkey()),
|
||||||
|
&blockhash,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Message::new(
|
Message::new_with_blockhash(
|
||||||
&[loader_instruction::finalize(buffer_pubkey, loader_id)],
|
&[loader_instruction::finalize(buffer_pubkey, loader_id)],
|
||||||
Some(&config.signers[0].pubkey()),
|
Some(&config.signers[0].pubkey()),
|
||||||
|
&blockhash,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
Some(message)
|
Some(message)
|
||||||
@@ -1876,6 +1880,7 @@ fn do_process_program_upgrade(
|
|||||||
|
|
||||||
// Build messages to calculate fees
|
// Build messages to calculate fees
|
||||||
let mut messages: Vec<&Message> = Vec::new();
|
let mut messages: Vec<&Message> = Vec::new();
|
||||||
|
let blockhash = rpc_client.get_latest_blockhash()?;
|
||||||
|
|
||||||
let (initial_message, write_messages, balance_needed) =
|
let (initial_message, write_messages, balance_needed) =
|
||||||
if let Some(buffer_signer) = buffer_signer {
|
if let Some(buffer_signer) = buffer_signer {
|
||||||
@@ -1907,9 +1912,10 @@ fn do_process_program_upgrade(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let initial_message = if !initial_instructions.is_empty() {
|
let initial_message = if !initial_instructions.is_empty() {
|
||||||
Some(Message::new(
|
Some(Message::new_with_blockhash(
|
||||||
&initial_instructions,
|
&initial_instructions,
|
||||||
Some(&config.signers[0].pubkey()),
|
Some(&config.signers[0].pubkey()),
|
||||||
|
&blockhash,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -1925,7 +1931,7 @@ fn do_process_program_upgrade(
|
|||||||
offset,
|
offset,
|
||||||
bytes,
|
bytes,
|
||||||
);
|
);
|
||||||
Message::new(&[instruction], Some(&payer_pubkey))
|
Message::new_with_blockhash(&[instruction], Some(&payer_pubkey), &blockhash)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create and add write messages
|
// Create and add write messages
|
||||||
@@ -1952,7 +1958,7 @@ fn do_process_program_upgrade(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create and add final message
|
// Create and add final message
|
||||||
let final_message = Message::new(
|
let final_message = Message::new_with_blockhash(
|
||||||
&[bpf_loader_upgradeable::upgrade(
|
&[bpf_loader_upgradeable::upgrade(
|
||||||
program_id,
|
program_id,
|
||||||
buffer_pubkey,
|
buffer_pubkey,
|
||||||
@@ -1960,6 +1966,7 @@ fn do_process_program_upgrade(
|
|||||||
&config.signers[0].pubkey(),
|
&config.signers[0].pubkey(),
|
||||||
)],
|
)],
|
||||||
Some(&config.signers[0].pubkey()),
|
Some(&config.signers[0].pubkey()),
|
||||||
|
&blockhash,
|
||||||
);
|
);
|
||||||
messages.push(&final_message);
|
messages.push(&final_message);
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
checks::{check_account_for_balance_with_commitment, get_fee_for_message},
|
checks::{check_account_for_balance_with_commitment, get_fee_for_messages},
|
||||||
cli::CliError,
|
cli::CliError,
|
||||||
};
|
};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
@@ -144,9 +144,10 @@ where
|
|||||||
F: Fn(u64) -> Message,
|
F: Fn(u64) -> Message,
|
||||||
{
|
{
|
||||||
let fee = match blockhash {
|
let fee = match blockhash {
|
||||||
Some(_) => {
|
Some(blockhash) => {
|
||||||
let dummy_message = build_message(0);
|
let mut dummy_message = build_message(0);
|
||||||
get_fee_for_message(rpc_client, &[&dummy_message])?
|
dummy_message.recent_blockhash = *blockhash;
|
||||||
|
get_fee_for_messages(rpc_client, &[&dummy_message])?
|
||||||
}
|
}
|
||||||
None => 0, // Offline, cannot calulate fee
|
None => 0, // Offline, cannot calulate fee
|
||||||
};
|
};
|
||||||
|
@@ -4285,7 +4285,7 @@ impl RpcClient {
|
|||||||
|
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "1.9.0",
|
since = "1.9.0",
|
||||||
note = "Please use `get_new_latest_blockhash` instead"
|
note = "Please do not use, will no longer be available in the future"
|
||||||
)]
|
)]
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub fn get_new_blockhash(&self, blockhash: &Hash) -> ClientResult<(Hash, FeeCalculator)> {
|
pub fn get_new_blockhash(&self, blockhash: &Hash) -> ClientResult<(Hash, FeeCalculator)> {
|
||||||
@@ -4802,7 +4802,9 @@ impl RpcClient {
|
|||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub fn get_fee_for_message(&self, message: &Message) -> ClientResult<u64> {
|
pub fn get_fee_for_message(&self, message: &Message) -> ClientResult<u64> {
|
||||||
if self.get_node_version()? < semver::Version::new(1, 9, 0) {
|
if self.get_node_version()? < semver::Version::new(1, 9, 0) {
|
||||||
let Fees { fee_calculator, .. } = self.get_fees()?;
|
let fee_calculator = self
|
||||||
|
.get_fee_calculator_for_blockhash(&message.recent_blockhash)?
|
||||||
|
.ok_or_else(|| ClientErrorKind::Custom("Invalid blockhash".to_string()))?;
|
||||||
Ok(fee_calculator
|
Ok(fee_calculator
|
||||||
.lamports_per_signature
|
.lamports_per_signature
|
||||||
.saturating_mul(message.header.num_required_signatures as u64))
|
.saturating_mul(message.header.num_required_signatures as u64))
|
||||||
|
@@ -605,12 +605,6 @@ impl SyncClient for ThinClient {
|
|||||||
.get_fee_for_message(message)
|
.get_fee_for_message(message)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_latest_blockhash(&self, blockhash: &Hash) -> TransportResult<Hash> {
|
|
||||||
self.rpc_client()
|
|
||||||
.get_new_latest_blockhash(blockhash)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncClient for ThinClient {
|
impl AsyncClient for ThinClient {
|
||||||
|
@@ -1978,10 +1978,10 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
message: &SanitizedMessage,
|
message: &SanitizedMessage,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<RpcResponse<Option<u64>>> {
|
) -> RpcResponse<Option<u64>> {
|
||||||
let bank = self.bank(commitment);
|
let bank = self.bank(commitment);
|
||||||
let fee = bank.get_fee_for_message(message);
|
let fee = bank.get_fee_for_message(message);
|
||||||
Ok(new_response(&bank, Some(fee)))
|
new_response(&bank, fee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3706,11 +3706,10 @@ pub mod rpc_full {
|
|||||||
debug!("get_fee_for_message rpc request received");
|
debug!("get_fee_for_message rpc request received");
|
||||||
let (_, message) =
|
let (_, message) =
|
||||||
decode_and_deserialize::<Message>(data, UiTransactionEncoding::Base64)?;
|
decode_and_deserialize::<Message>(data, UiTransactionEncoding::Base64)?;
|
||||||
SanitizedMessage::try_from(message)
|
let sanitized_message = SanitizedMessage::try_from(message).map_err(|err| {
|
||||||
.map_err(|err| {
|
Error::invalid_params(format!("invalid transaction message: {}", err))
|
||||||
Error::invalid_params(format!("invalid transaction message: {}", err))
|
})?;
|
||||||
})
|
Ok(meta.get_fee_for_message(&sanitized_message, commitment))
|
||||||
.and_then(|message| meta.get_fee_for_message(&message, commitment))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3118,8 +3118,11 @@ impl Bank {
|
|||||||
&self.fee_rate_governor
|
&self.fee_rate_governor
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> u64 {
|
pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> Option<u64> {
|
||||||
Self::calculate_fee(message, self.fee_rate_governor.lamports_per_signature)
|
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
||||||
|
let lamports_per_signature =
|
||||||
|
blockhash_queue.get_lamports_per_signature(message.recent_blockhash())?;
|
||||||
|
Some(Self::calculate_fee(message, lamports_per_signature))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fee_for_message_with_lamports_per_signature(
|
pub fn get_fee_for_message_with_lamports_per_signature(
|
||||||
@@ -11022,8 +11025,12 @@ pub(crate) mod tests {
|
|||||||
assert_eq!(bank.process_transaction(&durable_tx), Ok(()));
|
assert_eq!(bank.process_transaction(&durable_tx), Ok(()));
|
||||||
|
|
||||||
/* Check balances */
|
/* Check balances */
|
||||||
let mut expected_balance =
|
let mut recent_message = durable_tx.message;
|
||||||
4_650_000 - bank.get_fee_for_message(&durable_tx.message.try_into().unwrap());
|
recent_message.recent_blockhash = bank.last_blockhash();
|
||||||
|
let mut expected_balance = 4_650_000
|
||||||
|
- bank
|
||||||
|
.get_fee_for_message(&recent_message.try_into().unwrap())
|
||||||
|
.unwrap();
|
||||||
assert_eq!(bank.get_balance(&custodian_pubkey), expected_balance);
|
assert_eq!(bank.get_balance(&custodian_pubkey), expected_balance);
|
||||||
assert_eq!(bank.get_balance(&nonce_pubkey), 250_000);
|
assert_eq!(bank.get_balance(&nonce_pubkey), 250_000);
|
||||||
assert_eq!(bank.get_balance(&alice_pubkey), 100_000);
|
assert_eq!(bank.get_balance(&alice_pubkey), 100_000);
|
||||||
@@ -11075,8 +11082,11 @@ pub(crate) mod tests {
|
|||||||
))
|
))
|
||||||
);
|
);
|
||||||
/* Check fee charged and nonce has advanced */
|
/* Check fee charged and nonce has advanced */
|
||||||
|
let mut recent_message = durable_tx.message.clone();
|
||||||
|
recent_message.recent_blockhash = bank.last_blockhash();
|
||||||
expected_balance -= bank
|
expected_balance -= bank
|
||||||
.get_fee_for_message(&SanitizedMessage::try_from(durable_tx.message.clone()).unwrap());
|
.get_fee_for_message(&SanitizedMessage::try_from(recent_message).unwrap())
|
||||||
|
.unwrap();
|
||||||
assert_eq!(bank.get_balance(&custodian_pubkey), expected_balance);
|
assert_eq!(bank.get_balance(&custodian_pubkey), expected_balance);
|
||||||
assert_ne!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
assert_ne!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
||||||
/* Confirm replaying a TX that failed with InstructionError::* now
|
/* Confirm replaying a TX that failed with InstructionError::* now
|
||||||
@@ -11135,10 +11145,14 @@ pub(crate) mod tests {
|
|||||||
))
|
))
|
||||||
);
|
);
|
||||||
/* Check fee charged and nonce has *not* advanced */
|
/* Check fee charged and nonce has *not* advanced */
|
||||||
|
let mut recent_message = durable_tx.message;
|
||||||
|
recent_message.recent_blockhash = bank.last_blockhash();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&custodian_pubkey),
|
bank.get_balance(&custodian_pubkey),
|
||||||
initial_custodian_balance
|
initial_custodian_balance
|
||||||
- bank.get_fee_for_message(&durable_tx.message.try_into().unwrap())
|
- bank
|
||||||
|
.get_fee_for_message(&recent_message.try_into().unwrap())
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
assert_eq!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
||||||
}
|
}
|
||||||
@@ -11185,10 +11199,14 @@ pub(crate) mod tests {
|
|||||||
))
|
))
|
||||||
);
|
);
|
||||||
/* Check fee charged and nonce has advanced */
|
/* Check fee charged and nonce has advanced */
|
||||||
|
let mut recent_message = durable_tx.message;
|
||||||
|
recent_message.recent_blockhash = bank.last_blockhash();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_balance(&nonce_pubkey),
|
bank.get_balance(&nonce_pubkey),
|
||||||
nonce_starting_balance
|
nonce_starting_balance
|
||||||
- bank.get_fee_for_message(&durable_tx.message.try_into().unwrap())
|
- bank
|
||||||
|
.get_fee_for_message(&recent_message.try_into().unwrap())
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
assert_ne!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
assert_ne!(nonce_hash, get_nonce_account(&bank, &nonce_pubkey).unwrap());
|
||||||
}
|
}
|
||||||
|
@@ -314,26 +314,16 @@ impl SyncClient for BankClient {
|
|||||||
|
|
||||||
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
|
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
|
||||||
SanitizedMessage::try_from(message.clone())
|
SanitizedMessage::try_from(message.clone())
|
||||||
.map(|message| self.bank.get_fee_for_message(&message))
|
.ok()
|
||||||
.map_err(|_| {
|
.map(|sanitized_message| self.bank.get_fee_for_message(&sanitized_message))
|
||||||
|
.flatten()
|
||||||
|
.ok_or_else(|| {
|
||||||
TransportError::IoError(io::Error::new(
|
TransportError::IoError(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Unable calculate fee",
|
"Unable calculate fee",
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_latest_blockhash(&self, blockhash: &Hash) -> Result<Hash> {
|
|
||||||
let latest_blockhash = self.get_latest_blockhash()?;
|
|
||||||
if latest_blockhash != *blockhash {
|
|
||||||
Ok(latest_blockhash)
|
|
||||||
} else {
|
|
||||||
Err(TransportError::IoError(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Unable to get new blockhash",
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BankClient {
|
impl BankClient {
|
||||||
|
@@ -3042,18 +3042,19 @@ mod tests {
|
|||||||
|
|
||||||
let slot = slot + 1;
|
let slot = slot + 1;
|
||||||
let bank2 = Arc::new(Bank::new_from_parent(&bank1, &collector, slot));
|
let bank2 = Arc::new(Bank::new_from_parent(&bank1, &collector, slot));
|
||||||
|
let blockhash = bank2.last_blockhash();
|
||||||
let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
|
let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
|
||||||
&key1,
|
&key1,
|
||||||
&key2.pubkey(),
|
&key2.pubkey(),
|
||||||
lamports_to_transfer,
|
lamports_to_transfer,
|
||||||
bank2.last_blockhash(),
|
blockhash,
|
||||||
));
|
));
|
||||||
let fee = bank2.get_fee_for_message(tx.message());
|
let fee = bank2.get_fee_for_message(tx.message()).unwrap();
|
||||||
let tx = system_transaction::transfer(
|
let tx = system_transaction::transfer(
|
||||||
&key1,
|
&key1,
|
||||||
&key2.pubkey(),
|
&key2.pubkey(),
|
||||||
lamports_to_transfer - fee,
|
lamports_to_transfer - fee,
|
||||||
bank2.last_blockhash(),
|
blockhash,
|
||||||
);
|
);
|
||||||
bank2.process_transaction(&tx).unwrap();
|
bank2.process_transaction(&tx).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@@ -245,6 +245,14 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(instructions: &[Instruction], payer: Option<&Pubkey>) -> Self {
|
pub fn new(instructions: &[Instruction], payer: Option<&Pubkey>) -> Self {
|
||||||
|
Self::new_with_blockhash(instructions, payer, &Hash::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_blockhash(
|
||||||
|
instructions: &[Instruction],
|
||||||
|
payer: Option<&Pubkey>,
|
||||||
|
blockhash: &Hash,
|
||||||
|
) -> Self {
|
||||||
let InstructionKeys {
|
let InstructionKeys {
|
||||||
mut signed_keys,
|
mut signed_keys,
|
||||||
unsigned_keys,
|
unsigned_keys,
|
||||||
@@ -259,7 +267,7 @@ impl Message {
|
|||||||
num_readonly_signed_accounts,
|
num_readonly_signed_accounts,
|
||||||
num_readonly_unsigned_accounts,
|
num_readonly_unsigned_accounts,
|
||||||
signed_keys,
|
signed_keys,
|
||||||
Hash::default(),
|
*blockhash,
|
||||||
instructions,
|
instructions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -87,7 +87,7 @@ pub trait SyncClient {
|
|||||||
/// Get recent blockhash. Uses explicit commitment configuration.
|
/// Get recent blockhash. Uses explicit commitment configuration.
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "1.9.0",
|
since = "1.9.0",
|
||||||
note = "Please use `get_latest_blockhash_with_commitment` and `get_fee_for_message` instead"
|
note = "Please use `get_latest_blockhash_with_commitment` and `get_latest_blockhash_with_commitment` instead"
|
||||||
)]
|
)]
|
||||||
fn get_recent_blockhash_with_commitment(
|
fn get_recent_blockhash_with_commitment(
|
||||||
&self,
|
&self,
|
||||||
@@ -151,7 +151,7 @@ pub trait SyncClient {
|
|||||||
|
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "1.9.0",
|
since = "1.9.0",
|
||||||
note = "Please use `get_new_latest_blockhash` instead"
|
note = "Please do not use, will no longer be available in the future"
|
||||||
)]
|
)]
|
||||||
fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)>;
|
fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)>;
|
||||||
|
|
||||||
@@ -169,9 +169,6 @@ pub trait SyncClient {
|
|||||||
|
|
||||||
/// Calculate the fee for a `Message`
|
/// Calculate the fee for a `Message`
|
||||||
fn get_fee_for_message(&self, message: &Message) -> Result<u64>;
|
fn get_fee_for_message(&self, message: &Message) -> Result<u64>;
|
||||||
|
|
||||||
/// Get a new blockhash after the one specified
|
|
||||||
fn get_new_latest_blockhash(&self, blockhash: &Hash) -> Result<Hash>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsyncClient {
|
pub trait AsyncClient {
|
||||||
|
@@ -562,7 +562,7 @@ impl TestValidator {
|
|||||||
{
|
{
|
||||||
let rpc_client =
|
let rpc_client =
|
||||||
RpcClient::new_with_commitment(rpc_url.clone(), CommitmentConfig::processed());
|
RpcClient::new_with_commitment(rpc_url.clone(), CommitmentConfig::processed());
|
||||||
let message = Message::new(
|
let mut message = Message::new(
|
||||||
&[Instruction::new_with_bytes(
|
&[Instruction::new_with_bytes(
|
||||||
Pubkey::new_unique(),
|
Pubkey::new_unique(),
|
||||||
&[],
|
&[],
|
||||||
@@ -579,17 +579,20 @@ impl TestValidator {
|
|||||||
}
|
}
|
||||||
println!("Waiting for fees to stabilize {:?}...", num_tries);
|
println!("Waiting for fees to stabilize {:?}...", num_tries);
|
||||||
match rpc_client.get_latest_blockhash() {
|
match rpc_client.get_latest_blockhash() {
|
||||||
Ok(_) => match rpc_client.get_fee_for_message(&message) {
|
Ok(blockhash) => {
|
||||||
Ok(fee) => {
|
message.recent_blockhash = blockhash;
|
||||||
if fee != 0 {
|
match rpc_client.get_fee_for_message(&message) {
|
||||||
|
Ok(fee) => {
|
||||||
|
if fee != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("get_fee_for_message() failed: {:?}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
}
|
||||||
warn!("get_fee_for_message() failed: {:?}", err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("get_latest_blockhash() failed: {:?}", err);
|
warn!("get_latest_blockhash() failed: {:?}", err);
|
||||||
break;
|
break;
|
||||||
|
@@ -340,7 +340,11 @@ fn build_messages(
|
|||||||
do_create_associated_token_account,
|
do_create_associated_token_account,
|
||||||
);
|
);
|
||||||
let fee_payer_pubkey = args.fee_payer.pubkey();
|
let fee_payer_pubkey = args.fee_payer.pubkey();
|
||||||
let message = Message::new(&instructions, Some(&fee_payer_pubkey));
|
let message = Message::new_with_blockhash(
|
||||||
|
&instructions,
|
||||||
|
Some(&fee_payer_pubkey),
|
||||||
|
&client.get_latest_blockhash()?,
|
||||||
|
);
|
||||||
messages.push(message);
|
messages.push(message);
|
||||||
stake_extras.push((new_stake_account_keypair, lockup_date));
|
stake_extras.push((new_stake_account_keypair, lockup_date));
|
||||||
}
|
}
|
||||||
@@ -1209,14 +1213,15 @@ mod tests {
|
|||||||
use solana_test_validator::TestValidator;
|
use solana_test_validator::TestValidator;
|
||||||
use solana_transaction_status::TransactionConfirmationStatus;
|
use solana_transaction_status::TransactionConfirmationStatus;
|
||||||
|
|
||||||
fn one_signer_message() -> Message {
|
fn one_signer_message(client: &RpcClient) -> Message {
|
||||||
Message::new(
|
Message::new_with_blockhash(
|
||||||
&[Instruction::new_with_bytes(
|
&[Instruction::new_with_bytes(
|
||||||
Pubkey::new_unique(),
|
Pubkey::new_unique(),
|
||||||
&[],
|
&[],
|
||||||
vec![AccountMeta::new(Pubkey::default(), true)],
|
vec![AccountMeta::new(Pubkey::default(), true)],
|
||||||
)],
|
)],
|
||||||
None,
|
None,
|
||||||
|
&client.get_latest_blockhash().unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1598,7 +1603,7 @@ mod tests {
|
|||||||
&sender_keypair_file,
|
&sender_keypair_file,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args).unwrap();
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args).unwrap();
|
||||||
|
|
||||||
// Unfunded payer
|
// Unfunded payer
|
||||||
let unfunded_payer = Keypair::new();
|
let unfunded_payer = Keypair::new();
|
||||||
@@ -1612,7 +1617,7 @@ mod tests {
|
|||||||
.into();
|
.into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -1651,7 +1656,7 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into();
|
.into();
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -1705,7 +1710,7 @@ mod tests {
|
|||||||
&sender_keypair_file,
|
&sender_keypair_file,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args).unwrap();
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args).unwrap();
|
||||||
|
|
||||||
// Unfunded sender
|
// Unfunded sender
|
||||||
let unfunded_payer = Keypair::new();
|
let unfunded_payer = Keypair::new();
|
||||||
@@ -1717,7 +1722,7 @@ mod tests {
|
|||||||
args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into();
|
args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
||||||
@@ -1733,7 +1738,7 @@ mod tests {
|
|||||||
.into();
|
.into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
||||||
@@ -1821,7 +1826,7 @@ mod tests {
|
|||||||
&sender_keypair_file,
|
&sender_keypair_file,
|
||||||
Some(stake_args),
|
Some(stake_args),
|
||||||
);
|
);
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args).unwrap();
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args).unwrap();
|
||||||
|
|
||||||
// Underfunded stake-account
|
// Underfunded stake-account
|
||||||
let expensive_allocation_amount = 5000.0;
|
let expensive_allocation_amount = 5000.0;
|
||||||
@@ -1831,7 +1836,7 @@ mod tests {
|
|||||||
lockup_date: "".to_string(),
|
lockup_date: "".to_string(),
|
||||||
}];
|
}];
|
||||||
let err_result = check_payer_balances(
|
let err_result = check_payer_balances(
|
||||||
&[one_signer_message()],
|
&[one_signer_message(&client)],
|
||||||
&expensive_allocations,
|
&expensive_allocations,
|
||||||
&client,
|
&client,
|
||||||
&args,
|
&args,
|
||||||
@@ -1859,7 +1864,7 @@ mod tests {
|
|||||||
.into();
|
.into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -1898,7 +1903,7 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into();
|
.into();
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -1959,7 +1964,7 @@ mod tests {
|
|||||||
&sender_keypair_file,
|
&sender_keypair_file,
|
||||||
Some(stake_args),
|
Some(stake_args),
|
||||||
);
|
);
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args).unwrap();
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args).unwrap();
|
||||||
|
|
||||||
// Unfunded sender
|
// Unfunded sender
|
||||||
let unfunded_payer = Keypair::new();
|
let unfunded_payer = Keypair::new();
|
||||||
@@ -1971,7 +1976,7 @@ mod tests {
|
|||||||
args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into();
|
args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
assert_eq!(sources, vec![FundingSource::SystemAccount].into());
|
||||||
@@ -1987,7 +1992,7 @@ mod tests {
|
|||||||
.into();
|
.into();
|
||||||
|
|
||||||
let err_result =
|
let err_result =
|
||||||
check_payer_balances(&[one_signer_message()], &allocations, &client, &args)
|
check_payer_balances(&[one_signer_message(&client)], &allocations, &client, &args)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
if let Error::InsufficientFunds(sources, amount) = err_result {
|
if let Error::InsufficientFunds(sources, amount) = err_result {
|
||||||
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
assert_eq!(sources, vec![FundingSource::FeePayer].into());
|
||||||
|
Reference in New Issue
Block a user