automerge
This commit is contained in:
@ -40,6 +40,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
|
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
|
||||||
* [getVersion](jsonrpc-api.md#getversion)
|
* [getVersion](jsonrpc-api.md#getversion)
|
||||||
* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
|
* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
|
||||||
|
* [minimumLedgerSlot](jsonrpc-api.md#minimumledgerslot)
|
||||||
* [requestAirdrop](jsonrpc-api.md#requestairdrop)
|
* [requestAirdrop](jsonrpc-api.md#requestairdrop)
|
||||||
* [sendTransaction](jsonrpc-api.md#sendtransaction)
|
* [sendTransaction](jsonrpc-api.md#sendtransaction)
|
||||||
* [startSubscriptionChannel](jsonrpc-api.md#startsubscriptionchannel)
|
* [startSubscriptionChannel](jsonrpc-api.md#startsubscriptionchannel)
|
||||||
@ -585,7 +586,7 @@ Returns the current slot the node is processing
|
|||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlot"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlot"}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":"1234","id":1}
|
{"jsonrpc":"2.0","result":1234,"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getSlotLeader
|
### getSlotLeader
|
||||||
@ -628,7 +629,7 @@ Returns the current storage segment size in terms of slots
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotsPerSegment"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotsPerSegment"}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":"1024","id":1}
|
{"jsonrpc":"2.0","result":1024,"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getStorageTurn
|
### getStorageTurn
|
||||||
@ -772,6 +773,29 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
|||||||
{"jsonrpc":"2.0","result":{"current":[{"commission":0,"epochVoteAccount":true,"nodePubkey":"B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD","lastVote":147,"activatedStake":42,"votePubkey":"3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"}],"delinquent":[{"commission":127,"epochVoteAccount":false,"nodePubkey":"6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f","lastVote":0,"activatedStake":0,"votePubkey":"CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm"}]},"id":1}
|
{"jsonrpc":"2.0","result":{"current":[{"commission":0,"epochVoteAccount":true,"nodePubkey":"B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD","lastVote":147,"activatedStake":42,"votePubkey":"3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"}],"delinquent":[{"commission":127,"epochVoteAccount":false,"nodePubkey":"6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f","lastVote":0,"activatedStake":0,"votePubkey":"CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm"}]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### minimumLedgerSlot
|
||||||
|
|
||||||
|
Returns the lowest slot that the node has information about in its ledger. This
|
||||||
|
value may increase over time if the node is configured to purge older ledger data
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
#### Results:
|
||||||
|
|
||||||
|
* `u64` - Minimum ledger slot
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"minimumLedgerSlot"}' http://localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":1234,"id":1}
|
||||||
|
```
|
||||||
|
|
||||||
### requestAirdrop
|
### requestAirdrop
|
||||||
|
|
||||||
Requests an airdrop of lamports to a Pubkey
|
Requests an airdrop of lamports to a Pubkey
|
||||||
|
@ -434,19 +434,39 @@ pub fn process_show_block_production(
|
|||||||
return Err(format!("Epoch {} is in the future", epoch).into());
|
return Err(format!("Epoch {} is in the future", epoch).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let minimum_ledger_slot = rpc_client.minimum_ledger_slot()?;
|
||||||
|
|
||||||
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
|
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
|
||||||
let end_slot = std::cmp::min(
|
let end_slot = std::cmp::min(
|
||||||
epoch_info.absolute_slot,
|
epoch_info.absolute_slot,
|
||||||
epoch_schedule.get_last_slot_in_epoch(epoch),
|
epoch_schedule.get_last_slot_in_epoch(epoch),
|
||||||
);
|
);
|
||||||
|
|
||||||
let start_slot = if let Some(slot_limit) = slot_limit {
|
let mut start_slot = if let Some(slot_limit) = slot_limit {
|
||||||
std::cmp::max(end_slot.saturating_sub(slot_limit), first_slot_in_epoch)
|
std::cmp::max(end_slot.saturating_sub(slot_limit), first_slot_in_epoch)
|
||||||
} else {
|
} else {
|
||||||
first_slot_in_epoch
|
first_slot_in_epoch
|
||||||
};
|
};
|
||||||
let start_slot_index = (start_slot - first_slot_in_epoch) as usize;
|
|
||||||
let end_slot_index = (end_slot - first_slot_in_epoch) as usize;
|
if minimum_ledger_slot > end_slot {
|
||||||
|
return Err(format!(
|
||||||
|
"Ledger data not available for slots {} to {} (minimum ledger slot is {})",
|
||||||
|
start_slot, end_slot, minimum_ledger_slot
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if minimum_ledger_slot > start_slot {
|
||||||
|
println!(
|
||||||
|
"\n{}",
|
||||||
|
style(format!(
|
||||||
|
"Note: Requested start slot was {} but minimum ledger slot is {}",
|
||||||
|
start_slot, minimum_ledger_slot
|
||||||
|
))
|
||||||
|
.italic(),
|
||||||
|
);
|
||||||
|
start_slot = minimum_ledger_slot;
|
||||||
|
}
|
||||||
|
|
||||||
let progress_bar = new_spinner_progress_bar();
|
let progress_bar = new_spinner_progress_bar();
|
||||||
progress_bar.set_message(&format!(
|
progress_bar.set_message(&format!(
|
||||||
@ -455,6 +475,8 @@ pub fn process_show_block_production(
|
|||||||
));
|
));
|
||||||
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
|
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
|
||||||
|
|
||||||
|
let start_slot_index = (start_slot - first_slot_in_epoch) as usize;
|
||||||
|
let end_slot_index = (end_slot - first_slot_in_epoch) as usize;
|
||||||
let total_slots = end_slot_index - start_slot_index + 1;
|
let total_slots = end_slot_index - start_slot_index + 1;
|
||||||
let total_blocks = confirmed_blocks.len();
|
let total_blocks = confirmed_blocks.len();
|
||||||
assert!(total_blocks <= total_slots);
|
assert!(total_blocks <= total_slots);
|
||||||
|
@ -386,6 +386,25 @@ impl RpcClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn minimum_ledger_slot(&self) -> io::Result<Slot> {
|
||||||
|
let response = self
|
||||||
|
.client
|
||||||
|
.send(&RpcRequest::MinimumLedgerSlot, Value::Null, 0)
|
||||||
|
.map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("MinimumLedgerSlot request failure: {:?}", err),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
serde_json::from_value(response).map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("MinimumLedgerSlot parse failure: {}", err),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_and_confirm_transaction<T: KeypairUtil>(
|
pub fn send_and_confirm_transaction<T: KeypairUtil>(
|
||||||
&self,
|
&self,
|
||||||
transaction: &mut Transaction,
|
transaction: &mut Transaction,
|
||||||
|
@ -35,6 +35,7 @@ pub enum RpcRequest {
|
|||||||
SendTransaction,
|
SendTransaction,
|
||||||
SignVote,
|
SignVote,
|
||||||
GetMinimumBalanceForRentExemption,
|
GetMinimumBalanceForRentExemption,
|
||||||
|
MinimumLedgerSlot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcRequest {
|
impl RpcRequest {
|
||||||
@ -75,6 +76,7 @@ impl RpcRequest {
|
|||||||
RpcRequest::SendTransaction => "sendTransaction",
|
RpcRequest::SendTransaction => "sendTransaction",
|
||||||
RpcRequest::SignVote => "signVote",
|
RpcRequest::SignVote => "signVote",
|
||||||
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
|
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
|
||||||
|
RpcRequest::MinimumLedgerSlot => "minimumLedgerSlot",
|
||||||
};
|
};
|
||||||
json!({
|
json!({
|
||||||
"jsonrpc": jsonrpc,
|
"jsonrpc": jsonrpc,
|
||||||
|
@ -229,6 +229,19 @@ impl JsonRpcRequestProcessor {
|
|||||||
Ok(self.bank(commitment).collector_id().to_string())
|
Ok(self.bank(commitment).collector_id().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn minimum_ledger_slot(&self) -> Result<Slot> {
|
||||||
|
match self.blockstore.slot_meta_iterator(0) {
|
||||||
|
Ok(mut metas) => match metas.next() {
|
||||||
|
Some((slot, _meta)) => Ok(slot),
|
||||||
|
None => Err(Error::invalid_request()),
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
warn!("slot_meta_iterator failed: {:?}", err);
|
||||||
|
Err(Error::invalid_request())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_transaction_count(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_transaction_count(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
Ok(self.bank(commitment).transaction_count() as u64)
|
Ok(self.bank(commitment).transaction_count() as u64)
|
||||||
}
|
}
|
||||||
@ -530,6 +543,9 @@ pub trait RpcSol {
|
|||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<String>;
|
) -> Result<String>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "minimumLedgerSlot")]
|
||||||
|
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getVoteAccounts")]
|
#[rpc(meta, name = "getVoteAccounts")]
|
||||||
fn get_vote_accounts(
|
fn get_vote_accounts(
|
||||||
&self,
|
&self,
|
||||||
@ -990,6 +1006,10 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.get_slot_leader(commitment)
|
.get_slot_leader(commitment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot> {
|
||||||
|
meta.request_processor.read().unwrap().minimum_ledger_slot()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_vote_accounts(
|
fn get_vote_accounts(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
@ -1379,6 +1399,21 @@ pub mod tests {
|
|||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_minimum_ledger_slot() {
|
||||||
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
|
||||||
|
|
||||||
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"minimumLedgerSlot"}}"#);
|
||||||
|
let res = io.handle_request_sync(&req, meta);
|
||||||
|
let expected = r#"{"jsonrpc":"2.0","result":0,"id":1}"#;
|
||||||
|
let expected: Response =
|
||||||
|
serde_json::from_str(&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]
|
#[test]
|
||||||
fn test_rpc_get_total_supply() {
|
fn test_rpc_get_total_supply() {
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
Reference in New Issue
Block a user