Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mechanism to get blockhash queue length #10162

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
seed,
program_id,
} => process_create_address_with_seed(config, from_pubkey.as_ref(), &seed, &program_id),
CliCommand::Fees => process_fees(&rpc_client),
CliCommand::Fees => process_fees(&rpc_client, config),
CliCommand::GetBlockTime { slot } => process_get_block_time(&rpc_client, config, *slot),
CliCommand::GetGenesisHash => process_get_genesis_hash(&rpc_client),
CliCommand::GetEpochInfo { commitment_config } => {
Expand Down
35 changes: 34 additions & 1 deletion cli/src/cli_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use inflector::cases::titlecase::to_title_case;
use serde::Serialize;
use serde_json::{Map, Value};
use solana_client::rpc_response::{
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
RpcAccountBalance, RpcBlockhashLifespan, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
};
use solana_sdk::{
clock::{self, Epoch, Slot, UnixTimestamp},
Expand Down Expand Up @@ -900,6 +900,7 @@ impl fmt::Display for CliSignOnlyData {
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliSignature {
pub signature: String,
}
Expand All @@ -913,6 +914,7 @@ impl fmt::Display for CliSignature {
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliAccountBalances {
pub accounts: Vec<RpcAccountBalance>,
}
Expand All @@ -937,6 +939,7 @@ impl fmt::Display for CliAccountBalances {
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliSupply {
pub total: u64,
pub circulating: u64,
Expand Down Expand Up @@ -981,3 +984,33 @@ impl fmt::Display for CliSupply {
Ok(())
}
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFees {
pub slot: Slot,
pub blockhash: String,
pub lamports_per_signature: u64,
pub blockhash_lifespan: RpcBlockhashLifespan,
}

impl fmt::Display for CliFees {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
writeln_name_value(
f,
"Lamports per signature:",
&self.lamports_per_signature.to_string(),
)?;
writeln_name_value(f, "Slot:", &self.slot.to_string())?;
writeln_name_value(
f,
"Blockhash lifespan:",
&format!(
"{} slots (epoch {})",
&self.blockhash_lifespan.blockhash_lifespan, &self.blockhash_lifespan.epoch
),
)?;
Ok(())
}
}
18 changes: 11 additions & 7 deletions cli/src/cluster_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,13 +599,17 @@ pub fn process_cluster_version(rpc_client: &RpcClient) -> ProcessResult {
Ok(remote_version.solana_core)
}

pub fn process_fees(rpc_client: &RpcClient) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;

Ok(format!(
"blockhash: {}\nlamports per signature: {}",
recent_blockhash, fee_calculator.lamports_per_signature
))
pub fn process_fees(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let result = rpc_client.get_recent_blockhash_with_commitment(CommitmentConfig::default())?;
let (recent_blockhash, fee_calculator) = result.value;
let blockhash_lifespan = rpc_client.get_blockhash_lifespan()?;
let fees = CliFees {
slot: result.context.slot,
blockhash: recent_blockhash.to_string(),
lamports_per_signature: fee_calculator.lamports_per_signature,
blockhash_lifespan: blockhash_lifespan.value,
};
Ok(config.output_format.formatted_string(&fees))
}

pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
Expand Down
8 changes: 8 additions & 0 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,14 @@ impl RpcClient {
})
}

pub fn get_blockhash_lifespan(&self) -> RpcResult<RpcBlockhashLifespan> {
self.send::<Response<RpcBlockhashLifespan>>(
RpcRequest::GetBlockhashLifespan,
Value::Null,
0,
)
}

pub fn get_new_blockhash(&self, blockhash: &Hash) -> ClientResult<(Hash, FeeCalculator)> {
let mut num_retries = 0;
let start = Instant::now();
Expand Down
2 changes: 2 additions & 0 deletions client/src/rpc_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum RpcRequest {
ValidatorExit,
GetAccountInfo,
GetBalance,
GetBlockhashLifespan,
GetBlockTime,
GetClusterNodes,
GetConfirmedBlock,
Expand Down Expand Up @@ -53,6 +54,7 @@ impl fmt::Display for RpcRequest {
RpcRequest::ValidatorExit => "validatorExit",
RpcRequest::GetAccountInfo => "getAccountInfo",
RpcRequest::GetBalance => "getBalance",
RpcRequest::GetBlockhashLifespan => "getBlockhashLifespan",
RpcRequest::GetBlockTime => "getBlockTime",
RpcRequest::GetClusterNodes => "getClusterNodes",
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
Expand Down
7 changes: 7 additions & 0 deletions client/src/rpc_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ pub struct RpcFeeRateGovernor {
pub fee_rate_governor: FeeRateGovernor,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcBlockhashLifespan {
pub epoch: Epoch,
pub blockhash_lifespan: usize,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcKeyedAccount {
Expand Down
49 changes: 49 additions & 0 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,19 @@ impl JsonRpcRequestProcessor {
)
}

fn get_blockhash_lifespan(&self) -> RpcResponse<RpcBlockhashLifespan> {
let bank = &*self.bank(None)?;
let epoch = bank.epoch();
let blockhash_lifespan = bank.get_blockhash_lifespan();
new_response(
bank,
RpcBlockhashLifespan {
epoch,
blockhash_lifespan,
},
)
}

pub fn confirm_transaction(
&self,
signature: Result<Signature>,
Expand Down Expand Up @@ -796,6 +809,9 @@ pub trait RpcSol {
#[rpc(meta, name = "getFeeRateGovernor")]
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor>;

#[rpc(meta, name = "getBlockhashLifespan")]
fn get_blockhash_lifespan(&self, meta: Self::Metadata) -> RpcResponse<RpcBlockhashLifespan>;

#[rpc(meta, name = "getSignatureStatuses")]
fn get_signature_statuses(
&self,
Expand Down Expand Up @@ -1141,6 +1157,14 @@ impl RpcSol for RpcSolImpl {
.get_fee_rate_governor()
}

fn get_blockhash_lifespan(&self, meta: Self::Metadata) -> RpcResponse<RpcBlockhashLifespan> {
debug!("get_blockhash_length rpc request received");
meta.request_processor
.read()
.unwrap()
.get_blockhash_lifespan()
}

fn get_signature_confirmation(
&self,
meta: Self::Metadata,
Expand Down Expand Up @@ -1561,6 +1585,7 @@ pub mod tests {
get_tmp_ledger_path,
};
use solana_sdk::{
clock::MAX_RECENT_BLOCKHASHES,
fee_calculator::DEFAULT_BURN_PERCENT,
hash::{hash, Hash},
instruction::InstructionError,
Expand Down Expand Up @@ -2584,6 +2609,30 @@ pub mod tests {
assert_eq!(expected, result);
}

#[test]
fn test_rpc_get_blockhash_lifespan() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);

let req = r#"{"jsonrpc":"2.0","id":1,"method":"getBlockhashLifespan"}"#;
let res = io.handle_request_sync(&req, meta);
let expected = json!({
"jsonrpc": "2.0",
"result": {
"context":{"slot":0},
"value":{
"epoch": 0,
"blockhashLifespan": MAX_RECENT_BLOCKHASHES,
}},
"id": 1
});
let expected: Response =
serde_json::from_value(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);
}

#[test]
fn test_rpc_fail_request_airdrop() {
let bob_pubkey = Pubkey::new_rand();
Expand Down
30 changes: 29 additions & 1 deletion docs/src/apps/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getAccountInfo](jsonrpc-api.md#getaccountinfo)
* [getBalance](jsonrpc-api.md#getbalance)
* [getBlockCommitment](jsonrpc-api.md#getblockcommitment)
* [getBlockhashLifespan](jsonrpc-api.md#getblockhashlifespan)
* [getBlockTime](jsonrpc-api.md#getblocktime)
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
Expand Down Expand Up @@ -213,6 +214,33 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
{"jsonrpc":"2.0","result":{"commitment":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,32],"totalStake": 42},"id":1}
```

### getBlockhashLifespan

Returns the blockhash lifespan for the current epoch. A particular blockhash
from slot M is valid until slot N, where N = `M + blockhashLifespan`.

#### Parameters:

None

#### Results:

The result will be an RpcResponse JSON object with `value` equal to and object
with the following fields:

* `epoch: <u64>` - epoch
* `blockhashLifespan: <usize>` - blockhash lifespan, in slots

#### Example:

```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getBlockhashLifespan"}' http://localhost:8899

// Result
{"jsonrpc":"2.0","result":{"context":{"slot":221},"value":{"epoch":0,"blockhashLifespan":300}},"id":1}
```

### getBlockTime

Returns the estimated production time of a block.
Expand Down Expand Up @@ -390,7 +418,7 @@ The signatures will be ordered based on the Slot in which they were confirmed in
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", 0, 100]}' localhost:8899

// Result
{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"]},"id":1}
{"jsonrpc":"2.0","result":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"],"id":1}
```

### getConfirmedTransaction
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,10 @@ impl Bank {
&self.fee_rate_governor
}

pub fn get_blockhash_lifespan(&self) -> usize {
self.blockhash_queue.read().unwrap().len()
}

pub fn confirmed_last_blockhash(&self) -> (Hash, FeeCalculator) {
const NUM_BLOCKHASH_CONFIRMATIONS: usize = 3;

Expand Down
4 changes: 4 additions & 0 deletions runtime/src/blockhash_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ impl BlockhashQueue {
.iter()
.map(|(k, v)| recent_blockhashes::IterItem(v.hash_height, k, &v.fee_calculator))
}

pub fn len(&self) -> usize {
self.max_age
}
}
#[cfg(test)]
mod tests {
Expand Down