From 3ab428693ad605e176485ba176addb1ce26bdd33 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 23 Mar 2020 13:55:03 -0700 Subject: [PATCH] Manual v1.0 backports (#9025) automerge --- client/src/mock_rpc_client_request.rs | 19 ++-- client/src/rpc_client.rs | 8 +- client/src/rpc_request.rs | 2 +- client/src/rpc_response.rs | 11 +- core/src/rpc.rs | 145 ++++++++++++++----------- core/src/storage_stage.rs | 13 ++- core/src/transaction_status_service.rs | 4 +- core/src/validator.rs | 9 +- docs/src/apps/jsonrpc-api.md | 20 ++-- docs/src/cli/delegate-stake.md | 16 +-- docs/src/cli/transfer-tokens.md | 4 +- genesis/src/main.rs | 2 +- ledger/src/blockstore.rs | 42 ++++--- ledger/src/blockstore_db.rs | 4 +- multinode-demo/bootstrap-validator.sh | 5 +- multinode-demo/validator.sh | 5 +- net/remote/remote-node.sh | 2 +- run.sh | 2 +- runtime/src/bank.rs | 6 +- runtime/src/bank_client.rs | 11 +- runtime/src/status_cache.rs | 32 +++++- validator/src/main.rs | 16 ++- 22 files changed, 232 insertions(+), 146 deletions(-) diff --git a/client/src/mock_rpc_client_request.rs b/client/src/mock_rpc_client_request.rs index db464b6175..f442ae6319 100644 --- a/client/src/mock_rpc_client_request.rs +++ b/client/src/mock_rpc_client_request.rs @@ -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> = 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)), diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 9f633fa5bc..d8505c937c 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -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>> { let signature_status = self.client.send( &RpcRequest::GetSignatureStatus, - json!([signature.to_string(), commitment_config]), + json!([[signature.to_string()], commitment_config]), 5, )?; - let result: Option> = + let result: Vec> = 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 { diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index 6e9e100863..312b3014d5 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -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" */ diff --git a/client/src/rpc_response.rs b/client/src/rpc_response.rs index 212eb3a9f1..65de9459a5 100644 --- a/client/src/rpc_response.rs +++ b/client/src/rpc_response.rs @@ -52,7 +52,7 @@ pub struct RpcConfirmedBlock { #[serde(rename_all = "camelCase")] pub struct RpcTransactionWithStatusMeta { pub transaction: RpcEncodedTransaction, - pub meta: Option, + pub meta: Option, } #[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, pub post_balances: Vec, } +#[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 { diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 5a21aaa50d..5402607518 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -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(bank: &Bank, value: T) -> RpcResponse { 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, } @@ -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 { 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) -> Result { @@ -365,7 +367,7 @@ impl JsonRpcRequestProcessor { slot: Slot, encoding: Option, ) -> Result> { - 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, + commitment: Option, + ) -> Result>> { + let mut statuses: Vec> = 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>) -> Result { @@ -539,9 +562,9 @@ pub trait RpcSol { fn get_signature_status( &self, meta: Self::Metadata, - signature_str: String, + signature_strs: Vec, commitment: Option, - ) -> Result>>; + ) -> Result>>; #[rpc(meta, name = "getSlot")] fn get_slot(&self, meta: Self::Metadata, commitment: Option) -> Result; @@ -885,11 +908,17 @@ impl RpcSol for RpcSolImpl { fn get_signature_status( &self, meta: Self::Metadata, - signature_str: String, + signature_strs: Vec, commitment: Option, - ) -> Result>> { - self.get_signature_confirmation(meta, signature_str, commitment) - .map(|res| res.map(|x| x.status)) + ) -> Result>> { + let mut signatures: Vec = 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) -> Result { @@ -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> = 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> = + 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 = 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> = + 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> = 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> = + serde_json::from_value(json["result"].clone()) + .expect("actual response deserialization"); + assert_eq!(expected_res, result[0].as_ref().unwrap().status); } #[test] diff --git a/core/src/storage_stage.rs b/core/src/storage_stage.rs index 2a3ad88ac3..7f26738a90 100644 --- a/core/src/storage_stage.rs +++ b/core/src/storage_stage.rs @@ -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; diff --git a/core/src/transaction_status_service.rs b/core/src/transaction_status_service.rs index 2b6f4749e9..b541be2e12 100644 --- a/core/src/transaction_status_service.rs +++ b/core/src/transaction_status_service.rs @@ -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, diff --git a/core/src/validator.rs b/core/src/validator.rs index 0283e67cb5..8138dc738d 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -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, + 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, diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index 5a55cbbcbc..62b7d22320 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -693,24 +693,30 @@ Returns the status of a given signature. This method is similar to [confirmTrans #### Parameters: -* `` - Signature of Transaction to confirm, as base-58 encoded string -* `` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) +* `` - An array of transaction signatures to confirm, as base-58 encoded strings +* `` - (optional) Extended Rpc configuration, containing the following optional fields: + * `commitment: ` - [Commitment](jsonrpc-api.md#configuring-state-commitment) + * `searchTransactionHistory: ` - whether to search the ledger transaction status cache, which may be expensive #### Results: +An array of: + * `` - Unknown transaction -* `` - Transaction status: - * `"Ok": ` - Transaction was successful - * `"Err": ` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14) +* `` + * `slot: ` - The slot the transaction was processed + * `status: ` - Transaction status + * `"Ok": ` - Transaction was successful + * `"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 diff --git a/docs/src/cli/delegate-stake.md b/docs/src/cli/delegate-stake.md index c8de7c0333..e60f993f59 100644 --- a/docs/src/cli/delegate-stake.md +++ b/docs/src/cli/delegate-stake.md @@ -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= stake-account.json --stake-authority= --withdraw-authority= +solana create-stake-account --from stake-account.json --stake-authority --withdraw-authority ``` `` tokens are transferred from the account at `` 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-authority= --new-stake-authority= +solana stake-authorize --stake-authority --new-stake-authority ``` This will use the existing stake authority `` 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= --seed= --stake-authority= --withdraw-authority= +solana create-stake-account --from --seed --stake-authority --withdraw-authority ``` `` 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= STAKE +solana create-address-with-seed --from STAKE ``` `` is the public key of the `` 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= +solana delegate-stake --stake-authority ``` `` 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= +solana deactivate-stake --stake-authority ``` `` 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= +solana withdraw-stake --withdraw-authority ``` `` is the existing stake account, `` 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= +solana split-stake --stake-authority ``` `` is the existing stake account, `` is the diff --git a/docs/src/cli/transfer-tokens.md b/docs/src/cli/transfer-tokens.md index eb86893d06..b307899978 100644 --- a/docs/src/cli/transfer-tokens.md +++ b/docs/src/cli/transfer-tokens.md @@ -84,7 +84,7 @@ pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV ``` ```bash -solana transfer --from= 5 --url http://devnet.solana.com +solana transfer --from 5 --url http://devnet.solana.com ``` where you replace `` 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= +solana transfer --from ``` Confirm the updated balances with `solana balance`: diff --git a/genesis/src/main.rs b/genesis/src/main.rs index bef6099b0b..7dec922e79 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -181,7 +181,7 @@ fn main() -> Result<(), Box> { .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( diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 954bfe28dd..d731eeb0a3 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -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>, pub completed_slots_senders: Vec>>, pub lowest_cleanup_slot: Arc>, + 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)> = entries + let expected_transactions: Vec<(Transaction, Option)> = 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, ), diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index 9ad31f196c..9ac9266940 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -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 {} diff --git a/multinode-demo/bootstrap-validator.sh b/multinode-demo/bootstrap-validator.sh index d59846f021..d5a2480d85 100755 --- a/multinode-demo/bootstrap-validator.sh +++ b/multinode-demo/bootstrap-validator.sh @@ -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 diff --git a/multinode-demo/validator.sh b/multinode-demo/validator.sh index 407c7187c3..1c29b74c77 100755 --- a/multinode-demo/validator.sh +++ b/multinode-demo/validator.sh @@ -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 diff --git a/net/remote/remote-node.sh b/net/remote/remote-node.sh index 8b95bde877..897a0ec230 100755 --- a/net/remote/remote-node.sh +++ b/net/remote/remote-node.sh @@ -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 diff --git a/run.sh b/run.sh index da09d96401..aac83ef65d 100755 --- a/run.sh +++ b/run.sh @@ -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 diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 4d200ae3cf..8a14a72f4d 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -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>> { 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> { self.get_signature_confirmation_status(signature) - .map(|v| v.1) + .map(|v| v.status) } pub fn has_signature(&self, signature: &Signature) -> bool { diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index 1cf80ee36d..9346359c15 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -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; diff --git a/runtime/src/status_cache.rs b/runtime/src/status_cache.rs index 5e02da39d2..d7c0961209 100644 --- a/runtime/src/status_cache.rs +++ b/runtime/src/status_cache.rs @@ -32,6 +32,13 @@ type SlotDeltaMap = HashMap>; // construct a new one. Usually derived from a status cache's `SlotDeltaMap` pub type SlotDelta = (Slot, bool, SignatureStatus); +#[derive(Debug, PartialEq)] +pub struct SignatureConfirmationStatus { + pub slot: Slot, + pub confirmations: usize, + pub status: T, +} + #[derive(Clone, Debug)] pub struct StatusCache { cache: StatusMap, @@ -100,7 +107,7 @@ impl StatusCache { &self, sig: &Signature, ancestors: &HashMap, - ) -> Option<(usize, T)> { + ) -> Option> { 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 StatusCache { 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: () + }) ); } diff --git a/validator/src/main.rs b/validator/src/main.rs index 918b5af150..ccf26074b4 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -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() };