Manual v1.0 backports (#9025)

automerge
This commit is contained in:
Michael Vines
2020-03-23 13:55:03 -07:00
committed by GitHub
parent 7ffaf2ad29
commit 3ab428693a
22 changed files with 232 additions and 146 deletions

View File

@ -2,7 +2,7 @@ use crate::{
client_error::Result,
generic_rpc_client_request::GenericRpcClientRequest,
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext},
rpc_response::{Response, RpcResponseContext, RpcTransactionStatus},
};
use serde_json::{Number, Value};
use solana_sdk::{
@ -87,19 +87,22 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
})?,
RpcRequest::GetSignatureStatus => {
let response: Option<transaction::Result<()>> = if self.url == "account_in_use" {
Some(Err(TransactionError::AccountInUse))
let status: transaction::Result<()> = if self.url == "account_in_use" {
Err(TransactionError::AccountInUse)
} else if self.url == "instruction_error" {
Some(Err(TransactionError::InstructionError(
Err(TransactionError::InstructionError(
0,
InstructionError::UninitializedAccount,
)))
} else if self.url == "sig_not_found" {
))
} else {
Ok(())
};
let status = if self.url == "sig_not_found" {
None
} 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::GetSlot => Value::Number(Number::from(0)),

View File

@ -7,7 +7,7 @@ use crate::{
rpc_response::{
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
RpcEpochInfo, RpcFeeCalculator, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount,
RpcLeaderSchedule, RpcResult, RpcVersionInfo, RpcVoteAccountStatus,
RpcLeaderSchedule, RpcResult, RpcTransactionStatus, RpcVersionInfo, RpcVoteAccountStatus,
},
};
use bincode::serialize;
@ -120,12 +120,12 @@ impl RpcClient {
) -> ClientResult<Option<transaction::Result<()>>> {
let signature_status = self.client.send(
&RpcRequest::GetSignatureStatus,
json!([signature.to_string(), commitment_config]),
json!([[signature.to_string()], commitment_config]),
5,
)?;
let result: Option<transaction::Result<()>> =
let result: Vec<Option<RpcTransactionStatus>> =
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> {

View File

@ -95,7 +95,7 @@ impl RpcRequest {
#[derive(Debug, Error)]
pub enum RpcError {
#[error("rpc reques error: {0}")]
#[error("rpc request error: {0}")]
RpcRequestError(String),
#[error("parse error: expected {0}")]
ParseError(String), /* "expected" */

View File

@ -52,7 +52,7 @@ pub struct RpcConfirmedBlock {
#[serde(rename_all = "camelCase")]
pub struct RpcTransactionWithStatusMeta {
pub transaction: RpcEncodedTransaction,
pub meta: Option<RpcTransactionStatus>,
pub meta: Option<RpcTransactionStatusMeta>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
@ -136,13 +136,20 @@ pub struct RpcCompiledInstruction {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcTransactionStatus {
pub struct RpcTransactionStatusMeta {
pub status: Result<()>,
pub fee: u64,
pub pre_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)]
#[serde(rename_all = "camelCase")]
pub struct RpcBlockhashFeeCalculator {

View File

@ -7,18 +7,12 @@ use crate::{
use bincode::serialize;
use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc;
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_client::rpc_response::*;
use solana_faucet::faucet::request_airdrop_transaction;
use solana_ledger::{
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::{
clock::{Slot, UnixTimestamp},
commitment_config::{CommitmentConfig, CommitmentLevel},
@ -28,7 +22,7 @@ use solana_sdk::{
pubkey::Pubkey,
signature::Signature,
timing::slot_duration_from_slots_per_year,
transaction::{self, Transaction},
transaction::Transaction,
};
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
use std::{
@ -51,7 +45,7 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
pub struct JsonRpcConfig {
pub enable_validator_exit: bool,
pub enable_set_log_filter: bool,
pub enable_get_confirmed_block: bool,
pub enable_rpc_transaction_history: bool,
pub identity_pubkey: Pubkey,
pub faucet_addr: Option<SocketAddr>,
}
@ -202,7 +196,9 @@ impl JsonRpcRequestProcessor {
Ok(sig) => {
let status = bank.get_signature_confirmation_status(&sig);
match status {
Some((_, result)) => new_response(bank, result.is_ok()),
Some(SignatureConfirmationStatus { status, .. }) => {
new_response(bank, status.is_ok())
}
None => new_response(bank, false),
}
}
@ -226,10 +222,16 @@ impl JsonRpcRequestProcessor {
) -> Option<RpcSignatureConfirmation> {
self.bank(commitment)
.get_signature_confirmation_status(&signature)
.map(|(confirmations, status)| RpcSignatureConfirmation {
confirmations,
status,
})
.map(
|SignatureConfirmationStatus {
confirmations,
status,
..
}| RpcSignatureConfirmation {
confirmations,
status,
},
)
}
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
@ -365,7 +367,7 @@ impl JsonRpcRequestProcessor {
slot: Slot,
encoding: Option<RpcTransactionEncoding>,
) -> 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())
} else {
Ok(None)
@ -413,6 +415,27 @@ impl JsonRpcRequestProcessor {
.ok()
.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> {
@ -539,9 +562,9 @@ pub trait RpcSol {
fn get_signature_status(
&self,
meta: Self::Metadata,
signature_str: String,
signature_strs: Vec<String>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>>;
) -> Result<Vec<Option<RpcTransactionStatus>>>;
#[rpc(meta, name = "getSlot")]
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64>;
@ -885,11 +908,17 @@ impl RpcSol for RpcSolImpl {
fn get_signature_status(
&self,
meta: Self::Metadata,
signature_str: String,
signature_strs: Vec<String>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>> {
self.get_signature_confirmation(meta, signature_str, commitment)
.map(|res| res.map(|x| x.status))
) -> Result<Vec<Option<RpcTransactionStatus>>> {
let mut signatures: Vec<Signature> = vec![];
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> {
@ -1200,7 +1229,7 @@ pub mod tests {
rpc_port,
signature::{Keypair, Signer},
system_transaction,
transaction::TransactionError,
transaction::{self, TransactionError},
};
use solana_vote_program::{
vote_instruction,
@ -1329,7 +1358,7 @@ pub mod tests {
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
JsonRpcConfig {
enable_get_confirmed_block: true,
enable_rpc_transaction_history: true,
identity_pubkey: *pubkey,
..JsonRpcConfig::default()
},
@ -1773,66 +1802,50 @@ pub mod tests {
meta,
blockhash,
alice,
confirmed_block_signatures,
..
} = start_rpc_handler_with_tx(&bob_pubkey);
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signatures[0]
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
confirmed_block_signatures[0]
);
let res = io.handle_request_sync(&req, meta.clone());
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
let expected_res: transaction::Result<()> = Ok(());
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
let result: Vec<Option<RpcTransactionStatus>> =
serde_json::from_value(json["result"].clone())
.expect("actual response deserialization");
assert_eq!(expected_res, result[0].as_ref().unwrap().status);
// Test getSignatureStatus request on unprocessed tx
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta.clone());
let expected_res: Option<String> = None;
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
let result: Vec<Option<RpcTransactionStatus>> =
serde_json::from_value(json["result"].clone())
.expect("actual response deserialization");
assert!(result[0].is_none());
// Test getSignatureStatus request on a TransactionError
let tx = system_transaction::transfer(&alice, &bob_pubkey, std::u64::MAX, blockhash);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signatures[0]
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
confirmed_block_signatures[1]
);
let res = io.handle_request_sync(&req, meta);
let expected_res: Option<transaction::Result<()>> = Some(Err(
TransactionError::InstructionError(0, InstructionError::CustomError(1)),
let res = io.handle_request_sync(&req, meta.clone());
let expected_res: transaction::Result<()> = Err(TransactionError::InstructionError(
0,
InstructionError::CustomError(1),
));
let expected = json!({
"jsonrpc": "2.0",
"result": expected_res,
"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);
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
let result: Vec<Option<RpcTransactionStatus>> =
serde_json::from_value(json["result"].clone())
.expect("actual response deserialization");
assert_eq!(expected_res, result[0].as_ref().unwrap().status);
}
#[test]

View File

@ -11,7 +11,9 @@ use rand::{Rng, SeedableRng};
use rand_chacha::ChaChaRng;
use solana_chacha_cuda::chacha_cuda::chacha_cbc_encrypt_file_many_keys;
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::{
account::Account,
account_utils::StateMut,
@ -343,8 +345,13 @@ impl StorageStage {
.unwrap()
.working_bank()
.get_signature_confirmation_status(signature);
if let Some((confirmations, res)) = response {
if res.is_ok() {
if let Some(SignatureConfirmationStatus {
confirmations,
status,
..
}) = response
{
if status.is_ok() {
if confirmed_blocks != confirmations {
now = Instant::now();
confirmed_blocks = confirmations;

View File

@ -1,5 +1,5 @@
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_runtime::{
bank::{Bank, HashAgeKind},
@ -73,7 +73,7 @@ impl TransactionStatusService {
blockstore
.write_transaction_status(
(slot, transaction.signatures[0]),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status,
fee,
pre_balances,

View File

@ -79,6 +79,7 @@ pub struct ValidatorConfig {
pub halt_on_trusted_validators_accounts_hash_mismatch: bool,
pub accounts_hash_fault_injection_slots: u64, // 0 = no fault injection
pub frozen_accounts: Vec<Pubkey>,
pub no_rocksdb_compaction: bool,
}
impl Default for ValidatorConfig {
@ -105,6 +106,7 @@ impl Default for ValidatorConfig {
halt_on_trusted_validators_accounts_hash_mismatch: false,
accounts_hash_fault_injection_slots: 0,
frozen_accounts: vec![],
no_rocksdb_compaction: false,
}
}
}
@ -270,7 +272,7 @@ impl Validator {
});
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();
(
Some(transaction_status_sender),
@ -285,7 +287,7 @@ impl Validator {
};
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();
(
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.set_no_compaction(config.no_rocksdb_compaction);
let process_options = blockstore_processor::ProcessOptions {
poh_verify,

View File

@ -693,24 +693,30 @@ Returns the status of a given signature. This method is similar to [confirmTrans
#### Parameters:
* `<string>` - Signature of Transaction to confirm, as base-58 encoded string
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
* `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings
* `<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:
An array of:
* `<null>` - Unknown transaction
* `<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)
* `<object>`
* `slot: <u64>` - The slot the transaction was processed
* `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:
```bash
// 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
{"jsonrpc":"2.0","result":{"Ok": null},"id":1}
{"jsonrpc":"2.0","result":[{"slot": 72, "status": {"Ok": null}}, null],"id":1}
```
### getSlot

View File

@ -33,7 +33,7 @@ want to perform an action on the stake account you create next.
Now, create a stake account:
```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
@ -72,7 +72,7 @@ Stake and withdraw authorities can be set when creating an account via the
run:
```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
@ -87,7 +87,7 @@ addresses can be cumbersome. Fortunately, you can derive stake addresses using
the `--seed` option:
```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
@ -98,7 +98,7 @@ and seed string. To see what stake address the command will derive, use `solana
create-address-with-seed`:
```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
@ -122,7 +122,7 @@ is the vote account address. Choose a validator and use its vote account
address in `solana delegate-stake`:
```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
@ -155,7 +155,7 @@ Once delegated, you can undelegate stake with the `solana deactivate-stake`
command:
```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
@ -169,7 +169,7 @@ in the cool down period will fail.
Transfer tokens out of a stake account with the `solana withdraw-stake` command:
```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
@ -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:
```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

View File

@ -84,7 +84,7 @@ pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
```
```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,
@ -107,7 +107,7 @@ tokens to transfer. Once you have that collected, you can transfer tokens
with the `solana transfer` command:
```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`:

View File

@ -181,7 +181,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.validator(is_pubkey_or_keypair)
.help(
"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(

View File

@ -24,7 +24,7 @@ use rayon::{
use rocksdb::DBRawIterator;
use solana_client::rpc_response::{
RpcConfirmedBlock, RpcEncodedTransaction, RpcRewards, RpcTransactionEncoding,
RpcTransactionStatus, RpcTransactionWithStatusMeta,
RpcTransactionStatusMeta, RpcTransactionWithStatusMeta,
};
use solana_measure::measure::Measure;
use solana_metrics::{datapoint_debug, datapoint_error};
@ -93,6 +93,7 @@ pub struct Blockstore {
pub new_shreds_signals: Vec<SyncSender<bool>>,
pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>,
pub lowest_cleanup_slot: Arc<RwLock<u64>>,
no_compaction: bool,
}
pub struct IndexMetaWorkingSetEntry {
@ -228,6 +229,7 @@ impl Blockstore {
insert_shreds_lock: Arc::new(Mutex::new(())),
last_root,
lowest_cleanup_slot: Arc::new(RwLock::new(0)),
no_compaction: false,
};
Ok(blockstore)
}
@ -245,6 +247,10 @@ impl Blockstore {
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<()> {
// Database::destroy() fails if the path doesn't exist
fs::create_dir_all(ledger_path)?;
@ -276,12 +282,14 @@ impl Blockstore {
while from_slot < batch_end {
match self.run_purge(from_slot, batch_end) {
Ok(end) => {
if let Err(e) = self.compact_storage(from_slot, batch_end) {
// This error is not fatal and indicates an internal error
error!(
"Error: {:?}; Couldn't compact storage from {:?} to {:?}",
e, from_slot, batch_end
);
if !self.no_compaction {
if let Err(e) = self.compact_storage(from_slot, batch_end) {
// This error is not fatal and indicates an internal error
error!(
"Error: {:?}; Couldn't compact storage from {:?} to {:?}",
e, from_slot, batch_end
);
}
}
if end {
@ -1467,7 +1475,7 @@ impl Blockstore {
pub fn write_transaction_status(
&self,
index: (Slot, Signature),
status: &RpcTransactionStatus,
status: &RpcTransactionStatusMeta,
) -> Result<()> {
self.transaction_status_cf.put(index, status)
}
@ -4795,7 +4803,7 @@ pub mod tests {
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
.unwrap();
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatus>)> = entries
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatusMeta>)> = entries
.iter()
.cloned()
.filter(|entry| !entry.is_tick())
@ -4812,7 +4820,7 @@ pub mod tests {
.transaction_status_cf
.put(
(slot, signature),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
@ -4824,7 +4832,7 @@ pub mod tests {
.transaction_status_cf
.put(
(slot + 1, signature),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
@ -4834,7 +4842,7 @@ pub mod tests {
.unwrap();
(
transaction,
Some(RpcTransactionStatus {
Some(RpcTransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances,
@ -5097,7 +5105,7 @@ pub mod tests {
assert!(transaction_status_cf
.put(
(0, Signature::default()),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound
),
@ -5109,7 +5117,7 @@ pub mod tests {
.is_ok());
// result found
let RpcTransactionStatus {
let RpcTransactionStatusMeta {
status,
fee,
pre_balances,
@ -5127,7 +5135,7 @@ pub mod tests {
assert!(transaction_status_cf
.put(
(9, Signature::default()),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Ok(()),
fee: 9u64,
pre_balances: pre_balances_vec.clone(),
@ -5137,7 +5145,7 @@ pub mod tests {
.is_ok());
// result found
let RpcTransactionStatus {
let RpcTransactionStatusMeta {
status,
fee,
pre_balances,
@ -5192,7 +5200,7 @@ pub mod tests {
transaction_status_cf
.put(
(slot, transaction.signatures[0]),
&RpcTransactionStatus {
&RpcTransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound,
),

View File

@ -10,7 +10,7 @@ use rocksdb::{
};
use serde::de::DeserializeOwned;
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 std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
use thiserror::Error;
@ -269,7 +269,7 @@ pub trait TypedColumn: Column {
}
impl TypedColumn for columns::TransactionStatus {
type Type = RpcTransactionStatus;
type Type = RpcTransactionStatusMeta;
}
pub trait SlotColumn<Index = u64> {}

View File

@ -37,9 +37,12 @@ while [[ -n $1 ]]; do
args+=("$1" "$2")
shift 2
elif [[ $1 = --limit-ledger-size ]]; then
args+=("$1" "$2")
shift 2
elif [[ $1 = --no-rocksdb-compaction ]]; then
args+=("$1")
shift
elif [[ $1 = --enable-rpc-get-confirmed-block ]]; then
elif [[ $1 = --enable-rpc-transaction-history ]]; then
args+=("$1")
shift
elif [[ $1 = --skip-poh-verify ]]; then

View File

@ -131,9 +131,12 @@ while [[ -n $1 ]]; do
args+=("$1" "$2")
shift 2
elif [[ $1 = --limit-ledger-size ]]; then
args+=("$1" "$2")
shift 2
elif [[ $1 = --no-rocksdb-compaction ]]; then
args+=("$1")
shift
elif [[ $1 = --enable-rpc-get-confirmed-block ]]; then
elif [[ $1 = --enable-rpc-transaction-history ]]; then
args+=("$1")
shift
elif [[ $1 = --skip-poh-verify ]]; then

View File

@ -290,7 +290,7 @@ EOF
--blockstream /tmp/solana-blockstream.sock
--no-voting
--dev-no-sigverify
--enable-rpc-get-confirmed-block
--enable-rpc-transaction-history
)
else
if [[ -n $internalNodesLamports ]]; then

2
run.sh
View File

@ -105,7 +105,7 @@ args=(
--rpc-faucet-address 127.0.0.1:9900
--log -
--enable-rpc-exit
--enable-rpc-get-confirmed-block
--enable-rpc-transaction-history
--init-complete-file "$dataDir"/init-completed
)
if [[ -n $blockstreamSocket ]]; then

View File

@ -13,7 +13,7 @@ use crate::{
deserialize_atomicbool, deserialize_atomicu64, serialize_atomicbool, serialize_atomicu64,
},
stakes::Stakes,
status_cache::{SlotDelta, StatusCache},
status_cache::{SignatureConfirmationStatus, SlotDelta, StatusCache},
storage_utils,
storage_utils::StorageAccounts,
system_instruction_processor::{get_system_account_kind, SystemAccountKind},
@ -1820,14 +1820,14 @@ impl Bank {
pub fn get_signature_confirmation_status(
&self,
signature: &Signature,
) -> Option<(usize, Result<()>)> {
) -> Option<SignatureConfirmationStatus<Result<()>>> {
let rcache = self.src.status_cache.read().unwrap();
rcache.get_signature_status_slow(signature, &self.ancestors)
}
pub fn get_signature_status(&self, signature: &Signature) -> Option<Result<()>> {
self.get_signature_confirmation_status(signature)
.map(|v| v.1)
.map(|v| v.status)
}
pub fn has_signature(&self, signature: &Signature) -> bool {

View File

@ -1,4 +1,4 @@
use crate::bank::Bank;
use crate::{bank::Bank, status_cache::SignatureConfirmationStatus};
use solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
@ -188,8 +188,13 @@ impl SyncClient for BankClient {
let mut confirmed_blocks = 0;
loop {
let response = self.bank.get_signature_confirmation_status(signature);
if let Some((confirmations, res)) = response {
if res.is_ok() {
if let Some(SignatureConfirmationStatus {
confirmations,
status,
..
}) = response
{
if status.is_ok() {
if confirmed_blocks != confirmations {
now = Instant::now();
confirmed_blocks = confirmations;

View File

@ -32,6 +32,13 @@ type SlotDeltaMap<T> = HashMap<Slot, SignatureStatus<T>>;
// construct a new one. Usually derived from a status cache's `SlotDeltaMap`
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)]
pub struct StatusCache<T: Serialize + Clone> {
cache: StatusMap<T>,
@ -100,7 +107,7 @@ impl<T: Serialize + Clone> StatusCache<T> {
&self,
sig: &Signature,
ancestors: &HashMap<Slot, usize>,
) -> Option<(usize, T)> {
) -> Option<SignatureConfirmationStatus<T>> {
trace!("get_signature_status_slow");
let mut keys = vec![];
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);
if let Some((forkid, res)) = self.get_signature_status(sig, blockhash, ancestors) {
trace!("get_signature_status_slow: got {}", forkid);
return ancestors
let confirmations = ancestors
.get(&forkid)
.map(|id| (*id, res.clone()))
.or_else(|| Some((ancestors.len(), res)));
.copied()
.unwrap_or_else(|| ancestors.len());
return Some(SignatureConfirmationStatus {
slot: forkid,
confirmations,
status: res,
});
}
}
None
@ -272,7 +284,11 @@ mod tests {
);
assert_eq!(
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);
assert_eq!(
status_cache.get_signature_status_slow(&sig, &ancestors),
Some((ancestors.len(), ()))
Some(SignatureConfirmationStatus {
slot: 0,
confirmations: ancestors.len(),
status: ()
})
);
}

View File

@ -696,10 +696,10 @@ pub fn main() {
.help("Enable the JSON RPC 'setLogFilter' API. Only enable in a debug environment"),
)
.arg(
Arg::with_name("enable_rpc_get_confirmed_block")
.long("enable-rpc-get-confirmed-block")
Arg::with_name("enable_rpc_transaction_history")
.long("enable-rpc-transaction-history")
.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::with_name("rpc_faucet_addr")
@ -835,6 +835,12 @@ pub fn main() {
.takes_value(false)
.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(
clap::Arg::with_name("bind_address")
.long("bind-address")
@ -892,6 +898,7 @@ pub fn main() {
let no_snapshot_fetch = matches.is_present("no_snapshot_fetch");
let no_check_vote_account = matches.is_present("no_check_vote_account");
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
let _ = fs::create_dir_all(&ledger_path);
@ -932,7 +939,7 @@ pub fn main() {
rpc_config: JsonRpcConfig {
enable_validator_exit: matches.is_present("enable_rpc_exit"),
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(),
faucet_addr: matches.value_of("rpc_faucet_addr").map(|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(),
trusted_validators,
frozen_accounts: values_t!(matches, "frozen_accounts", Pubkey).unwrap_or_default(),
no_rocksdb_compaction,
..ValidatorConfig::default()
};