Skip to content

Commit

Permalink
Update fee api to use blockhash (#21054)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmay authored Oct 29, 2021
1 parent aea3c66 commit bced07a
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 93 deletions.
3 changes: 2 additions & 1 deletion accounts-cluster-bench/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ fn run_accounts_bench(
let executor = TransactionExecutor::new(entrypoint_addr);

// 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(
Pubkey::new_unique(),
Expand All @@ -270,6 +270,7 @@ fn run_accounts_bench(
latest_blockhash = Instant::now();
}

message.recent_blockhash = blockhash;
let fee = client
.get_fee_for_message(&message)
.expect("get_fee_for_message");
Expand Down
2 changes: 1 addition & 1 deletion banks-server/src/banks_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl Banks for BanksServer {
) -> Option<u64> {
let bank = self.bank(commitment);
let sanitized_message = SanitizedMessage::try_from(message).ok()?;
Some(bank.get_fee_for_message(&sanitized_message))
bank.get_fee_for_message(&sanitized_message)
}
}

Expand Down
23 changes: 20 additions & 3 deletions bench-tps/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_measure::measure::Measure;
use solana_metrics::{self, datapoint_info};
use solana_sdk::{
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,
hash::Hash,
instruction::{AccountMeta, Instruction},
Expand Down Expand Up @@ -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>(
exit_signal: &Arc<AtomicBool>,
blockhash: &Arc<RwLock<Hash>>,
Expand All @@ -400,7 +416,7 @@ fn poll_blockhash<T: Client>(
loop {
let blockhash_updated = {
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_last_updated = Instant::now();
true
Expand Down Expand Up @@ -888,13 +904,14 @@ pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
// pay for the transaction fees in a new run.
let enough_lamports = 8 * lamports_per_account / 10;
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(
Pubkey::new_unique(),
&[],
vec![AccountMeta::new(Pubkey::new_unique(), true)],
)],
None,
&client.get_latest_blockhash().unwrap(),
);
let max_fee = client.get_fee_for_message(&single_sig_message).unwrap();
let extra_fees = extra * max_fee;
Expand Down
20 changes: 13 additions & 7 deletions cli/src/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
messages: &[&Message],
commitment: CommitmentConfig,
) -> 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(
rpc_client,
account_pubkey,
Expand All @@ -90,10 +90,16 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
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
.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<_>, _>>()?
.iter()
.sum())
Expand Down Expand Up @@ -235,7 +241,7 @@ mod tests {
}

#[test]
fn test_get_fee_for_message() {
fn test_get_fee_for_messages() {
let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
value: json!(1),
Expand All @@ -245,14 +251,14 @@ mod tests {
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);

// 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.
let pubkey0 = Pubkey::new(&[0; 32]);
let pubkey1 = Pubkey::new(&[1; 32]);
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
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.
let check_fee_response = json!(Response {
Expand All @@ -264,7 +270,7 @@ mod tests {
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
let message = Message::default();
assert_eq!(
get_fee_for_message(&rpc_client, &[&message, &message]).unwrap(),
get_fee_for_messages(&rpc_client, &[&message, &message]).unwrap(),
0
);
}
Expand Down
21 changes: 14 additions & 7 deletions cli/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1710,6 +1710,7 @@ fn do_process_program_write_and_deploy(
) -> ProcessResult {
// Build messages to calculate fees
let mut messages: Vec<&Message> = Vec::new();
let blockhash = rpc_client.get_latest_blockhash()?;

// Initialize buffer account or complete if already partially initialized
let (initial_message, write_messages, balance_needed) =
Expand Down Expand Up @@ -1755,9 +1756,10 @@ fn do_process_program_write_and_deploy(
)
};
let initial_message = if !initial_instructions.is_empty() {
Some(Message::new(
Some(Message::new_with_blockhash(
&initial_instructions,
Some(&config.signers[0].pubkey()),
&blockhash,
))
} else {
None
Expand All @@ -1777,7 +1779,7 @@ fn do_process_program_write_and_deploy(
} else {
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![];
Expand Down Expand Up @@ -1806,7 +1808,7 @@ fn do_process_program_write_and_deploy(

let final_message = if let Some(program_signers) = program_signers {
let message = if loader_id == &bpf_loader_upgradeable::id() {
Message::new(
Message::new_with_blockhash(
&bpf_loader_upgradeable::deploy_with_max_program_len(
&config.signers[0].pubkey(),
&program_signers[0].pubkey(),
Expand All @@ -1818,11 +1820,13 @@ fn do_process_program_write_and_deploy(
programdata_len,
)?,
Some(&config.signers[0].pubkey()),
&blockhash,
)
} else {
Message::new(
Message::new_with_blockhash(
&[loader_instruction::finalize(buffer_pubkey, loader_id)],
Some(&config.signers[0].pubkey()),
&blockhash,
)
};
Some(message)
Expand Down Expand Up @@ -1876,6 +1880,7 @@ fn do_process_program_upgrade(

// Build messages to calculate fees
let mut messages: Vec<&Message> = Vec::new();
let blockhash = rpc_client.get_latest_blockhash()?;

let (initial_message, write_messages, balance_needed) =
if let Some(buffer_signer) = buffer_signer {
Expand Down Expand Up @@ -1907,9 +1912,10 @@ fn do_process_program_upgrade(
};

let initial_message = if !initial_instructions.is_empty() {
Some(Message::new(
Some(Message::new_with_blockhash(
&initial_instructions,
Some(&config.signers[0].pubkey()),
&blockhash,
))
} else {
None
Expand All @@ -1925,7 +1931,7 @@ fn do_process_program_upgrade(
offset,
bytes,
);
Message::new(&[instruction], Some(&payer_pubkey))
Message::new_with_blockhash(&[instruction], Some(&payer_pubkey), &blockhash)
};

// Create and add write messages
Expand All @@ -1952,14 +1958,15 @@ fn do_process_program_upgrade(
}

// Create and add final message
let final_message = Message::new(
let final_message = Message::new_with_blockhash(
&[bpf_loader_upgradeable::upgrade(
program_id,
buffer_pubkey,
&upgrade_authority.pubkey(),
&config.signers[0].pubkey(),
)],
Some(&config.signers[0].pubkey()),
&blockhash,
);
messages.push(&final_message);

Expand Down
9 changes: 5 additions & 4 deletions cli/src/spend_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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,
};
use clap::ArgMatches;
Expand Down Expand Up @@ -144,9 +144,10 @@ where
F: Fn(u64) -> Message,
{
let fee = match blockhash {
Some(_) => {
let dummy_message = build_message(0);
get_fee_for_message(rpc_client, &[&dummy_message])?
Some(blockhash) => {
let mut dummy_message = build_message(0);
dummy_message.recent_blockhash = *blockhash;
get_fee_for_messages(rpc_client, &[&dummy_message])?
}
None => 0, // Offline, cannot calulate fee
};
Expand Down
6 changes: 4 additions & 2 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4285,7 +4285,7 @@ impl RpcClient {

#[deprecated(
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)]
pub fn get_new_blockhash(&self, blockhash: &Hash) -> ClientResult<(Hash, FeeCalculator)> {
Expand Down Expand Up @@ -4802,7 +4802,9 @@ impl RpcClient {
#[allow(deprecated)]
pub fn get_fee_for_message(&self, message: &Message) -> ClientResult<u64> {
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
.lamports_per_signature
.saturating_mul(message.header.num_required_signatures as u64))
Expand Down
6 changes: 0 additions & 6 deletions client/src/thin_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,12 +605,6 @@ impl SyncClient for ThinClient {
.get_fee_for_message(message)
.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 {
Expand Down
13 changes: 6 additions & 7 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1978,10 +1978,10 @@ impl JsonRpcRequestProcessor {
&self,
message: &SanitizedMessage,
commitment: Option<CommitmentConfig>,
) -> Result<RpcResponse<Option<u64>>> {
) -> RpcResponse<Option<u64>> {
let bank = self.bank(commitment);
let fee = bank.get_fee_for_message(message);
Ok(new_response(&bank, Some(fee)))
new_response(&bank, fee)
}
}

Expand Down Expand Up @@ -3706,11 +3706,10 @@ pub mod rpc_full {
debug!("get_fee_for_message rpc request received");
let (_, message) =
decode_and_deserialize::<Message>(data, UiTransactionEncoding::Base64)?;
SanitizedMessage::try_from(message)
.map_err(|err| {
Error::invalid_params(format!("invalid transaction message: {}", err))
})
.and_then(|message| meta.get_fee_for_message(&message, commitment))
let sanitized_message = SanitizedMessage::try_from(message).map_err(|err| {
Error::invalid_params(format!("invalid transaction message: {}", err))
})?;
Ok(meta.get_fee_for_message(&sanitized_message, commitment))
}
}
}
Expand Down
Loading

0 comments on commit bced07a

Please sign in to comment.