@ -2,7 +2,7 @@ use crate::{
|
|||||||
client_error::Result,
|
client_error::Result,
|
||||||
generic_rpc_client_request::GenericRpcClientRequest,
|
generic_rpc_client_request::GenericRpcClientRequest,
|
||||||
rpc_request::RpcRequest,
|
rpc_request::RpcRequest,
|
||||||
rpc_response::{Response, RpcResponseContext},
|
rpc_response::{Response, RpcResponseContext, RpcTransactionStatus},
|
||||||
};
|
};
|
||||||
use serde_json::{Number, Value};
|
use serde_json::{Number, Value};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -87,19 +87,22 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
|
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
|
||||||
})?,
|
})?,
|
||||||
RpcRequest::GetSignatureStatus => {
|
RpcRequest::GetSignatureStatus => {
|
||||||
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
|
let status: transaction::Result<()> = if self.url == "account_in_use" {
|
||||||
Some(Err(TransactionError::AccountInUse))
|
Err(TransactionError::AccountInUse)
|
||||||
} else if self.url == "instruction_error" {
|
} else if self.url == "instruction_error" {
|
||||||
Some(Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::UninitializedAccount,
|
InstructionError::UninitializedAccount,
|
||||||
)))
|
))
|
||||||
} else if self.url == "sig_not_found" {
|
} else {
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
let status = if self.url == "sig_not_found" {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Ok(()))
|
Some(RpcTransactionStatus { status, slot: 1 })
|
||||||
};
|
};
|
||||||
serde_json::to_value(response).unwrap()
|
serde_json::to_value(vec![status])?
|
||||||
}
|
}
|
||||||
RpcRequest::GetTransactionCount => Value::Number(Number::from(1234)),
|
RpcRequest::GetTransactionCount => Value::Number(Number::from(1234)),
|
||||||
RpcRequest::GetSlot => Value::Number(Number::from(0)),
|
RpcRequest::GetSlot => Value::Number(Number::from(0)),
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
rpc_response::{
|
rpc_response::{
|
||||||
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
||||||
RpcEpochInfo, RpcFeeCalculator, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount,
|
RpcEpochInfo, RpcFeeCalculator, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount,
|
||||||
RpcLeaderSchedule, RpcResult, RpcVersionInfo, RpcVoteAccountStatus,
|
RpcLeaderSchedule, RpcResult, RpcTransactionStatus, RpcVersionInfo, RpcVoteAccountStatus,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
@ -120,12 +120,12 @@ impl RpcClient {
|
|||||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||||
let signature_status = self.client.send(
|
let signature_status = self.client.send(
|
||||||
&RpcRequest::GetSignatureStatus,
|
&RpcRequest::GetSignatureStatus,
|
||||||
json!([signature.to_string(), commitment_config]),
|
json!([[signature.to_string()], commitment_config]),
|
||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
let result: Option<transaction::Result<()>> =
|
let result: Vec<Option<RpcTransactionStatus>> =
|
||||||
serde_json::from_value(signature_status).unwrap();
|
serde_json::from_value(signature_status).unwrap();
|
||||||
Ok(result)
|
Ok(result[0].clone().map(|status_meta| status_meta.status))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_slot(&self) -> ClientResult<Slot> {
|
pub fn get_slot(&self) -> ClientResult<Slot> {
|
||||||
|
@ -95,7 +95,7 @@ impl RpcRequest {
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum RpcError {
|
pub enum RpcError {
|
||||||
#[error("rpc reques error: {0}")]
|
#[error("rpc request error: {0}")]
|
||||||
RpcRequestError(String),
|
RpcRequestError(String),
|
||||||
#[error("parse error: expected {0}")]
|
#[error("parse error: expected {0}")]
|
||||||
ParseError(String), /* "expected" */
|
ParseError(String), /* "expected" */
|
||||||
|
@ -52,7 +52,7 @@ pub struct RpcConfirmedBlock {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTransactionWithStatusMeta {
|
pub struct RpcTransactionWithStatusMeta {
|
||||||
pub transaction: RpcEncodedTransaction,
|
pub transaction: RpcEncodedTransaction,
|
||||||
pub meta: Option<RpcTransactionStatus>,
|
pub meta: Option<RpcTransactionStatusMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
@ -136,13 +136,20 @@ pub struct RpcCompiledInstruction {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTransactionStatus {
|
pub struct RpcTransactionStatusMeta {
|
||||||
pub status: Result<()>,
|
pub status: Result<()>,
|
||||||
pub fee: u64,
|
pub fee: u64,
|
||||||
pub pre_balances: Vec<u64>,
|
pub pre_balances: Vec<u64>,
|
||||||
pub post_balances: Vec<u64>,
|
pub post_balances: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcTransactionStatus {
|
||||||
|
pub slot: Slot,
|
||||||
|
pub status: Result<()>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcBlockhashFeeCalculator {
|
pub struct RpcBlockhashFeeCalculator {
|
||||||
|
145
core/src/rpc.rs
145
core/src/rpc.rs
@ -7,18 +7,12 @@ use crate::{
|
|||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use jsonrpc_core::{Error, Metadata, Result};
|
use jsonrpc_core::{Error, Metadata, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use solana_client::rpc_response::{
|
use solana_client::rpc_response::*;
|
||||||
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
|
|
||||||
RpcContactInfo, RpcEpochInfo, RpcFeeCalculator, RpcFeeRateGovernor, RpcIdentity,
|
|
||||||
RpcKeyedAccount, RpcLeaderSchedule, RpcResponseContext, RpcSignatureConfirmation,
|
|
||||||
RpcStorageTurn, RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo,
|
|
||||||
RpcVoteAccountStatus,
|
|
||||||
};
|
|
||||||
use solana_faucet::faucet::request_airdrop_transaction;
|
use solana_faucet::faucet::request_airdrop_transaction;
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator,
|
bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator,
|
||||||
};
|
};
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::{bank::Bank, status_cache::SignatureConfirmationStatus};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, UnixTimestamp},
|
clock::{Slot, UnixTimestamp},
|
||||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||||
@ -28,7 +22,7 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
timing::slot_duration_from_slots_per_year,
|
timing::slot_duration_from_slots_per_year,
|
||||||
transaction::{self, Transaction},
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
||||||
use std::{
|
use std::{
|
||||||
@ -51,7 +45,7 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
|||||||
pub struct JsonRpcConfig {
|
pub struct JsonRpcConfig {
|
||||||
pub enable_validator_exit: bool,
|
pub enable_validator_exit: bool,
|
||||||
pub enable_set_log_filter: bool,
|
pub enable_set_log_filter: bool,
|
||||||
pub enable_get_confirmed_block: bool,
|
pub enable_rpc_transaction_history: bool,
|
||||||
pub identity_pubkey: Pubkey,
|
pub identity_pubkey: Pubkey,
|
||||||
pub faucet_addr: Option<SocketAddr>,
|
pub faucet_addr: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
@ -202,7 +196,9 @@ impl JsonRpcRequestProcessor {
|
|||||||
Ok(sig) => {
|
Ok(sig) => {
|
||||||
let status = bank.get_signature_confirmation_status(&sig);
|
let status = bank.get_signature_confirmation_status(&sig);
|
||||||
match status {
|
match status {
|
||||||
Some((_, result)) => new_response(bank, result.is_ok()),
|
Some(SignatureConfirmationStatus { status, .. }) => {
|
||||||
|
new_response(bank, status.is_ok())
|
||||||
|
}
|
||||||
None => new_response(bank, false),
|
None => new_response(bank, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,10 +222,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
) -> Option<RpcSignatureConfirmation> {
|
) -> Option<RpcSignatureConfirmation> {
|
||||||
self.bank(commitment)
|
self.bank(commitment)
|
||||||
.get_signature_confirmation_status(&signature)
|
.get_signature_confirmation_status(&signature)
|
||||||
.map(|(confirmations, status)| RpcSignatureConfirmation {
|
.map(
|
||||||
confirmations,
|
|SignatureConfirmationStatus {
|
||||||
status,
|
confirmations,
|
||||||
})
|
status,
|
||||||
|
..
|
||||||
|
}| RpcSignatureConfirmation {
|
||||||
|
confirmations,
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@ -365,7 +367,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<RpcTransactionEncoding>,
|
encoding: Option<RpcTransactionEncoding>,
|
||||||
) -> Result<Option<RpcConfirmedBlock>> {
|
) -> Result<Option<RpcConfirmedBlock>> {
|
||||||
if self.config.enable_get_confirmed_block {
|
if self.config.enable_rpc_transaction_history {
|
||||||
Ok(self.blockstore.get_confirmed_block(slot, encoding).ok())
|
Ok(self.blockstore.get_confirmed_block(slot, encoding).ok())
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -413,6 +415,27 @@ impl JsonRpcRequestProcessor {
|
|||||||
.ok()
|
.ok()
|
||||||
.unwrap_or(None))
|
.unwrap_or(None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_signature_status(
|
||||||
|
&self,
|
||||||
|
signatures: Vec<Signature>,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Vec<Option<RpcTransactionStatus>>> {
|
||||||
|
let mut statuses: Vec<Option<RpcTransactionStatus>> = vec![];
|
||||||
|
|
||||||
|
let bank = self.bank(commitment);
|
||||||
|
|
||||||
|
for signature in signatures {
|
||||||
|
let status = bank.get_signature_confirmation_status(&signature).map(
|
||||||
|
|SignatureConfirmationStatus { slot, status, .. }| RpcTransactionStatus {
|
||||||
|
slot,
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
statuses.push(status);
|
||||||
|
}
|
||||||
|
Ok(statuses)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
||||||
@ -539,9 +562,9 @@ pub trait RpcSol {
|
|||||||
fn get_signature_status(
|
fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_strs: Vec<String>,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<transaction::Result<()>>>;
|
) -> Result<Vec<Option<RpcTransactionStatus>>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSlot")]
|
#[rpc(meta, name = "getSlot")]
|
||||||
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64>;
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64>;
|
||||||
@ -885,11 +908,17 @@ impl RpcSol for RpcSolImpl {
|
|||||||
fn get_signature_status(
|
fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_strs: Vec<String>,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<transaction::Result<()>>> {
|
) -> Result<Vec<Option<RpcTransactionStatus>>> {
|
||||||
self.get_signature_confirmation(meta, signature_str, commitment)
|
let mut signatures: Vec<Signature> = vec![];
|
||||||
.map(|res| res.map(|x| x.status))
|
for signature_str in signature_strs {
|
||||||
|
signatures.push(verify_signature(&signature_str)?);
|
||||||
|
}
|
||||||
|
meta.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_signature_status(signatures, commitment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@ -1200,7 +1229,7 @@ pub mod tests {
|
|||||||
rpc_port,
|
rpc_port,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::TransactionError,
|
transaction::{self, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
@ -1329,7 +1358,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
||||||
JsonRpcConfig {
|
JsonRpcConfig {
|
||||||
enable_get_confirmed_block: true,
|
enable_rpc_transaction_history: true,
|
||||||
identity_pubkey: *pubkey,
|
identity_pubkey: *pubkey,
|
||||||
..JsonRpcConfig::default()
|
..JsonRpcConfig::default()
|
||||||
},
|
},
|
||||||
@ -1773,66 +1802,50 @@ pub mod tests {
|
|||||||
meta,
|
meta,
|
||||||
blockhash,
|
blockhash,
|
||||||
alice,
|
alice,
|
||||||
|
confirmed_block_signatures,
|
||||||
..
|
..
|
||||||
} = start_rpc_handler_with_tx(&bob_pubkey);
|
} = start_rpc_handler_with_tx(&bob_pubkey);
|
||||||
|
|
||||||
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
||||||
tx.signatures[0]
|
confirmed_block_signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
let expected_res: transaction::Result<()> = Ok(());
|
||||||
let expected = json!({
|
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
||||||
"jsonrpc": "2.0",
|
let result: Vec<Option<RpcTransactionStatus>> =
|
||||||
"result": expected_res,
|
serde_json::from_value(json["result"].clone())
|
||||||
"id": 1
|
.expect("actual response deserialization");
|
||||||
});
|
assert_eq!(expected_res, result[0].as_ref().unwrap().status);
|
||||||
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 getSignatureStatus request on unprocessed tx
|
// Test getSignatureStatus request on unprocessed tx
|
||||||
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
||||||
tx.signatures[0]
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected_res: Option<String> = None;
|
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
||||||
let expected = json!({
|
let result: Vec<Option<RpcTransactionStatus>> =
|
||||||
"jsonrpc": "2.0",
|
serde_json::from_value(json["result"].clone())
|
||||||
"result": expected_res,
|
.expect("actual response deserialization");
|
||||||
"id": 1
|
assert!(result[0].is_none());
|
||||||
});
|
|
||||||
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 getSignatureStatus request on a TransactionError
|
// Test getSignatureStatus request on a TransactionError
|
||||||
let tx = system_transaction::transfer(&alice, &bob_pubkey, std::u64::MAX, blockhash);
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
||||||
tx.signatures[0]
|
confirmed_block_signatures[1]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Err(
|
let expected_res: transaction::Result<()> = Err(TransactionError::InstructionError(
|
||||||
TransactionError::InstructionError(0, InstructionError::CustomError(1)),
|
0,
|
||||||
|
InstructionError::CustomError(1),
|
||||||
));
|
));
|
||||||
let expected = json!({
|
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
||||||
"jsonrpc": "2.0",
|
let result: Vec<Option<RpcTransactionStatus>> =
|
||||||
"result": expected_res,
|
serde_json::from_value(json["result"].clone())
|
||||||
"id": 1
|
.expect("actual response deserialization");
|
||||||
});
|
assert_eq!(expected_res, result[0].as_ref().unwrap().status);
|
||||||
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]
|
#[test]
|
||||||
|
@ -11,7 +11,9 @@ use rand::{Rng, SeedableRng};
|
|||||||
use rand_chacha::ChaChaRng;
|
use rand_chacha::ChaChaRng;
|
||||||
use solana_chacha_cuda::chacha_cuda::chacha_cbc_encrypt_file_many_keys;
|
use solana_chacha_cuda::chacha_cuda::chacha_cbc_encrypt_file_many_keys;
|
||||||
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
||||||
use solana_runtime::{bank::Bank, storage_utils::archiver_accounts};
|
use solana_runtime::{
|
||||||
|
bank::Bank, status_cache::SignatureConfirmationStatus, storage_utils::archiver_accounts,
|
||||||
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
@ -343,8 +345,13 @@ impl StorageStage {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.working_bank()
|
.working_bank()
|
||||||
.get_signature_confirmation_status(signature);
|
.get_signature_confirmation_status(signature);
|
||||||
if let Some((confirmations, res)) = response {
|
if let Some(SignatureConfirmationStatus {
|
||||||
if res.is_ok() {
|
confirmations,
|
||||||
|
status,
|
||||||
|
..
|
||||||
|
}) = response
|
||||||
|
{
|
||||||
|
if status.is_ok() {
|
||||||
if confirmed_blocks != confirmations {
|
if confirmed_blocks != confirmations {
|
||||||
now = Instant::now();
|
now = Instant::now();
|
||||||
confirmed_blocks = confirmations;
|
confirmed_blocks = confirmations;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crossbeam_channel::{Receiver, RecvTimeoutError};
|
use crossbeam_channel::{Receiver, RecvTimeoutError};
|
||||||
use solana_client::rpc_response::RpcTransactionStatus;
|
use solana_client::rpc_response::RpcTransactionStatusMeta;
|
||||||
use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch};
|
use solana_ledger::{blockstore::Blockstore, blockstore_processor::TransactionStatusBatch};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::{Bank, HashAgeKind},
|
bank::{Bank, HashAgeKind},
|
||||||
@ -73,7 +73,7 @@ impl TransactionStatusService {
|
|||||||
blockstore
|
blockstore
|
||||||
.write_transaction_status(
|
.write_transaction_status(
|
||||||
(slot, transaction.signatures[0]),
|
(slot, transaction.signatures[0]),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
|
@ -79,6 +79,7 @@ pub struct ValidatorConfig {
|
|||||||
pub halt_on_trusted_validators_accounts_hash_mismatch: bool,
|
pub halt_on_trusted_validators_accounts_hash_mismatch: bool,
|
||||||
pub accounts_hash_fault_injection_slots: u64, // 0 = no fault injection
|
pub accounts_hash_fault_injection_slots: u64, // 0 = no fault injection
|
||||||
pub frozen_accounts: Vec<Pubkey>,
|
pub frozen_accounts: Vec<Pubkey>,
|
||||||
|
pub no_rocksdb_compaction: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ValidatorConfig {
|
impl Default for ValidatorConfig {
|
||||||
@ -105,6 +106,7 @@ impl Default for ValidatorConfig {
|
|||||||
halt_on_trusted_validators_accounts_hash_mismatch: false,
|
halt_on_trusted_validators_accounts_hash_mismatch: false,
|
||||||
accounts_hash_fault_injection_slots: 0,
|
accounts_hash_fault_injection_slots: 0,
|
||||||
frozen_accounts: vec![],
|
frozen_accounts: vec![],
|
||||||
|
no_rocksdb_compaction: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,7 +272,7 @@ impl Validator {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let (transaction_status_sender, transaction_status_service) =
|
let (transaction_status_sender, transaction_status_service) =
|
||||||
if rpc_service.is_some() && config.rpc_config.enable_get_confirmed_block {
|
if rpc_service.is_some() && config.rpc_config.enable_rpc_transaction_history {
|
||||||
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
||||||
(
|
(
|
||||||
Some(transaction_status_sender),
|
Some(transaction_status_sender),
|
||||||
@ -285,7 +287,7 @@ impl Validator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (rewards_recorder_sender, rewards_recorder_service) =
|
let (rewards_recorder_sender, rewards_recorder_service) =
|
||||||
if rpc_service.is_some() && config.rpc_config.enable_get_confirmed_block {
|
if rpc_service.is_some() && config.rpc_config.enable_rpc_transaction_history {
|
||||||
let (rewards_recorder_sender, rewards_receiver) = unbounded();
|
let (rewards_recorder_sender, rewards_receiver) = unbounded();
|
||||||
(
|
(
|
||||||
Some(rewards_recorder_sender),
|
Some(rewards_recorder_sender),
|
||||||
@ -589,8 +591,9 @@ fn new_banks_from_blockstore(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (blockstore, ledger_signal_receiver, completed_slots_receiver) =
|
let (mut blockstore, ledger_signal_receiver, completed_slots_receiver) =
|
||||||
Blockstore::open_with_signal(blockstore_path).expect("Failed to open ledger database");
|
Blockstore::open_with_signal(blockstore_path).expect("Failed to open ledger database");
|
||||||
|
blockstore.set_no_compaction(config.no_rocksdb_compaction);
|
||||||
|
|
||||||
let process_options = blockstore_processor::ProcessOptions {
|
let process_options = blockstore_processor::ProcessOptions {
|
||||||
poh_verify,
|
poh_verify,
|
||||||
|
@ -693,24 +693,30 @@ Returns the status of a given signature. This method is similar to [confirmTrans
|
|||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
* `<string>` - Signature of Transaction to confirm, as base-58 encoded string
|
* `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings
|
||||||
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
* `<object>` - (optional) Extended Rpc configuration, containing the following optional fields:
|
||||||
|
* `commitment: <string>` - [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
|
* `searchTransactionHistory: <bool>` - whether to search the ledger transaction status cache, which may be expensive
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
|
An array of:
|
||||||
|
|
||||||
* `<null>` - Unknown transaction
|
* `<null>` - Unknown transaction
|
||||||
* `<object>` - Transaction status:
|
* `<object>`
|
||||||
* `"Ok": <null>` - Transaction was successful
|
* `slot: <u64>` - The slot the transaction was processed
|
||||||
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
* `status: <object>` - Transaction status
|
||||||
|
* `"Ok": <null>` - Transaction was successful
|
||||||
|
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]]}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"Ok": null},"id":1}
|
{"jsonrpc":"2.0","result":[{"slot": 72, "status": {"Ok": null}}, null],"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getSlot
|
### getSlot
|
||||||
|
@ -33,7 +33,7 @@ want to perform an action on the stake account you create next.
|
|||||||
Now, create a stake account:
|
Now, create a stake account:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana create-stake-account --from=<KEYPAIR> stake-account.json <AMOUNT> --stake-authority=<KEYPAIR> --withdraw-authority=<KEYPAIR>
|
solana create-stake-account --from <KEYPAIR> stake-account.json <AMOUNT> --stake-authority <KEYPAIR> --withdraw-authority <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<AMOUNT>` tokens are transferred from the account at `<KEYPAIR>` to a new
|
`<AMOUNT>` tokens are transferred from the account at `<KEYPAIR>` to a new
|
||||||
@ -72,7 +72,7 @@ Stake and withdraw authorities can be set when creating an account via the
|
|||||||
run:
|
run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana stake-authorize <STAKE_ACCOUNT_ADDRESS> --stake-authority=<KEYPAIR> --new-stake-authority=<PUBKEY>
|
solana stake-authorize <STAKE_ACCOUNT_ADDRESS> --stake-authority <KEYPAIR> --new-stake-authority <PUBKEY>
|
||||||
```
|
```
|
||||||
|
|
||||||
This will use the existing stake authority `<KEYPAIR>` to authorize a new stake
|
This will use the existing stake authority `<KEYPAIR>` to authorize a new stake
|
||||||
@ -87,7 +87,7 @@ addresses can be cumbersome. Fortunately, you can derive stake addresses using
|
|||||||
the `--seed` option:
|
the `--seed` option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana create-stake-account --from=<KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed=<STRING> <AMOUNT> --stake-authority=<PUBKEY> --withdraw-authority=<PUBKEY>
|
solana create-stake-account --from <KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed <STRING> <AMOUNT> --stake-authority <PUBKEY> --withdraw-authority <PUBKEY>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STRING>` is an arbitrary string up to 32 bytes, but will typically be a
|
`<STRING>` is an arbitrary string up to 32 bytes, but will typically be a
|
||||||
@ -98,7 +98,7 @@ and seed string. To see what stake address the command will derive, use `solana
|
|||||||
create-address-with-seed`:
|
create-address-with-seed`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana create-address-with-seed --from=<PUBKEY> <SEED_STRING> STAKE
|
solana create-address-with-seed --from <PUBKEY> <SEED_STRING> STAKE
|
||||||
```
|
```
|
||||||
|
|
||||||
`<PUBKEY>` is the public key of the `<STAKE_ACCOUNT_KEYPAIR>` passed to
|
`<PUBKEY>` is the public key of the `<STAKE_ACCOUNT_KEYPAIR>` passed to
|
||||||
@ -122,7 +122,7 @@ is the vote account address. Choose a validator and use its vote account
|
|||||||
address in `solana delegate-stake`:
|
address in `solana delegate-stake`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana delegate-stake --stake-authority=<KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS>
|
solana delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<KEYPAIR>` authorizes the operation on the account with address
|
`<KEYPAIR>` authorizes the operation on the account with address
|
||||||
@ -155,7 +155,7 @@ Once delegated, you can undelegate stake with the `solana deactivate-stake`
|
|||||||
command:
|
command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana deactivate-stake --stake-authority=<KEYPAIR> <STAKE_ACCOUNT_ADDRESS>
|
solana deactivate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<KEYPAIR>` authorizes the operation on the account with address
|
`<KEYPAIR>` authorizes the operation on the account with address
|
||||||
@ -169,7 +169,7 @@ in the cool down period will fail.
|
|||||||
Transfer tokens out of a stake account with the `solana withdraw-stake` command:
|
Transfer tokens out of a stake account with the `solana withdraw-stake` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana withdraw-stake --withdraw-authority=<KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>
|
solana withdraw-stake --withdraw-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
||||||
@ -184,7 +184,7 @@ currently staked, cooling down, or locked up. To transfer tokens from an
|
|||||||
existing stake account to a new one, use the `solana split-stake` command:
|
existing stake account to a new one, use the `solana split-stake` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana split-stake --stake-authority=<KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT>
|
solana split-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
||||||
|
@ -84,7 +84,7 @@ pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana transfer --from=<SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> 5 --url http://devnet.solana.com
|
solana transfer --from <SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> 5 --url http://devnet.solana.com
|
||||||
```
|
```
|
||||||
|
|
||||||
where you replace `<SENDER_KEYPAIR>` with the path to a keypair in your wallet,
|
where you replace `<SENDER_KEYPAIR>` with the path to a keypair in your wallet,
|
||||||
@ -107,7 +107,7 @@ tokens to transfer. Once you have that collected, you can transfer tokens
|
|||||||
with the `solana transfer` command:
|
with the `solana transfer` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana transfer --from=<SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> <AMOUNT>
|
solana transfer --from <SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> <AMOUNT>
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm the updated balances with `solana balance`:
|
Confirm the updated balances with `solana balance`:
|
||||||
|
@ -181,7 +181,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||||||
.validator(is_pubkey_or_keypair)
|
.validator(is_pubkey_or_keypair)
|
||||||
.help(
|
.help(
|
||||||
"Path to file containing the pubkey authorized to manage the bootstrap \
|
"Path to file containing the pubkey authorized to manage the bootstrap \
|
||||||
validator's stake [default: --bootstrap-validator-pubkey]",
|
validator's stake [default: --bootstrap-validator IDENTITY_PUBKEY]",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -24,7 +24,7 @@ use rayon::{
|
|||||||
use rocksdb::DBRawIterator;
|
use rocksdb::DBRawIterator;
|
||||||
use solana_client::rpc_response::{
|
use solana_client::rpc_response::{
|
||||||
RpcConfirmedBlock, RpcEncodedTransaction, RpcRewards, RpcTransactionEncoding,
|
RpcConfirmedBlock, RpcEncodedTransaction, RpcRewards, RpcTransactionEncoding,
|
||||||
RpcTransactionStatus, RpcTransactionWithStatusMeta,
|
RpcTransactionStatusMeta, RpcTransactionWithStatusMeta,
|
||||||
};
|
};
|
||||||
use solana_measure::measure::Measure;
|
use solana_measure::measure::Measure;
|
||||||
use solana_metrics::{datapoint_debug, datapoint_error};
|
use solana_metrics::{datapoint_debug, datapoint_error};
|
||||||
@ -93,6 +93,7 @@ pub struct Blockstore {
|
|||||||
pub new_shreds_signals: Vec<SyncSender<bool>>,
|
pub new_shreds_signals: Vec<SyncSender<bool>>,
|
||||||
pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>,
|
pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>,
|
||||||
pub lowest_cleanup_slot: Arc<RwLock<u64>>,
|
pub lowest_cleanup_slot: Arc<RwLock<u64>>,
|
||||||
|
no_compaction: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IndexMetaWorkingSetEntry {
|
pub struct IndexMetaWorkingSetEntry {
|
||||||
@ -228,6 +229,7 @@ impl Blockstore {
|
|||||||
insert_shreds_lock: Arc::new(Mutex::new(())),
|
insert_shreds_lock: Arc::new(Mutex::new(())),
|
||||||
last_root,
|
last_root,
|
||||||
lowest_cleanup_slot: Arc::new(RwLock::new(0)),
|
lowest_cleanup_slot: Arc::new(RwLock::new(0)),
|
||||||
|
no_compaction: false,
|
||||||
};
|
};
|
||||||
Ok(blockstore)
|
Ok(blockstore)
|
||||||
}
|
}
|
||||||
@ -245,6 +247,10 @@ impl Blockstore {
|
|||||||
Ok((blockstore, signal_receiver, completed_slots_receiver))
|
Ok((blockstore, signal_receiver, completed_slots_receiver))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_no_compaction(&mut self, no_compaction: bool) {
|
||||||
|
self.no_compaction = no_compaction;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destroy(ledger_path: &Path) -> Result<()> {
|
pub fn destroy(ledger_path: &Path) -> Result<()> {
|
||||||
// Database::destroy() fails if the path doesn't exist
|
// Database::destroy() fails if the path doesn't exist
|
||||||
fs::create_dir_all(ledger_path)?;
|
fs::create_dir_all(ledger_path)?;
|
||||||
@ -276,12 +282,14 @@ impl Blockstore {
|
|||||||
while from_slot < batch_end {
|
while from_slot < batch_end {
|
||||||
match self.run_purge(from_slot, batch_end) {
|
match self.run_purge(from_slot, batch_end) {
|
||||||
Ok(end) => {
|
Ok(end) => {
|
||||||
if let Err(e) = self.compact_storage(from_slot, batch_end) {
|
if !self.no_compaction {
|
||||||
// This error is not fatal and indicates an internal error
|
if let Err(e) = self.compact_storage(from_slot, batch_end) {
|
||||||
error!(
|
// This error is not fatal and indicates an internal error
|
||||||
"Error: {:?}; Couldn't compact storage from {:?} to {:?}",
|
error!(
|
||||||
e, from_slot, batch_end
|
"Error: {:?}; Couldn't compact storage from {:?} to {:?}",
|
||||||
);
|
e, from_slot, batch_end
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if end {
|
if end {
|
||||||
@ -1467,7 +1475,7 @@ impl Blockstore {
|
|||||||
pub fn write_transaction_status(
|
pub fn write_transaction_status(
|
||||||
&self,
|
&self,
|
||||||
index: (Slot, Signature),
|
index: (Slot, Signature),
|
||||||
status: &RpcTransactionStatus,
|
status: &RpcTransactionStatusMeta,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.transaction_status_cf.put(index, status)
|
self.transaction_status_cf.put(index, status)
|
||||||
}
|
}
|
||||||
@ -4795,7 +4803,7 @@ pub mod tests {
|
|||||||
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatus>)> = entries
|
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatusMeta>)> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.filter(|entry| !entry.is_tick())
|
.filter(|entry| !entry.is_tick())
|
||||||
@ -4812,7 +4820,7 @@ pub mod tests {
|
|||||||
.transaction_status_cf
|
.transaction_status_cf
|
||||||
.put(
|
.put(
|
||||||
(slot, signature),
|
(slot, signature),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances: pre_balances.clone(),
|
pre_balances: pre_balances.clone(),
|
||||||
@ -4824,7 +4832,7 @@ pub mod tests {
|
|||||||
.transaction_status_cf
|
.transaction_status_cf
|
||||||
.put(
|
.put(
|
||||||
(slot + 1, signature),
|
(slot + 1, signature),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances: pre_balances.clone(),
|
pre_balances: pre_balances.clone(),
|
||||||
@ -4834,7 +4842,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
(
|
(
|
||||||
transaction,
|
transaction,
|
||||||
Some(RpcTransactionStatus {
|
Some(RpcTransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@ -5097,7 +5105,7 @@ pub mod tests {
|
|||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
.put(
|
.put(
|
||||||
(0, Signature::default()),
|
(0, Signature::default()),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status: solana_sdk::transaction::Result::<()>::Err(
|
status: solana_sdk::transaction::Result::<()>::Err(
|
||||||
TransactionError::AccountNotFound
|
TransactionError::AccountNotFound
|
||||||
),
|
),
|
||||||
@ -5109,7 +5117,7 @@ pub mod tests {
|
|||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
let RpcTransactionStatus {
|
let RpcTransactionStatusMeta {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@ -5127,7 +5135,7 @@ pub mod tests {
|
|||||||
assert!(transaction_status_cf
|
assert!(transaction_status_cf
|
||||||
.put(
|
.put(
|
||||||
(9, Signature::default()),
|
(9, Signature::default()),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
status: solana_sdk::transaction::Result::<()>::Ok(()),
|
||||||
fee: 9u64,
|
fee: 9u64,
|
||||||
pre_balances: pre_balances_vec.clone(),
|
pre_balances: pre_balances_vec.clone(),
|
||||||
@ -5137,7 +5145,7 @@ pub mod tests {
|
|||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
// result found
|
// result found
|
||||||
let RpcTransactionStatus {
|
let RpcTransactionStatusMeta {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@ -5192,7 +5200,7 @@ pub mod tests {
|
|||||||
transaction_status_cf
|
transaction_status_cf
|
||||||
.put(
|
.put(
|
||||||
(slot, transaction.signatures[0]),
|
(slot, transaction.signatures[0]),
|
||||||
&RpcTransactionStatus {
|
&RpcTransactionStatusMeta {
|
||||||
status: solana_sdk::transaction::Result::<()>::Err(
|
status: solana_sdk::transaction::Result::<()>::Err(
|
||||||
TransactionError::AccountNotFound,
|
TransactionError::AccountNotFound,
|
||||||
),
|
),
|
||||||
|
@ -10,7 +10,7 @@ use rocksdb::{
|
|||||||
};
|
};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_client::rpc_response::{RpcRewards, RpcTransactionStatus};
|
use solana_client::rpc_response::{RpcRewards, RpcTransactionStatusMeta};
|
||||||
use solana_sdk::{clock::Slot, signature::Signature};
|
use solana_sdk::{clock::Slot, signature::Signature};
|
||||||
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -269,7 +269,7 @@ pub trait TypedColumn: Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypedColumn for columns::TransactionStatus {
|
impl TypedColumn for columns::TransactionStatus {
|
||||||
type Type = RpcTransactionStatus;
|
type Type = RpcTransactionStatusMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SlotColumn<Index = u64> {}
|
pub trait SlotColumn<Index = u64> {}
|
||||||
|
@ -37,9 +37,12 @@ while [[ -n $1 ]]; do
|
|||||||
args+=("$1" "$2")
|
args+=("$1" "$2")
|
||||||
shift 2
|
shift 2
|
||||||
elif [[ $1 = --limit-ledger-size ]]; then
|
elif [[ $1 = --limit-ledger-size ]]; then
|
||||||
|
args+=("$1" "$2")
|
||||||
|
shift 2
|
||||||
|
elif [[ $1 = --no-rocksdb-compaction ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
elif [[ $1 = --enable-rpc-get-confirmed-block ]]; then
|
elif [[ $1 = --enable-rpc-transaction-history ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
elif [[ $1 = --skip-poh-verify ]]; then
|
elif [[ $1 = --skip-poh-verify ]]; then
|
||||||
|
@ -131,9 +131,12 @@ while [[ -n $1 ]]; do
|
|||||||
args+=("$1" "$2")
|
args+=("$1" "$2")
|
||||||
shift 2
|
shift 2
|
||||||
elif [[ $1 = --limit-ledger-size ]]; then
|
elif [[ $1 = --limit-ledger-size ]]; then
|
||||||
|
args+=("$1" "$2")
|
||||||
|
shift 2
|
||||||
|
elif [[ $1 = --no-rocksdb-compaction ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
elif [[ $1 = --enable-rpc-get-confirmed-block ]]; then
|
elif [[ $1 = --enable-rpc-transaction-history ]]; then
|
||||||
args+=("$1")
|
args+=("$1")
|
||||||
shift
|
shift
|
||||||
elif [[ $1 = --skip-poh-verify ]]; then
|
elif [[ $1 = --skip-poh-verify ]]; then
|
||||||
|
@ -290,7 +290,7 @@ EOF
|
|||||||
--blockstream /tmp/solana-blockstream.sock
|
--blockstream /tmp/solana-blockstream.sock
|
||||||
--no-voting
|
--no-voting
|
||||||
--dev-no-sigverify
|
--dev-no-sigverify
|
||||||
--enable-rpc-get-confirmed-block
|
--enable-rpc-transaction-history
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
if [[ -n $internalNodesLamports ]]; then
|
if [[ -n $internalNodesLamports ]]; then
|
||||||
|
2
run.sh
2
run.sh
@ -105,7 +105,7 @@ args=(
|
|||||||
--rpc-faucet-address 127.0.0.1:9900
|
--rpc-faucet-address 127.0.0.1:9900
|
||||||
--log -
|
--log -
|
||||||
--enable-rpc-exit
|
--enable-rpc-exit
|
||||||
--enable-rpc-get-confirmed-block
|
--enable-rpc-transaction-history
|
||||||
--init-complete-file "$dataDir"/init-completed
|
--init-complete-file "$dataDir"/init-completed
|
||||||
)
|
)
|
||||||
if [[ -n $blockstreamSocket ]]; then
|
if [[ -n $blockstreamSocket ]]; then
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
deserialize_atomicbool, deserialize_atomicu64, serialize_atomicbool, serialize_atomicu64,
|
deserialize_atomicbool, deserialize_atomicu64, serialize_atomicbool, serialize_atomicu64,
|
||||||
},
|
},
|
||||||
stakes::Stakes,
|
stakes::Stakes,
|
||||||
status_cache::{SlotDelta, StatusCache},
|
status_cache::{SignatureConfirmationStatus, SlotDelta, StatusCache},
|
||||||
storage_utils,
|
storage_utils,
|
||||||
storage_utils::StorageAccounts,
|
storage_utils::StorageAccounts,
|
||||||
system_instruction_processor::{get_system_account_kind, SystemAccountKind},
|
system_instruction_processor::{get_system_account_kind, SystemAccountKind},
|
||||||
@ -1820,14 +1820,14 @@ impl Bank {
|
|||||||
pub fn get_signature_confirmation_status(
|
pub fn get_signature_confirmation_status(
|
||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
) -> Option<(usize, Result<()>)> {
|
) -> Option<SignatureConfirmationStatus<Result<()>>> {
|
||||||
let rcache = self.src.status_cache.read().unwrap();
|
let rcache = self.src.status_cache.read().unwrap();
|
||||||
rcache.get_signature_status_slow(signature, &self.ancestors)
|
rcache.get_signature_status_slow(signature, &self.ancestors)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_signature_status(&self, signature: &Signature) -> Option<Result<()>> {
|
pub fn get_signature_status(&self, signature: &Signature) -> Option<Result<()>> {
|
||||||
self.get_signature_confirmation_status(signature)
|
self.get_signature_confirmation_status(signature)
|
||||||
.map(|v| v.1)
|
.map(|v| v.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_signature(&self, signature: &Signature) -> bool {
|
pub fn has_signature(&self, signature: &Signature) -> bool {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::bank::Bank;
|
use crate::{bank::Bank, status_cache::SignatureConfirmationStatus};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
client::{AsyncClient, Client, SyncClient},
|
client::{AsyncClient, Client, SyncClient},
|
||||||
@ -188,8 +188,13 @@ impl SyncClient for BankClient {
|
|||||||
let mut confirmed_blocks = 0;
|
let mut confirmed_blocks = 0;
|
||||||
loop {
|
loop {
|
||||||
let response = self.bank.get_signature_confirmation_status(signature);
|
let response = self.bank.get_signature_confirmation_status(signature);
|
||||||
if let Some((confirmations, res)) = response {
|
if let Some(SignatureConfirmationStatus {
|
||||||
if res.is_ok() {
|
confirmations,
|
||||||
|
status,
|
||||||
|
..
|
||||||
|
}) = response
|
||||||
|
{
|
||||||
|
if status.is_ok() {
|
||||||
if confirmed_blocks != confirmations {
|
if confirmed_blocks != confirmations {
|
||||||
now = Instant::now();
|
now = Instant::now();
|
||||||
confirmed_blocks = confirmations;
|
confirmed_blocks = confirmations;
|
||||||
|
@ -32,6 +32,13 @@ type SlotDeltaMap<T> = HashMap<Slot, SignatureStatus<T>>;
|
|||||||
// construct a new one. Usually derived from a status cache's `SlotDeltaMap`
|
// construct a new one. Usually derived from a status cache's `SlotDeltaMap`
|
||||||
pub type SlotDelta<T> = (Slot, bool, SignatureStatus<T>);
|
pub type SlotDelta<T> = (Slot, bool, SignatureStatus<T>);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct SignatureConfirmationStatus<T> {
|
||||||
|
pub slot: Slot,
|
||||||
|
pub confirmations: usize,
|
||||||
|
pub status: T,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StatusCache<T: Serialize + Clone> {
|
pub struct StatusCache<T: Serialize + Clone> {
|
||||||
cache: StatusMap<T>,
|
cache: StatusMap<T>,
|
||||||
@ -100,7 +107,7 @@ impl<T: Serialize + Clone> StatusCache<T> {
|
|||||||
&self,
|
&self,
|
||||||
sig: &Signature,
|
sig: &Signature,
|
||||||
ancestors: &HashMap<Slot, usize>,
|
ancestors: &HashMap<Slot, usize>,
|
||||||
) -> Option<(usize, T)> {
|
) -> Option<SignatureConfirmationStatus<T>> {
|
||||||
trace!("get_signature_status_slow");
|
trace!("get_signature_status_slow");
|
||||||
let mut keys = vec![];
|
let mut keys = vec![];
|
||||||
let mut val: Vec<_> = self.cache.iter().map(|(k, _)| *k).collect();
|
let mut val: Vec<_> = self.cache.iter().map(|(k, _)| *k).collect();
|
||||||
@ -110,10 +117,15 @@ impl<T: Serialize + Clone> StatusCache<T> {
|
|||||||
trace!("get_signature_status_slow: trying {}", blockhash);
|
trace!("get_signature_status_slow: trying {}", blockhash);
|
||||||
if let Some((forkid, res)) = self.get_signature_status(sig, blockhash, ancestors) {
|
if let Some((forkid, res)) = self.get_signature_status(sig, blockhash, ancestors) {
|
||||||
trace!("get_signature_status_slow: got {}", forkid);
|
trace!("get_signature_status_slow: got {}", forkid);
|
||||||
return ancestors
|
let confirmations = ancestors
|
||||||
.get(&forkid)
|
.get(&forkid)
|
||||||
.map(|id| (*id, res.clone()))
|
.copied()
|
||||||
.or_else(|| Some((ancestors.len(), res)));
|
.unwrap_or_else(|| ancestors.len());
|
||||||
|
return Some(SignatureConfirmationStatus {
|
||||||
|
slot: forkid,
|
||||||
|
confirmations,
|
||||||
|
status: res,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -272,7 +284,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
status_cache.get_signature_status_slow(&sig, &ancestors),
|
status_cache.get_signature_status_slow(&sig, &ancestors),
|
||||||
Some((1, ()))
|
Some(SignatureConfirmationStatus {
|
||||||
|
slot: 0,
|
||||||
|
confirmations: 1,
|
||||||
|
status: ()
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +333,11 @@ mod tests {
|
|||||||
status_cache.add_root(0);
|
status_cache.add_root(0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
status_cache.get_signature_status_slow(&sig, &ancestors),
|
status_cache.get_signature_status_slow(&sig, &ancestors),
|
||||||
Some((ancestors.len(), ()))
|
Some(SignatureConfirmationStatus {
|
||||||
|
slot: 0,
|
||||||
|
confirmations: ancestors.len(),
|
||||||
|
status: ()
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,10 +696,10 @@ pub fn main() {
|
|||||||
.help("Enable the JSON RPC 'setLogFilter' API. Only enable in a debug environment"),
|
.help("Enable the JSON RPC 'setLogFilter' API. Only enable in a debug environment"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("enable_rpc_get_confirmed_block")
|
Arg::with_name("enable_rpc_transaction_history")
|
||||||
.long("enable-rpc-get-confirmed-block")
|
.long("enable-rpc-transaction-history")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Enable the JSON RPC 'getConfirmedBlock' API. This will cause an increase in disk usage and IOPS"),
|
.help("Enable historical transaction info over JSON RPC, including the 'getConfirmedBlock' API. This will cause an increase in disk usage and IOPS"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("rpc_faucet_addr")
|
Arg::with_name("rpc_faucet_addr")
|
||||||
@ -835,6 +835,12 @@ pub fn main() {
|
|||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Use the RPC service of trusted validators only")
|
.help("Use the RPC service of trusted validators only")
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("no_rocksdb_compaction")
|
||||||
|
.long("no-rocksdb-compaction")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Disable manual compaction of the ledger database. May increase storage requirements.")
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("bind_address")
|
clap::Arg::with_name("bind_address")
|
||||||
.long("bind-address")
|
.long("bind-address")
|
||||||
@ -892,6 +898,7 @@ pub fn main() {
|
|||||||
let no_snapshot_fetch = matches.is_present("no_snapshot_fetch");
|
let no_snapshot_fetch = matches.is_present("no_snapshot_fetch");
|
||||||
let no_check_vote_account = matches.is_present("no_check_vote_account");
|
let no_check_vote_account = matches.is_present("no_check_vote_account");
|
||||||
let private_rpc = matches.is_present("private_rpc");
|
let private_rpc = matches.is_present("private_rpc");
|
||||||
|
let no_rocksdb_compaction = matches.is_present("no_rocksdb_compaction");
|
||||||
|
|
||||||
// Canonicalize ledger path to avoid issues with symlink creation
|
// Canonicalize ledger path to avoid issues with symlink creation
|
||||||
let _ = fs::create_dir_all(&ledger_path);
|
let _ = fs::create_dir_all(&ledger_path);
|
||||||
@ -932,7 +939,7 @@ pub fn main() {
|
|||||||
rpc_config: JsonRpcConfig {
|
rpc_config: JsonRpcConfig {
|
||||||
enable_validator_exit: matches.is_present("enable_rpc_exit"),
|
enable_validator_exit: matches.is_present("enable_rpc_exit"),
|
||||||
enable_set_log_filter: matches.is_present("enable_rpc_set_log_filter"),
|
enable_set_log_filter: matches.is_present("enable_rpc_set_log_filter"),
|
||||||
enable_get_confirmed_block: matches.is_present("enable_rpc_get_confirmed_block"),
|
enable_rpc_transaction_history: matches.is_present("enable_rpc_transaction_history"),
|
||||||
identity_pubkey: identity_keypair.pubkey(),
|
identity_pubkey: identity_keypair.pubkey(),
|
||||||
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
|
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
|
||||||
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
||||||
@ -945,6 +952,7 @@ pub fn main() {
|
|||||||
wait_for_supermajority: value_t!(matches, "wait_for_supermajority", Slot).ok(),
|
wait_for_supermajority: value_t!(matches, "wait_for_supermajority", Slot).ok(),
|
||||||
trusted_validators,
|
trusted_validators,
|
||||||
frozen_accounts: values_t!(matches, "frozen_accounts", Pubkey).unwrap_or_default(),
|
frozen_accounts: values_t!(matches, "frozen_accounts", Pubkey).unwrap_or_default(),
|
||||||
|
no_rocksdb_compaction,
|
||||||
..ValidatorConfig::default()
|
..ValidatorConfig::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user