Extend GetBlockHash RPC API to include the fee scehdule for using the returned blockhash (#4222)

This commit is contained in:
Michael Vines 2019-05-13 12:49:37 -07:00 committed by GitHub
parent 23c696706b
commit a2e3a92b01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 126 additions and 98 deletions

View File

@ -371,7 +371,7 @@ fn swapper<T>(
} }
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let blockhash = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
let to_swap_txs: Vec<_> = to_swap let to_swap_txs: Vec<_> = to_swap
@ -499,7 +499,7 @@ fn trader<T>(
} }
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let blockhash = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
@ -663,7 +663,8 @@ pub fn fund_keys(client: &Client, source: &Keypair, dests: &[Arc<Keypair>], lamp
to_fund_txs.len(), 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)| { to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
tx.sign(&[*k], blockhash); tx.sign(&[*k], blockhash);
}); });
@ -738,7 +739,7 @@ pub fn create_token_accounts(client: &Client, signers: &[Arc<Keypair>], accounts
let mut retries = 0; let mut retries = 0;
while !to_create_txs.is_empty() { while !to_create_txs.is_empty() {
let blockhash = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
to_create_txs.par_iter_mut().for_each(|(k, tx)| { 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; let mut tries = 0;
loop { loop {
let blockhash = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) { match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) {

View File

@ -140,7 +140,7 @@ where
// this seems to be faster than trying to determine the balance of individual // this seems to be faster than trying to determine the balance of individual
// accounts // accounts
let len = tx_count as usize; 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; blockhash = new_blockhash;
} else { } else {
if blockhash_time.elapsed().as_secs() > 30 { if blockhash_time.elapsed().as_secs() > 30 {
@ -404,7 +404,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Keypair], lam
to_fund_txs.len(), 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 // re-sign retained to_fund_txes with updated blockhash
to_fund_txs.par_iter_mut().for_each(|(k, tx)| { to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
@ -454,7 +454,7 @@ pub fn airdrop_lamports<T: Client>(
id.pubkey(), 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) { match request_airdrop_transaction(&drone_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => { Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap(); let signature = client.async_send_transaction(transaction).unwrap();

View File

@ -167,13 +167,16 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
--- ---
### getRecentBlockhash ### 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: ##### Parameters:
None None
##### Results: ##### Results:
An array consisting of
* `string` - a Hash as base-58 encoded string * `string` - a Hash as base-58 encoded string
* `FeeCalculator object` - the fee schedule for this block hash
##### Example: ##### Example:
```bash ```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 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1} {"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1}
``` ```
--- ---

View File

@ -2,6 +2,7 @@ use crate::client_error::ClientError;
use crate::generic_rpc_client_request::GenericRpcClientRequest; use crate::generic_rpc_client_request::GenericRpcClientRequest;
use crate::rpc_request::RpcRequest; use crate::rpc_request::RpcRequest;
use serde_json::{Number, Value}; use serde_json::{Number, Value};
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::transaction::{self, TransactionError}; use solana_sdk::transaction::{self, TransactionError};
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8"; pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
@ -44,7 +45,10 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
let n = if self.url == "airdrop" { 0 } else { 50 }; let n = if self.url == "airdrop" { 0 } else { 50 };
Value::Number(Number::from(n)) 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 => { RpcRequest::GetSignatureStatus => {
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" { let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
Some(Err(TransactionError::AccountInUse)) Some(Err(TransactionError::AccountInUse))

View File

@ -7,6 +7,7 @@ use bincode::serialize;
use log::*; use log::*;
use serde_json::{json, Value}; use serde_json::{json, Value};
use solana_sdk::account::Account; use solana_sdk::account::Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{KeypairUtil, Signature}; use solana_sdk::signature::{KeypairUtil, Signature};
@ -186,7 +187,7 @@ impl RpcClient {
send_retries -= 1; send_retries -= 1;
// Re-sign any failed transactions with a new blockhash and retry // 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)?; self.get_new_blockhash(&transactions_signatures[0].0.message().recent_blockhash)?;
transactions = transactions_signatures transactions = transactions_signatures
.into_iter() .into_iter()
@ -203,7 +204,8 @@ impl RpcClient {
tx: &mut Transaction, tx: &mut Transaction,
signer_keys: &[&T], signer_keys: &[&T],
) -> Result<(), ClientError> { ) -> 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); tx.sign(signer_keys, blockhash);
Ok(()) Ok(())
} }
@ -234,9 +236,11 @@ impl RpcClient {
trace!("Response account {:?} {:?}", pubkey, account); trace!("Response account {:?} {:?}", pubkey, account);
Ok(account) Ok(account)
}) })
.map_err(|error| { .map_err(|err| {
debug!("Response account {}: None (error: {:?})", pubkey, error); io::Error::new(
io::Error::new(io::ErrorKind::Other, "AccountNotFound") io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}: {}", pubkey, err),
)
}) })
} }
@ -264,13 +268,15 @@ impl RpcClient {
) )
})?; })?;
serde_json::from_value(response).map_err(|error| { serde_json::from_value(response).map_err(|err| {
debug!("ParseError: get_transaction_count: {}", error); io::Error::new(
io::Error::new(io::ErrorKind::Other, "GetTransactionCount parse failure") io::ErrorKind::Other,
format!("GetTransactionCount parse failure: {}", err),
)
}) })
} }
pub fn get_recent_blockhash(&self) -> io::Result<Hash> { pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetRecentBlockhash, None, 0) .send(&RpcRequest::GetRecentBlockhash, None, 0)
@ -281,21 +287,29 @@ impl RpcClient {
) )
})?; })?;
response let (blockhash, fee_calculator) =
.as_str() serde_json::from_value::<(String, FeeCalculator)>(response).map_err(|err| {
.ok_or_else(|| { io::Error::new(
io::Error::new(io::ErrorKind::Other, "GetRecentBlockhash parse failure") io::ErrorKind::Other,
})? format!("GetRecentBlockhash parse failure: {:?}", err),
.parse() )
.map_err(|_| io::Error::new(io::ErrorKind::Other, "GetRecentBlockhash parse failure")) })?;
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<Hash> { pub fn get_new_blockhash(&self, blockhash: &Hash) -> io::Result<(Hash, FeeCalculator)> {
let mut num_retries = 10; let mut num_retries = 10;
while num_retries > 0 { 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 { if new_blockhash != *blockhash {
return Ok(new_blockhash); return Ok((new_blockhash, fee_calculator));
} }
} }
debug!("Got same blockhash ({:?}), will retry...", blockhash); debug!("Got same blockhash ({:?}), will retry...", blockhash);
@ -454,24 +468,22 @@ impl RpcClient {
Some(params.clone()), Some(params.clone()),
1, 1,
) )
.map_err(|error| { .map_err(|err| {
debug!(
"Response get_num_blocks_since_signature_confirmation: {:?}",
error
);
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
"GetNumBlocksSinceSignatureConfirmation request failure", format!(
"GetNumBlocksSinceSignatureConfirmation request failure: {}",
err
),
) )
})?; })?;
serde_json::from_value(response).map_err(|error| { serde_json::from_value(response).map_err(|err| {
debug!(
"ParseError: get_num_blocks_since_signature_confirmation: {}",
error
);
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
"GetNumBlocksSinceSignatureConfirmation parse failure", format!(
"GetNumBlocksSinceSignatureConfirmation parse failure: {}",
err
),
) )
}) })
} }
@ -578,7 +590,7 @@ mod tests {
// Send erroneous parameter // Send erroneous parameter
let blockhash = rpc_client.retry_make_rpc_request( let blockhash = rpc_client.retry_make_rpc_request(
&RpcRequest::GetRecentBlockhash, &RpcRequest::GetRecentBlockhash,
Some(json!("paramter")), Some(json!("parameter")),
0, 0,
); );
assert_eq!(blockhash.is_err(), true); assert_eq!(blockhash.is_err(), true);
@ -646,13 +658,12 @@ mod tests {
let vec = bs58::decode(PUBKEY).into_vec().unwrap(); let vec = bs58::decode(PUBKEY).into_vec().unwrap();
let expected_blockhash = Hash::new(&vec); 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); assert_eq!(blockhash, expected_blockhash);
let rpc_client = RpcClient::new_mock("fails".to_string()); let rpc_client = RpcClient::new_mock("fails".to_string());
let blockhash = dbg!(rpc_client.get_recent_blockhash()); assert!(rpc_client.get_recent_blockhash().is_err());
assert!(blockhash.is_err());
} }
#[test] #[test]

View File

@ -7,6 +7,7 @@ use crate::rpc_client::RpcClient;
use bincode::{serialize_into, serialized_size}; use bincode::{serialize_into, serialized_size};
use log::*; use log::*;
use solana_sdk::client::{AsyncClient, Client, SyncClient}; use solana_sdk::client::{AsyncClient, Client, SyncClient};
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::instruction::Instruction; use solana_sdk::instruction::Instruction;
use solana_sdk::message::Message; use solana_sdk::message::Message;
@ -107,7 +108,8 @@ impl ThinClient {
return Ok(transaction.signatures[0]); return Ok(transaction.signatures[0]);
} }
info!("{} tries failed transfer to {}", x, self.transactions_addr); 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( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -159,7 +161,7 @@ impl Client for ThinClient {
impl SyncClient for ThinClient { impl SyncClient for ThinClient {
fn send_message(&self, keypairs: &[&Keypair], message: Message) -> TransportResult<Signature> { fn send_message(&self, keypairs: &[&Keypair], message: Message) -> TransportResult<Signature> {
let blockhash = self.get_recent_blockhash()?; let (blockhash, _fee_calculator) = self.get_recent_blockhash()?;
let mut transaction = Transaction::new(&keypairs, message, blockhash); let mut transaction = Transaction::new(&keypairs, message, blockhash);
let signature = self.send_and_confirm_transaction(keypairs, &mut transaction, 5, 0)?; let signature = self.send_and_confirm_transaction(keypairs, &mut transaction, 5, 0)?;
Ok(signature) Ok(signature)
@ -210,9 +212,8 @@ impl SyncClient for ThinClient {
Ok(status) Ok(status)
} }
fn get_recent_blockhash(&self) -> TransportResult<Hash> { fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
let recent_blockhash = self.rpc_client.get_recent_blockhash()?; Ok(self.rpc_client.get_recent_blockhash()?)
Ok(recent_blockhash)
} }
fn get_transaction_count(&self) -> TransportResult<u64> { fn get_transaction_count(&self) -> TransportResult<u64> {
@ -235,9 +236,8 @@ impl SyncClient for ThinClient {
Ok(self.rpc_client.poll_for_signature(signature)?) Ok(self.rpc_client.poll_for_signature(signature)?)
} }
fn get_new_blockhash(&self, blockhash: &Hash) -> TransportResult<Hash> { fn get_new_blockhash(&self, blockhash: &Hash) -> TransportResult<(Hash, FeeCalculator)> {
let new_blockhash = self.rpc_client.get_new_blockhash(blockhash)?; Ok(self.rpc_client.get_new_blockhash(blockhash)?)
Ok(new_blockhash)
} }
} }

View File

@ -39,11 +39,12 @@ pub fn spend_and_verify_all_nodes(
.poll_get_balance(&funding_keypair.pubkey()) .poll_get_balance(&funding_keypair.pubkey())
.expect("balance in source"); .expect("balance in source");
assert!(bal > 0); assert!(bal > 0);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
let mut transaction = system_transaction::transfer( let mut transaction = system_transaction::transfer(
&funding_keypair, &funding_keypair,
&random_keypair.pubkey(), &random_keypair.pubkey(),
1, 1,
client.get_recent_blockhash().unwrap(), blockhash,
0, 0,
); );
let confs = VOTE_THRESHOLD_DEPTH + 1; 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()) .poll_get_balance(&funding_keypair.pubkey())
.expect("balance in source"); .expect("balance in source");
assert!(bal > 0); assert!(bal > 0);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
let mut transaction = system_transaction::transfer( let mut transaction = system_transaction::transfer(
&funding_keypair, &funding_keypair,
&random_keypair.pubkey(), &random_keypair.pubkey(),
1, 1,
client.get_recent_blockhash().unwrap(), blockhash,
0, 0,
); );
client client
@ -187,11 +189,12 @@ pub fn kill_entry_and_spend_and_verify_rest(
} }
let random_keypair = Keypair::new(); let random_keypair = Keypair::new();
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
let mut transaction = system_transaction::transfer( let mut transaction = system_transaction::transfer(
&funding_keypair, &funding_keypair,
&random_keypair.pubkey(), &random_keypair.pubkey(),
1, 1,
client.get_recent_blockhash().unwrap(), blockhash,
0, 0,
); );

View File

@ -338,7 +338,7 @@ impl LocalCluster {
lamports: u64, lamports: u64,
) -> u64 { ) -> u64 {
trace!("getting leader blockhash"); 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( let mut tx = system_transaction::create_user_account(
&source_keypair, &source_keypair,
dest_pubkey, dest_pubkey,
@ -378,10 +378,11 @@ impl LocalCluster {
0, 0,
amount, amount,
); );
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
let mut transaction = Transaction::new_signed_instructions( let mut transaction = Transaction::new_signed_instructions(
&[from_account.as_ref()], &[from_account.as_ref()],
instructions, instructions,
client.get_recent_blockhash().unwrap(), blockhash,
); );
client client

View File

@ -419,7 +419,7 @@ impl Replicator {
// check if the account exists // check if the account exists
let bal = client.poll_get_balance(&storage_keypair.pubkey()); let bal = client.poll_get_balance(&storage_keypair.pubkey());
if bal.is_err() || bal.unwrap() == 0 { 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 //TODO the account space needs to be well defined somewhere
let tx = system_transaction::create_account( let tx = system_transaction::create_account(
keypair, keypair,

View File

@ -12,6 +12,7 @@ use jsonrpc_derive::rpc;
use solana_drone::drone::request_airdrop_transaction; use solana_drone::drone::request_airdrop_transaction;
use solana_runtime::bank::Bank; use solana_runtime::bank::Bank;
use solana_sdk::account::Account; use solana_sdk::account::Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signature; use solana_sdk::signature::Signature;
use solana_sdk::transaction::{self, Transaction}; use solana_sdk::transaction::{self, Transaction};
@ -74,9 +75,12 @@ impl JsonRpcRequestProcessor {
self.bank().get_balance(&pubkey) 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(); 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<transaction::Result<()>> { pub fn get_signature_status(&self, signature: Signature) -> Option<transaction::Result<()>> {
@ -199,7 +203,7 @@ pub trait RpcSol {
fn get_cluster_nodes(&self, _: Self::Metadata) -> Result<Vec<RpcContactInfo>>; fn get_cluster_nodes(&self, _: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
#[rpc(meta, name = "getRecentBlockhash")] #[rpc(meta, name = "getRecentBlockhash")]
fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<String>; fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<(String, FeeCalculator)>;
#[rpc(meta, name = "getSignatureStatus")] #[rpc(meta, name = "getSignatureStatus")]
fn get_signature_status( fn get_signature_status(
@ -303,7 +307,7 @@ impl RpcSol for RpcSolImpl {
.collect()) .collect())
} }
fn get_recent_blockhash(&self, meta: Self::Metadata) -> Result<String> { fn get_recent_blockhash(&self, meta: Self::Metadata) -> Result<(String, FeeCalculator)> {
debug!("get_recent_blockhash rpc request received"); debug!("get_recent_blockhash rpc request received");
Ok(meta Ok(meta
.request_processor .request_processor
@ -732,7 +736,10 @@ mod tests {
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}}"#); let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}}"#);
let res = io.handle_request_sync(&req, meta); 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 = let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization"); serde_json::from_str(&expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response")) let result: Response = serde_json::from_str(&res.expect("actual response"))

View File

@ -35,7 +35,7 @@ fn test_rpc_send_tx() {
.send() .send()
.unwrap(); .unwrap();
let json: Value = serde_json::from_str(&response.text().unwrap()).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() .into_vec()
.unwrap(); .unwrap();
let blockhash = Hash::new(&blockhash_vec); let blockhash = Hash::new(&blockhash_vec);

View File

@ -197,7 +197,7 @@ fn new_update_manifest(
.get_account_data(&update_manifest_keypair.pubkey()) .get_account_data(&update_manifest_keypair.pubkey())
.is_err() .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::<SignedUpdateManifest>( let new_account = config_instruction::create_account::<SignedUpdateManifest>(
&from_keypair.pubkey(), &from_keypair.pubkey(),
@ -205,7 +205,7 @@ fn new_update_manifest(
1, // lamports 1, // lamports
); );
let mut transaction = Transaction::new_unsigned_instructions(vec![new_account]); 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])?; rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
} }
@ -219,7 +219,7 @@ fn store_update_manifest(
update_manifest_keypair: &Keypair, update_manifest_keypair: &Keypair,
update_manifest: &SignedUpdateManifest, update_manifest: &SignedUpdateManifest,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
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 signers = [from_keypair, update_manifest_keypair];
let instruction = config_instruction::store::<SignedUpdateManifest>( let instruction = config_instruction::store::<SignedUpdateManifest>(
@ -228,7 +228,7 @@ fn store_update_manifest(
); );
let message = Message::new_with_payer(vec![instruction], Some(&from_keypair.pubkey())); 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])?; rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
Ok(()) Ok(())
} }

View File

@ -50,11 +50,8 @@ pub fn create_builtin_transactions(
.expect(&format!("{}:{}", line!(), file!())); .expect(&format!("{}:{}", line!(), file!()));
let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8); let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8);
Transaction::new_signed_instructions( let (blockhash, _fee_calculator) = bank_client.get_recent_blockhash().unwrap();
&[&rando0], Transaction::new_signed_instructions(&[&rando0], vec![instruction], blockhash)
vec![instruction],
bank_client.get_recent_blockhash().unwrap(),
)
}) })
.collect() .collect()
} }
@ -76,11 +73,8 @@ pub fn create_native_loader_transactions(
.expect(&format!("{}:{}", line!(), file!())); .expect(&format!("{}:{}", line!(), file!()));
let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8); let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8);
Transaction::new_signed_instructions( let (blockhash, _fee_calculator) = bank_client.get_recent_blockhash().unwrap();
&[&rando0], Transaction::new_signed_instructions(&[&rando0], vec![instruction], blockhash)
vec![instruction],
bank_client.get_recent_blockhash().unwrap(),
)
}) })
.collect() .collect()
} }

View File

@ -1,5 +1,6 @@
use crate::bank::Bank; use crate::bank::Bank;
use solana_sdk::client::{AsyncClient, Client, SyncClient}; use solana_sdk::client::{AsyncClient, Client, SyncClient};
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::instruction::Instruction; use solana_sdk::instruction::Instruction;
use solana_sdk::message::Message; use solana_sdk::message::Message;
@ -105,9 +106,10 @@ impl SyncClient for BankClient {
Ok(self.bank.get_signature_status(signature)) Ok(self.bank.get_signature_status(signature))
} }
fn get_recent_blockhash(&self) -> Result<Hash> { fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> {
let last_blockhash = self.bank.last_blockhash(); 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<u64> { fn get_transaction_count(&self) -> Result<u64> {
@ -167,10 +169,10 @@ impl SyncClient for BankClient {
Ok(()) Ok(())
} }
fn get_new_blockhash(&self, blockhash: &Hash) -> Result<Hash> { fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)> {
let last_blockhash = self.bank.last_blockhash(); let (last_blockhash, fee_calculator) = self.get_recent_blockhash()?;
if last_blockhash != *blockhash { if last_blockhash != *blockhash {
Ok(last_blockhash) Ok((last_blockhash, fee_calculator))
} else { } else {
Err(TransportError::IoError(io::Error::new( Err(TransportError::IoError(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,

View File

@ -7,6 +7,7 @@
//! Asynchronous implementations are expected to create transactions, sign them, and send //! Asynchronous implementations are expected to create transactions, sign them, and send
//! them but without waiting to see if the server accepted it. //! them but without waiting to see if the server accepted it.
use crate::fee_calculator::FeeCalculator;
use crate::hash::Hash; use crate::hash::Hash;
use crate::instruction::Instruction; use crate::instruction::Instruction;
use crate::message::Message; use crate::message::Message;
@ -46,7 +47,7 @@ pub trait SyncClient {
) -> Result<Option<transaction::Result<()>>>; ) -> Result<Option<transaction::Result<()>>>;
/// Get recent blockhash /// Get recent blockhash
fn get_recent_blockhash(&self) -> Result<Hash>; fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)>;
/// Get transaction count /// Get transaction count
fn get_transaction_count(&self) -> Result<u64>; fn get_transaction_count(&self) -> Result<u64>;
@ -61,7 +62,7 @@ pub trait SyncClient {
/// Poll to confirm a transaction. /// Poll to confirm a transaction.
fn poll_for_signature(&self, signature: &Signature) -> Result<()>; fn poll_for_signature(&self, signature: &Signature) -> Result<()>;
fn get_new_blockhash(&self, blockhash: &Hash) -> Result<Hash>; fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)>;
} }
pub trait AsyncClient { pub trait AsyncClient {

View File

@ -1,6 +1,7 @@
use crate::message::Message; use crate::message::Message;
#[derive(Serialize, Deserialize, Clone, Debug, Default)] #[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct FeeCalculator { pub struct FeeCalculator {
pub lamports_per_signature: u64, pub lamports_per_signature: u64,
} }

View File

@ -388,7 +388,7 @@ fn process_create_vote_account(
commission, commission,
lamports, 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 mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?; let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
Ok(signature_str.to_string()) Ok(signature_str.to_string())
@ -399,7 +399,7 @@ fn process_authorize_voter(
config: &WalletConfig, config: &WalletConfig,
authorized_voter_id: &Pubkey, authorized_voter_id: &Pubkey,
) -> ProcessResult { ) -> 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( let ixs = vec![vote_instruction::authorize_voter(
&config.keypair.pubkey(), &config.keypair.pubkey(),
authorized_voter_id, authorized_voter_id,
@ -457,7 +457,7 @@ fn process_create_stake_account(
staking_account_id: &Pubkey, staking_account_id: &Pubkey,
lamports: u64, lamports: u64,
) -> ProcessResult { ) -> 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( let ixs = vec![stake_instruction::create_account(
&config.keypair.pubkey(), &config.keypair.pubkey(),
staking_account_id, staking_account_id,
@ -474,7 +474,7 @@ fn process_delegate_stake(
staking_account_keypair: &Keypair, staking_account_keypair: &Keypair,
voting_account_id: &Pubkey, voting_account_id: &Pubkey,
) -> ProcessResult { ) -> 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( let ixs = vec![stake_instruction::delegate_stake(
&config.keypair.pubkey(), &config.keypair.pubkey(),
&staking_account_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 program_id = Keypair::new();
let mut file = File::open(program_location).map_err(|err| { let mut file = File::open(program_location).map_err(|err| {
WalletError::DynamicProgramError( WalletError::DynamicProgramError(
@ -600,7 +600,7 @@ fn process_pay(
witnesses: &Option<Vec<Pubkey>>, witnesses: &Option<Vec<Pubkey>>,
cancelable: Option<Pubkey>, cancelable: Option<Pubkey>,
) -> ProcessResult { ) -> ProcessResult {
let blockhash = rpc_client.get_recent_blockhash()?; let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
if timestamp == None && *witnesses == None { if timestamp == None && *witnesses == None {
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0); let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0);
@ -636,7 +636,7 @@ fn process_pay(
}) })
.to_string()) .to_string())
} else if timestamp == None { } 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 { let witness = if let Some(ref witness_vec) = *witnesses {
witness_vec[0] witness_vec[0]
@ -672,7 +672,7 @@ fn process_pay(
} }
fn process_cancel(rpc_client: &RpcClient, config: &WalletConfig, pubkey: &Pubkey) -> ProcessResult { 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( let ix = budget_instruction::apply_signature(
&config.keypair.pubkey(), &config.keypair.pubkey(),
pubkey, pubkey,
@ -703,7 +703,7 @@ fn process_time_elapsed(
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config.keypair.pubkey(), 1)?; 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 ix = budget_instruction::apply_timestamp(&config.keypair.pubkey(), pubkey, to, dt);
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash); 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)?; 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 ix = budget_instruction::apply_signature(&config.keypair.pubkey(), pubkey, to);
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash); let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); 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, to_pubkey: &Pubkey,
lamports: u64, lamports: u64,
) -> Result<(), Box<dyn error::Error>> { ) -> Result<(), Box<dyn error::Error>> {
let blockhash = rpc_client.get_recent_blockhash()?; let (blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
let keypair = { let keypair = {
let mut retries = 5; let mut retries = 5;
loop { loop {