From a2e3a92b01675a3d3f0a14a055ed9c6c528bcc00 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 13 May 2019 12:49:37 -0700 Subject: [PATCH] Extend GetBlockHash RPC API to include the fee scehdule for using the returned blockhash (#4222) --- bench-exchange/src/bench.rs | 11 ++-- bench-tps/src/bench.rs | 6 +- book/src/jsonrpc-api.md | 7 ++- client/src/mock_rpc_client_request.rs | 6 +- client/src/rpc_client.rs | 81 +++++++++++++++------------ client/src/thin_client.rs | 16 +++--- core/src/cluster_tests.rs | 9 ++- core/src/local_cluster.rs | 5 +- core/src/replicator.rs | 2 +- core/src/rpc.rs | 17 ++++-- core/tests/rpc.rs | 2 +- install/src/command.rs | 8 +-- runtime/benches/bank.rs | 14 ++--- runtime/src/bank_client.rs | 12 ++-- sdk/src/client.rs | 5 +- sdk/src/fee_calculator.rs | 1 + wallet/src/wallet.rs | 22 ++++---- 17 files changed, 126 insertions(+), 98 deletions(-) diff --git a/bench-exchange/src/bench.rs b/bench-exchange/src/bench.rs index 99c7ea4918..5cb108d7f4 100644 --- a/bench-exchange/src/bench.rs +++ b/bench-exchange/src/bench.rs @@ -371,7 +371,7 @@ fn swapper( } account_group = (account_group + 1) % account_groups as usize; - let blockhash = client + let (blockhash, _fee_calculator) = client .get_recent_blockhash() .expect("Failed to get blockhash"); let to_swap_txs: Vec<_> = to_swap @@ -499,7 +499,7 @@ fn trader( } account_group = (account_group + 1) % account_groups as usize; - let blockhash = client + let (blockhash, _fee_calculator) = client .get_recent_blockhash() .expect("Failed to get blockhash"); @@ -663,7 +663,8 @@ pub fn fund_keys(client: &Client, source: &Keypair, dests: &[Arc], lamp to_fund_txs.len(), ); - let blockhash = client.get_recent_blockhash().expect("blockhash"); + let (blockhash, _fee_calculator) = + client.get_recent_blockhash().expect("blockhash"); to_fund_txs.par_iter_mut().for_each(|(k, tx)| { tx.sign(&[*k], blockhash); }); @@ -738,7 +739,7 @@ pub fn create_token_accounts(client: &Client, signers: &[Arc], accounts let mut retries = 0; while !to_create_txs.is_empty() { - let blockhash = client + let (blockhash, _fee_calculator) = client .get_recent_blockhash() .expect("Failed to get blockhash"); to_create_txs.par_iter_mut().for_each(|(k, tx)| { @@ -854,7 +855,7 @@ pub fn airdrop_lamports(client: &Client, drone_addr: &SocketAddr, id: &Keypair, let mut tries = 0; loop { - let blockhash = client + let (blockhash, _fee_calculator) = client .get_recent_blockhash() .expect("Failed to get blockhash"); match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) { diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index cf073caaff..8294ade16a 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -140,7 +140,7 @@ where // this seems to be faster than trying to determine the balance of individual // accounts let len = tx_count as usize; - if let Ok(new_blockhash) = client.get_new_blockhash(&blockhash) { + if let Ok((new_blockhash, _fee_calculator)) = client.get_new_blockhash(&blockhash) { blockhash = new_blockhash; } else { if blockhash_time.elapsed().as_secs() > 30 { @@ -404,7 +404,7 @@ pub fn fund_keys(client: &T, source: &Keypair, dests: &[Keypair], lam to_fund_txs.len(), ); - let blockhash = client.get_recent_blockhash().unwrap(); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); // re-sign retained to_fund_txes with updated blockhash to_fund_txs.par_iter_mut().for_each(|(k, tx)| { @@ -454,7 +454,7 @@ pub fn airdrop_lamports( id.pubkey(), ); - let blockhash = client.get_recent_blockhash().unwrap(); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); match request_airdrop_transaction(&drone_addr, &id.pubkey(), airdrop_amount, blockhash) { Ok(transaction) => { let signature = client.async_send_transaction(transaction).unwrap(); diff --git a/book/src/jsonrpc-api.md b/book/src/jsonrpc-api.md index a4ad1a2b26..dd49e4032d 100644 --- a/book/src/jsonrpc-api.md +++ b/book/src/jsonrpc-api.md @@ -167,13 +167,16 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, " --- ### getRecentBlockhash -Returns a recent block hash from the ledger +Returns a recent block hash from the ledger, and a fee schedule that can be used +to compute the cost of submitting a transaction using it. ##### Parameters: None ##### Results: +An array consisting of * `string` - a Hash as base-58 encoded string +* `FeeCalculator object` - the fee schedule for this block hash ##### Example: ```bash @@ -181,7 +184,7 @@ None curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899 // Result -{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1} +{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1} ``` --- diff --git a/client/src/mock_rpc_client_request.rs b/client/src/mock_rpc_client_request.rs index 51c0d97147..df9ef0b20c 100644 --- a/client/src/mock_rpc_client_request.rs +++ b/client/src/mock_rpc_client_request.rs @@ -2,6 +2,7 @@ use crate::client_error::ClientError; use crate::generic_rpc_client_request::GenericRpcClientRequest; use crate::rpc_request::RpcRequest; use serde_json::{Number, Value}; +use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::transaction::{self, TransactionError}; pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8"; @@ -44,7 +45,10 @@ impl GenericRpcClientRequest for MockRpcClientRequest { let n = if self.url == "airdrop" { 0 } else { 50 }; Value::Number(Number::from(n)) } - RpcRequest::GetRecentBlockhash => Value::String(PUBKEY.to_string()), + RpcRequest::GetRecentBlockhash => Value::Array(vec![ + Value::String(PUBKEY.to_string()), + serde_json::to_value(FeeCalculator::default()).unwrap(), + ]), RpcRequest::GetSignatureStatus => { let response: Option> = if self.url == "account_in_use" { Some(Err(TransactionError::AccountInUse)) diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 4a606a451f..b020f2e1ed 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -7,6 +7,7 @@ use bincode::serialize; use log::*; use serde_json::{json, Value}; use solana_sdk::account::Account; +use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{KeypairUtil, Signature}; @@ -186,7 +187,7 @@ impl RpcClient { send_retries -= 1; // Re-sign any failed transactions with a new blockhash and retry - let blockhash = + let (blockhash, _fee_calculator) = self.get_new_blockhash(&transactions_signatures[0].0.message().recent_blockhash)?; transactions = transactions_signatures .into_iter() @@ -203,7 +204,8 @@ impl RpcClient { tx: &mut Transaction, signer_keys: &[&T], ) -> Result<(), ClientError> { - let blockhash = self.get_new_blockhash(&tx.message().recent_blockhash)?; + let (blockhash, _fee_calculator) = + self.get_new_blockhash(&tx.message().recent_blockhash)?; tx.sign(signer_keys, blockhash); Ok(()) } @@ -234,9 +236,11 @@ impl RpcClient { trace!("Response account {:?} {:?}", pubkey, account); Ok(account) }) - .map_err(|error| { - debug!("Response account {}: None (error: {:?})", pubkey, error); - io::Error::new(io::ErrorKind::Other, "AccountNotFound") + .map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("AccountNotFound: pubkey={}: {}", pubkey, err), + ) }) } @@ -264,13 +268,15 @@ impl RpcClient { ) })?; - serde_json::from_value(response).map_err(|error| { - debug!("ParseError: get_transaction_count: {}", error); - io::Error::new(io::ErrorKind::Other, "GetTransactionCount parse failure") + serde_json::from_value(response).map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("GetTransactionCount parse failure: {}", err), + ) }) } - pub fn get_recent_blockhash(&self) -> io::Result { + pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> { let response = self .client .send(&RpcRequest::GetRecentBlockhash, None, 0) @@ -281,21 +287,29 @@ impl RpcClient { ) })?; - response - .as_str() - .ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "GetRecentBlockhash parse failure") - })? - .parse() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "GetRecentBlockhash parse failure")) + let (blockhash, fee_calculator) = + serde_json::from_value::<(String, FeeCalculator)>(response).map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("GetRecentBlockhash parse failure: {:?}", err), + ) + })?; + + let blockhash = blockhash.parse().map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("GetRecentBlockhash parse failure: {:?}", err), + ) + })?; + Ok((blockhash, fee_calculator)) } - pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result { + pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> { let mut num_retries = 10; while num_retries > 0 { - if let Ok(new_blockhash) = self.get_recent_blockhash() { + if let Ok((new_blockhash, fee_calculator)) = self.get_recent_blockhash() { if new_blockhash != *blockhash { - return Ok(new_blockhash); + return Ok((new_blockhash, fee_calculator)); } } debug!("Got same blockhash ({:?}), will retry...", blockhash); @@ -454,24 +468,22 @@ impl RpcClient { Some(params.clone()), 1, ) - .map_err(|error| { - debug!( - "Response get_num_blocks_since_signature_confirmation: {:?}", - error - ); + .map_err(|err| { io::Error::new( io::ErrorKind::Other, - "GetNumBlocksSinceSignatureConfirmation request failure", + format!( + "GetNumBlocksSinceSignatureConfirmation request failure: {}", + err + ), ) })?; - serde_json::from_value(response).map_err(|error| { - debug!( - "ParseError: get_num_blocks_since_signature_confirmation: {}", - error - ); + serde_json::from_value(response).map_err(|err| { io::Error::new( io::ErrorKind::Other, - "GetNumBlocksSinceSignatureConfirmation parse failure", + format!( + "GetNumBlocksSinceSignatureConfirmation parse failure: {}", + err + ), ) }) } @@ -578,7 +590,7 @@ mod tests { // Send erroneous parameter let blockhash = rpc_client.retry_make_rpc_request( &RpcRequest::GetRecentBlockhash, - Some(json!("paramter")), + Some(json!("parameter")), 0, ); assert_eq!(blockhash.is_err(), true); @@ -646,13 +658,12 @@ mod tests { let vec = bs58::decode(PUBKEY).into_vec().unwrap(); let expected_blockhash = Hash::new(&vec); - let blockhash = dbg!(rpc_client.get_recent_blockhash()).expect("blockhash ok"); + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash().expect("blockhash ok"); assert_eq!(blockhash, expected_blockhash); let rpc_client = RpcClient::new_mock("fails".to_string()); - let blockhash = dbg!(rpc_client.get_recent_blockhash()); - assert!(blockhash.is_err()); + assert!(rpc_client.get_recent_blockhash().is_err()); } #[test] diff --git a/client/src/thin_client.rs b/client/src/thin_client.rs index 79632f4293..3be1733b6a 100644 --- a/client/src/thin_client.rs +++ b/client/src/thin_client.rs @@ -7,6 +7,7 @@ use crate::rpc_client::RpcClient; use bincode::{serialize_into, serialized_size}; use log::*; use solana_sdk::client::{AsyncClient, Client, SyncClient}; +use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::hash::Hash; use solana_sdk::instruction::Instruction; use solana_sdk::message::Message; @@ -107,7 +108,8 @@ impl ThinClient { return Ok(transaction.signatures[0]); } info!("{} tries failed transfer to {}", x, self.transactions_addr); - transaction.sign(keypairs, self.rpc_client.get_recent_blockhash()?); + let (blockhash, _fee_calculator) = self.rpc_client.get_recent_blockhash()?; + transaction.sign(keypairs, blockhash); } Err(io::Error::new( io::ErrorKind::Other, @@ -159,7 +161,7 @@ impl Client for ThinClient { impl SyncClient for ThinClient { fn send_message(&self, keypairs: &[&Keypair], message: Message) -> TransportResult { - let blockhash = self.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = self.get_recent_blockhash()?; let mut transaction = Transaction::new(&keypairs, message, blockhash); let signature = self.send_and_confirm_transaction(keypairs, &mut transaction, 5, 0)?; Ok(signature) @@ -210,9 +212,8 @@ impl SyncClient for ThinClient { Ok(status) } - fn get_recent_blockhash(&self) -> TransportResult { - let recent_blockhash = self.rpc_client.get_recent_blockhash()?; - Ok(recent_blockhash) + fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> { + Ok(self.rpc_client.get_recent_blockhash()?) } fn get_transaction_count(&self) -> TransportResult { @@ -235,9 +236,8 @@ impl SyncClient for ThinClient { Ok(self.rpc_client.poll_for_signature(signature)?) } - fn get_new_blockhash(&self, blockhash: &Hash) -> TransportResult { - let new_blockhash = self.rpc_client.get_new_blockhash(blockhash)?; - Ok(new_blockhash) + fn get_new_blockhash(&self, blockhash: &Hash) -> TransportResult<(Hash, FeeCalculator)> { + Ok(self.rpc_client.get_new_blockhash(blockhash)?) } } diff --git a/core/src/cluster_tests.rs b/core/src/cluster_tests.rs index 594b4ff87e..48c720bb8f 100644 --- a/core/src/cluster_tests.rs +++ b/core/src/cluster_tests.rs @@ -39,11 +39,12 @@ pub fn spend_and_verify_all_nodes( .poll_get_balance(&funding_keypair.pubkey()) .expect("balance in source"); assert!(bal > 0); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let mut transaction = system_transaction::transfer( &funding_keypair, &random_keypair.pubkey(), 1, - client.get_recent_blockhash().unwrap(), + blockhash, 0, ); let confs = VOTE_THRESHOLD_DEPTH + 1; @@ -65,11 +66,12 @@ pub fn send_many_transactions(node: &ContactInfo, funding_keypair: &Keypair, num .poll_get_balance(&funding_keypair.pubkey()) .expect("balance in source"); assert!(bal > 0); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let mut transaction = system_transaction::transfer( &funding_keypair, &random_keypair.pubkey(), 1, - client.get_recent_blockhash().unwrap(), + blockhash, 0, ); client @@ -187,11 +189,12 @@ pub fn kill_entry_and_spend_and_verify_rest( } let random_keypair = Keypair::new(); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let mut transaction = system_transaction::transfer( &funding_keypair, &random_keypair.pubkey(), 1, - client.get_recent_blockhash().unwrap(), + blockhash, 0, ); diff --git a/core/src/local_cluster.rs b/core/src/local_cluster.rs index 4770d65892..43399b827f 100644 --- a/core/src/local_cluster.rs +++ b/core/src/local_cluster.rs @@ -338,7 +338,7 @@ impl LocalCluster { lamports: u64, ) -> u64 { trace!("getting leader blockhash"); - let blockhash = client.get_recent_blockhash().unwrap(); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let mut tx = system_transaction::create_user_account( &source_keypair, dest_pubkey, @@ -378,10 +378,11 @@ impl LocalCluster { 0, amount, ); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let mut transaction = Transaction::new_signed_instructions( &[from_account.as_ref()], instructions, - client.get_recent_blockhash().unwrap(), + blockhash, ); client diff --git a/core/src/replicator.rs b/core/src/replicator.rs index 941d127b06..0adc3f3d42 100644 --- a/core/src/replicator.rs +++ b/core/src/replicator.rs @@ -419,7 +419,7 @@ impl Replicator { // check if the account exists let bal = client.poll_get_balance(&storage_keypair.pubkey()); if bal.is_err() || bal.unwrap() == 0 { - let blockhash = client.get_recent_blockhash().expect("blockhash"); + let (blockhash, _fee_calculator) = client.get_recent_blockhash().expect("blockhash"); //TODO the account space needs to be well defined somewhere let tx = system_transaction::create_account( keypair, diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 1b17d93503..deebf9ff77 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -12,6 +12,7 @@ use jsonrpc_derive::rpc; use solana_drone::drone::request_airdrop_transaction; use solana_runtime::bank::Bank; use solana_sdk::account::Account; +use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Signature; use solana_sdk::transaction::{self, Transaction}; @@ -74,9 +75,12 @@ impl JsonRpcRequestProcessor { self.bank().get_balance(&pubkey) } - fn get_recent_blockhash(&self) -> String { + fn get_recent_blockhash(&self) -> (String, FeeCalculator) { let id = self.bank().confirmed_last_blockhash(); - bs58::encode(id).into_string() + ( + bs58::encode(id).into_string(), + self.bank().fee_calculator.clone(), + ) } pub fn get_signature_status(&self, signature: Signature) -> Option> { @@ -199,7 +203,7 @@ pub trait RpcSol { fn get_cluster_nodes(&self, _: Self::Metadata) -> Result>; #[rpc(meta, name = "getRecentBlockhash")] - fn get_recent_blockhash(&self, _: Self::Metadata) -> Result; + fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<(String, FeeCalculator)>; #[rpc(meta, name = "getSignatureStatus")] fn get_signature_status( @@ -303,7 +307,7 @@ impl RpcSol for RpcSolImpl { .collect()) } - fn get_recent_blockhash(&self, meta: Self::Metadata) -> Result { + fn get_recent_blockhash(&self, meta: Self::Metadata) -> Result<(String, FeeCalculator)> { debug!("get_recent_blockhash rpc request received"); Ok(meta .request_processor @@ -732,7 +736,10 @@ mod tests { let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}}"#); let res = io.handle_request_sync(&req, meta); - let expected = format!(r#"{{"jsonrpc":"2.0","result":"{}","id":1}}"#, blockhash); + let expected = format!( + r#"{{"jsonrpc":"2.0","result":["{}", {{"lamportsPerSignature": 0}}],"id":1}}"#, + blockhash + ); let expected: Response = serde_json::from_str(&expected).expect("expected response deserialization"); let result: Response = serde_json::from_str(&res.expect("actual response")) diff --git a/core/tests/rpc.rs b/core/tests/rpc.rs index c9161c9794..0931795023 100644 --- a/core/tests/rpc.rs +++ b/core/tests/rpc.rs @@ -35,7 +35,7 @@ fn test_rpc_send_tx() { .send() .unwrap(); let json: Value = serde_json::from_str(&response.text().unwrap()).unwrap(); - let blockhash_vec = bs58::decode(json["result"].as_str().unwrap()) + let blockhash_vec = bs58::decode(json["result"][0].as_str().unwrap()) .into_vec() .unwrap(); let blockhash = Hash::new(&blockhash_vec); diff --git a/install/src/command.rs b/install/src/command.rs index 59e671fb73..13dd8c79df 100644 --- a/install/src/command.rs +++ b/install/src/command.rs @@ -197,7 +197,7 @@ fn new_update_manifest( .get_account_data(&update_manifest_keypair.pubkey()) .is_err() { - let recect_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let new_account = config_instruction::create_account::( &from_keypair.pubkey(), @@ -205,7 +205,7 @@ fn new_update_manifest( 1, // lamports ); let mut transaction = Transaction::new_unsigned_instructions(vec![new_account]); - transaction.sign(&[from_keypair], recect_blockhash); + transaction.sign(&[from_keypair], recent_blockhash); rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?; } @@ -219,7 +219,7 @@ fn store_update_manifest( update_manifest_keypair: &Keypair, update_manifest: &SignedUpdateManifest, ) -> Result<(), Box> { - let recect_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let signers = [from_keypair, update_manifest_keypair]; let instruction = config_instruction::store::( @@ -228,7 +228,7 @@ fn store_update_manifest( ); let message = Message::new_with_payer(vec![instruction], Some(&from_keypair.pubkey())); - let mut transaction = Transaction::new(&signers, message, recect_blockhash); + let mut transaction = Transaction::new(&signers, message, recent_blockhash); rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?; Ok(()) } diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index ca7c9ef85c..0df9b56603 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -50,11 +50,8 @@ pub fn create_builtin_transactions( .expect(&format!("{}:{}", line!(), file!())); let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8); - Transaction::new_signed_instructions( - &[&rando0], - vec![instruction], - bank_client.get_recent_blockhash().unwrap(), - ) + let (blockhash, _fee_calculator) = bank_client.get_recent_blockhash().unwrap(); + Transaction::new_signed_instructions(&[&rando0], vec![instruction], blockhash) }) .collect() } @@ -76,11 +73,8 @@ pub fn create_native_loader_transactions( .expect(&format!("{}:{}", line!(), file!())); let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8); - Transaction::new_signed_instructions( - &[&rando0], - vec![instruction], - bank_client.get_recent_blockhash().unwrap(), - ) + let (blockhash, _fee_calculator) = bank_client.get_recent_blockhash().unwrap(); + Transaction::new_signed_instructions(&[&rando0], vec![instruction], blockhash) }) .collect() } diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index 81e5b6d575..b8685c7004 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -1,5 +1,6 @@ use crate::bank::Bank; use solana_sdk::client::{AsyncClient, Client, SyncClient}; +use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::hash::Hash; use solana_sdk::instruction::Instruction; use solana_sdk::message::Message; @@ -105,9 +106,10 @@ impl SyncClient for BankClient { Ok(self.bank.get_signature_status(signature)) } - fn get_recent_blockhash(&self) -> Result { + fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> { let last_blockhash = self.bank.last_blockhash(); - Ok(last_blockhash) + let fee_calculator = self.bank.fee_calculator.clone(); + Ok((last_blockhash, fee_calculator)) } fn get_transaction_count(&self) -> Result { @@ -167,10 +169,10 @@ impl SyncClient for BankClient { Ok(()) } - fn get_new_blockhash(&self, blockhash: &Hash) -> Result { - let last_blockhash = self.bank.last_blockhash(); + fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)> { + let (last_blockhash, fee_calculator) = self.get_recent_blockhash()?; if last_blockhash != *blockhash { - Ok(last_blockhash) + Ok((last_blockhash, fee_calculator)) } else { Err(TransportError::IoError(io::Error::new( io::ErrorKind::Other, diff --git a/sdk/src/client.rs b/sdk/src/client.rs index 42b03aee03..b7aa3bf300 100644 --- a/sdk/src/client.rs +++ b/sdk/src/client.rs @@ -7,6 +7,7 @@ //! Asynchronous implementations are expected to create transactions, sign them, and send //! them but without waiting to see if the server accepted it. +use crate::fee_calculator::FeeCalculator; use crate::hash::Hash; use crate::instruction::Instruction; use crate::message::Message; @@ -46,7 +47,7 @@ pub trait SyncClient { ) -> Result>>; /// Get recent blockhash - fn get_recent_blockhash(&self) -> Result; + fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)>; /// Get transaction count fn get_transaction_count(&self) -> Result; @@ -61,7 +62,7 @@ pub trait SyncClient { /// Poll to confirm a transaction. fn poll_for_signature(&self, signature: &Signature) -> Result<()>; - fn get_new_blockhash(&self, blockhash: &Hash) -> Result; + fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)>; } pub trait AsyncClient { diff --git a/sdk/src/fee_calculator.rs b/sdk/src/fee_calculator.rs index 812df2f4cf..c23307cbf6 100644 --- a/sdk/src/fee_calculator.rs +++ b/sdk/src/fee_calculator.rs @@ -1,6 +1,7 @@ use crate::message::Message; #[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct FeeCalculator { pub lamports_per_signature: u64, } diff --git a/wallet/src/wallet.rs b/wallet/src/wallet.rs index d60b6b35be..8fbc8206ac 100644 --- a/wallet/src/wallet.rs +++ b/wallet/src/wallet.rs @@ -388,7 +388,7 @@ fn process_create_vote_account( commission, lamports, ); - let recent_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?; Ok(signature_str.to_string()) @@ -399,7 +399,7 @@ fn process_authorize_voter( config: &WalletConfig, authorized_voter_id: &Pubkey, ) -> ProcessResult { - let recent_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![vote_instruction::authorize_voter( &config.keypair.pubkey(), authorized_voter_id, @@ -457,7 +457,7 @@ fn process_create_stake_account( staking_account_id: &Pubkey, lamports: u64, ) -> ProcessResult { - let recent_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![stake_instruction::create_account( &config.keypair.pubkey(), staking_account_id, @@ -474,7 +474,7 @@ fn process_delegate_stake( staking_account_keypair: &Keypair, voting_account_id: &Pubkey, ) -> ProcessResult { - let recent_blockhash = rpc_client.get_recent_blockhash()?; + let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![stake_instruction::delegate_stake( &config.keypair.pubkey(), &staking_account_keypair.pubkey(), @@ -527,7 +527,7 @@ fn process_deploy( } } - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let program_id = Keypair::new(); let mut file = File::open(program_location).map_err(|err| { WalletError::DynamicProgramError( @@ -600,7 +600,7 @@ fn process_pay( witnesses: &Option>, cancelable: Option, ) -> ProcessResult { - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; if timestamp == None && *witnesses == None { let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0); @@ -636,7 +636,7 @@ fn process_pay( }) .to_string()) } else if timestamp == None { - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let witness = if let Some(ref witness_vec) = *witnesses { witness_vec[0] @@ -672,7 +672,7 @@ fn process_pay( } fn process_cancel(rpc_client: &RpcClient, config: &WalletConfig, pubkey: &Pubkey) -> ProcessResult { - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ix = budget_instruction::apply_signature( &config.keypair.pubkey(), pubkey, @@ -703,7 +703,7 @@ fn process_time_elapsed( request_and_confirm_airdrop(&rpc_client, &drone_addr, &config.keypair.pubkey(), 1)?; } - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ix = budget_instruction::apply_timestamp(&config.keypair.pubkey(), pubkey, to, dt); let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash); @@ -726,7 +726,7 @@ fn process_witness( request_and_confirm_airdrop(&rpc_client, &drone_addr, &config.keypair.pubkey(), 1)?; } - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let ix = budget_instruction::apply_signature(&config.keypair.pubkey(), pubkey, to); let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash); let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); @@ -891,7 +891,7 @@ pub fn request_and_confirm_airdrop( to_pubkey: &Pubkey, lamports: u64, ) -> Result<(), Box> { - let blockhash = rpc_client.get_recent_blockhash()?; + let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?; let keypair = { let mut retries = 5; loop {